diff --git a/CMakeLists.txt b/CMakeLists.txt index f240c37..18aba7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,98 +1,102 @@ # Copyright (C) 2008 by Volker Lanz +# Copyright (C) 2014-2018 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 . project(partitionmanager) -cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) + +# Dependencies +set(QT_MIN_VERSION "5.10.0") +set(KF5_MIN_VERSION "5.31") +set(KPMCORE_MIN_VERSION "3.50.0") set(CMAKE_USE_RELATIVE_PATHS OFF) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) set(KDE_INSTALL_USE_QT_SYS_PATHS ON CACHE BOOL "Install mkspecs files, Plugins and Imports to the Qt 5 install dir" FORCE) -set(QT_MIN_VERSION "5.7.0") -set(KF5_MIN_VERSION "5.31") -set(KPMCORE_MIN_VERSION "3.3.0") # Check KPMcore dependency when bumping set(VERSION_MAJOR "3") -set(VERSION_MINOR "3") -set(VERSION_RELEASE "1") +set(VERSION_MINOR "50") +set(VERSION_RELEASE "0") set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}) add_definitions(-D'VERSION="${VERSION}"') #" set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH}) include(ECMInstallIcons) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(FeatureSummary) include(GenerateExportHeader) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets ) # Load the frameworks we need find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Config ConfigWidgets CoreAddons Crash + DBusAddons I18n IconThemes JobWidgets KIO XmlGui WidgetsAddons OPTIONAL_COMPONENTS DocTools ) # use sane compile flags add_definitions( -DQT_USE_QSTRINGBUILDER -DQT_NO_CAST_TO_ASCII -DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_URL_CAST_FROM_STRING -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_CAST_TO_BYTEARRAY -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_USE_FAST_OPERATOR_PLUS -DQT_DISABLE_DEPRECATED_BEFORE=0x050900 ) find_package(KPMcore ${KPMCORE_MIN_VERSION} REQUIRED) include_directories(${Qt5Core_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${BLKID_INCLUDE_DIRS} ${KPMCORE_INCLUDE_DIR} lib/ src/) add_subdirectory(src) add_subdirectory(icons) if (KF5DocTools_FOUND) add_subdirectory(doc) endif() ki18n_install(po) message(STATUS "KDE Partition Manager ${VERSION} will be built for install into ${CMAKE_INSTALL_PREFIX}") feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 476d269..01a14f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,62 +1,63 @@ # Copyright (C) 2008, 2012 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 . ############################################ include(config/CMakeLists.txt) include(gui/CMakeLists.txt) include(util/CMakeLists.txt) set(partitionmanager_SRCS main.cpp ${CONFIG_SRC} ${GUI_SRC} ${UTIL_SRC} ) file(GLOB partitionmanager_UIFILES config/*.ui gui/*.ui) ki18n_wrap_ui(partitionmanager_SRCS ${partitionmanager_UIFILES}) kconfig_add_kcfg_files(partitionmanager_SRCS config.kcfgc) install(FILES partitionmanager.kcfg DESTINATION ${KCFG_INSTALL_DIR}) ############################################ add_executable(partitionmanager ${partitionmanager_SRCS} ) target_link_libraries(partitionmanager ${BLKID_LIBRARIES} kpmcore KF5::ConfigCore KF5::ConfigGui KF5::ConfigWidgets KF5::CoreAddons KF5::Crash + KF5::DBusAddons KF5::I18n KF5::IconThemes KF5::JobWidgets KF5::KIOWidgets KF5::WidgetsAddons KF5::XmlGui ) target_compile_definitions(partitionmanager PRIVATE -DCMAKE_INSTALL_FULL_LIBEXECDIR_KF5=\"${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}\") install(TARGETS partitionmanager ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES org.kde.partitionmanager.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) install(FILES gui/partitionmanagerui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/partitionmanager) install(PROGRAMS org.kde.partitionmanager.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) ############################################ diff --git a/src/config/configureoptionsdialog.cpp b/src/config/configureoptionsdialog.cpp index f1a03e8..ddc4f6b 100644 --- a/src/config/configureoptionsdialog.cpp +++ b/src/config/configureoptionsdialog.cpp @@ -1,162 +1,162 @@ /************************************************************************* * 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 "config/configureoptionsdialog.h" #include "config/generalpagewidget.h" #include "config/filesystemcolorspagewidget.h" #include "config/advancedpagewidget.h" #include #include #include #include #include #include "util/guihelpers.h" #include "ui_configurepagefilesystemcolors.h" #include #include #include #include #include #include ConfigureOptionsDialog::ConfigureOptionsDialog(QWidget* parent, const OperationStack& ostack, const QString& name) : KConfigDialog(parent, name, Config::self()), m_GeneralPageWidget(new GeneralPageWidget(this)), m_FileSystemColorsPageWidget(new FileSystemColorsPageWidget(this)), m_AdvancedPageWidget(new AdvancedPageWidget(this)), m_OperationStack(ostack) { setFaceType(List); KPageWidgetItem* item = nullptr; item = addPage(&generalPageWidget(), xi18nc("@title:tab general application settings", "General"), QString(), i18n("General Settings")); item->setIcon(QIcon::fromTheme(QStringLiteral("partitionmanager")).pixmap(IconSize(KIconLoader::Desktop))); connect(&generalPageWidget().comboDefaultFileSystem(), qOverload(&QComboBox::activated), this, &ConfigureOptionsDialog::onComboDefaultFileSystemActivated); connect(generalPageWidget().radioButton, &QRadioButton::toggled, this, &ConfigureOptionsDialog::onShredSourceActivated); item = addPage(&fileSystemColorsPageWidget(), xi18nc("@title:tab", "File System Colors"), QString(), i18n("File System Color Settings")); item->setIcon(QIcon::fromTheme(QStringLiteral("format-fill-color")).pixmap(IconSize(KIconLoader::Desktop))); item = addPage(&advancedPageWidget(), xi18nc("@title:tab advanced application settings", "Advanced"), QString(), i18n("Advanced Settings")); item->setIcon(QIcon::fromTheme(QStringLiteral("configure")).pixmap(IconSize(KIconLoader::Desktop))); connect(&advancedPageWidget().comboBackend(), qOverload(&QComboBox::activated), this, &ConfigureOptionsDialog::onComboDefaultFileSystemActivated); KConfigGroup kcg(KSharedConfig::openConfig(), "configureOptionsDialogs"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a ConfigureOptionsDialog instance */ ConfigureOptionsDialog::~ConfigureOptionsDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "configureOptionsDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void ConfigureOptionsDialog::updateSettings() { KConfigDialog::updateSettings(); bool changed = false; - if (generalPageWidget().defaultFileSystem() != Config::defaultFileSystem()) { - Config::setDefaultFileSystem(generalPageWidget().defaultFileSystem()); + if (generalPageWidget().defaultFileSystem() != static_cast(Config::defaultFileSystem())) { + Config::setDefaultFileSystem(static_cast(generalPageWidget().defaultFileSystem())); changed = true; } if (generalPageWidget().radioButton->isChecked() != (Config::shredSource() == Config::EnumShredSource::random)) { qDebug() << "updateSettings: " << generalPageWidget().kcfg_shredSource->checkedId(); Config::setShredSource(generalPageWidget().kcfg_shredSource->checkedId()); changed = true; } if (advancedPageWidget().backend() != Config::backend()) { Config::setBackend(advancedPageWidget().backend()); changed = true; } if (changed) emit KConfigDialog::settingsChanged(i18n("General Settings")); } bool ConfigureOptionsDialog::hasChanged() { bool result = KConfigDialog::hasChanged(); KConfigSkeletonItem* kcItem = Config::self()->findItem(QStringLiteral("defaultFileSystem")); - result = result || !kcItem->isEqual(generalPageWidget().defaultFileSystem()); + result = result || !kcItem->isEqual(static_cast(generalPageWidget().defaultFileSystem())); result = result || (generalPageWidget().kcfg_shredSource->checkedId() != Config::shredSource()); if (advancedPageWidget().isVisible()) { kcItem = Config::self()->findItem(QStringLiteral("backend")); result = result || !kcItem->isEqual(advancedPageWidget().backend()); } return result; } bool ConfigureOptionsDialog::isDefault() { bool result = KConfigDialog::isDefault(); if (result) { const bool useDefaults = Config::self()->useDefaults(true); result = !hasChanged(); Config::self()->useDefaults(useDefaults); } return result; } void ConfigureOptionsDialog::updateWidgetsDefault() { bool useDefaults = Config::self()->useDefaults(true); generalPageWidget().setDefaultFileSystem(GuiHelpers::defaultFileSystem()); generalPageWidget().radioButton->setChecked(true); if (advancedPageWidget().isVisible()) advancedPageWidget().setBackend(CoreBackendManager::defaultBackendName()); Config::self()->useDefaults(useDefaults); } void ConfigureOptionsDialog::onComboBackendActivated(int) { Q_ASSERT(advancedPageWidget().isVisible()); if (operationStack().size() == 0 || KMessageBox::warningContinueCancel(this, xi18nc("@info", "Do you really want to change the backend?" "This will also rescan devices and thus clear the list of pending operations."), xi18nc("@title:window", "Really Change Backend?"), KGuiItem(xi18nc("@action:button", "Change the Backend"), QStringLiteral("arrow-right")), KGuiItem(xi18nc("@action:button", "Do Not Change the Backend"), QStringLiteral("dialog-cancel")), QStringLiteral("reallyChangeBackend")) == KMessageBox::Continue) { settingsChangedSlot(); } else advancedPageWidget().setBackend(CoreBackendManager::defaultBackendName()); } diff --git a/src/config/configurepageadvanced.ui b/src/config/configurepageadvanced.ui index dc10749..96b5e5a 100644 --- a/src/config/configurepageadvanced.ui +++ b/src/config/configurepageadvanced.ui @@ -1,138 +1,110 @@ ConfigurePageAdvanced 0 0 - 367 + 449 420 - - - - - 0 - 1 - - - - Permissions - - - - - - - 0 - 0 - - - - Allow applying operations without administrator privileges - - - - - - 0 1 Backend Active backend: m_ComboBackend 0 1 Units Preferred unit: m_ComboBackend Byte KiB MiB GiB TiB PiB EiB diff --git a/src/config/configurepagefilesystemcolors.ui b/src/config/configurepagefilesystemcolors.ui index 5b2f267..49e3251 100644 --- a/src/config/configurepagefilesystemcolors.ui +++ b/src/config/configurepagefilesystemcolors.ui @@ -1,794 +1,810 @@ ConfigurePageFileSystemColors 0 0 - 481 + 484 457 0 3 File Systems - + ext2: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 28 17 ext3: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 ext4: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + Btrfs: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 37 18 NTFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 28 17 - + - Linux Swap: + Linux RAID: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - - - + - FAT12: + Linux Swap: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 - + - FAT16: + FAT12: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 - + - FAT32: + FAT16: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - - + + + Qt::Horizontal 28 17 - - - - ZFS: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - + + - ReiserFS: + FAT32: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + - - + + Qt::Horizontal - 43 + 28 17 - - + + - Reiser4: + HPFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + - - + + Qt::Horizontal - 28 + 43 17 - - + + - HPFS: + ReiserFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + - + - JFS: + Reiser4: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 - + - HFS: + JFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 28 17 - + - HFS+: + HFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + - + - UFS: + HFS+: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 - + - XFS: + UFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 28 17 - + - OCFS2: + XFS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - - - - + + - - + + - exFAT: + OCFS2: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - NILFS2: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + false - - + + Qt::Horizontal 40 20 + + + + ZFS: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + Qt::Horizontal 40 20 - - + + - LVM2 PV: + exFAT: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - false + + + + + + + + + NILFS2: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + Qt::Horizontal 43 17 - + - F2FS: + LVM2 PV: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 - + - UDF: + F2FS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + - + - ISO 9660: + UDF: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 - + - LUKS: + ISO 9660: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 43 17 + + + LUKS: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + LUKS2: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + - + Qt::Horizontal extended: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 28 17 unformatted: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - + Qt::Horizontal 21 21 unknown: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false - - + + + + + KColorButton QPushButton
kcolorbutton.h
diff --git a/src/config/generalpagewidget.cpp b/src/config/generalpagewidget.cpp index c4450dd..c596313 100644 --- a/src/config/generalpagewidget.cpp +++ b/src/config/generalpagewidget.cpp @@ -1,65 +1,65 @@ /************************************************************************* * 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 "config/generalpagewidget.h" #include #include #include #include "util/guihelpers.h" #include GeneralPageWidget::GeneralPageWidget(QWidget* parent) : QWidget(parent) { setupUi(this); setupDialog(); } FileSystem::Type GeneralPageWidget::defaultFileSystem() const { return FileSystem::typeForName(comboDefaultFileSystem().currentText()); } void GeneralPageWidget::setDefaultFileSystem(FileSystem::Type t) { const int idx = comboDefaultFileSystem().findText(FileSystem::nameForType(t)); comboDefaultFileSystem().setCurrentIndex(idx != -1 ? idx : 0); } void GeneralPageWidget::setupDialog() { QStringList fsNames; for (const auto &fs : FileSystemFactory::map()) - if (fs->supportCreate() != FileSystem::cmdSupportNone && fs->type() != FileSystem::Extended && fs->type() != FileSystem::Luks) + if (fs->supportCreate() != FileSystem::cmdSupportNone && fs->type() != FileSystem::Type::Extended && fs->type() != FileSystem::Type::Luks) fsNames.append(fs->name()); std::sort(fsNames.begin(), fsNames.end(), caseInsensitiveLessThan); for (const auto &fsName : qAsConst(fsNames)) comboDefaultFileSystem().addItem(createFileSystemColor(FileSystem::typeForName(fsName), 8), fsName); setDefaultFileSystem(GuiHelpers::defaultFileSystem()); kcfg_shredSource->setId(radioButton, 0); kcfg_shredSource->setId(radioButton_2, 1); radioButton->setChecked(Config::shredSource() == Config::EnumShredSource::random); radioButton_2->setChecked(Config::shredSource() == Config::EnumShredSource::zeros); } diff --git a/src/gui/applyprogressdialog.cpp b/src/gui/applyprogressdialog.cpp index d9c1ae1..4d30dd4 100644 --- a/src/gui/applyprogressdialog.cpp +++ b/src/gui/applyprogressdialog.cpp @@ -1,462 +1,464 @@ /************************************************************************* * 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); + okButton->setEnabled(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; // suspend the runner, so it doesn't happily carry on while the user decides // if he really wants to cancel operationRunner().suspendMutex().lock(); 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()) { 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); + okButton->setEnabled(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)); + 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/createvolumegroupdialog.cpp b/src/gui/createvolumegroupdialog.cpp index 09dcd12..b4c0ed2 100644 --- a/src/gui/createvolumegroupdialog.cpp +++ b/src/gui/createvolumegroupdialog.cpp @@ -1,99 +1,152 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * 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/createvolumegroupdialog.h" #include "gui/volumegroupwidget.h" +#include #include +#include #include +#include + #include #include #include #include #include #include -CreateVolumeGroupDialog::CreateVolumeGroupDialog(QWidget* parent, QString& vgName, QVector& partList, qint32& peSize, QList devices) +CreateVolumeGroupDialog::CreateVolumeGroupDialog(QWidget* parent, QString& vgName, QVector& partList, qint32& peSize, QList devices, QList pendingOps) : VolumeGroupDialog(parent, vgName, partList) , m_PESize(peSize) , m_Devices(devices) + , m_PendingOps(pendingOps) { setWindowTitle(xi18nc("@title:window", "Create new Volume Group")); setupDialog(); setupConstraints(); setupConnections(); // disable volume type and PE size for now, until the features are implemented. dialogWidget().volumeType().setEnabled(false); KConfigGroup kcg(KSharedConfig::openConfig(), "createVolumeDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } void CreateVolumeGroupDialog::setupDialog() { - for (const auto &p : qAsConst(LVM::pvList)) + for (const auto &p : qAsConst(LVM::pvList::list())) { + bool toBeDeleted = false; + + // Ignore partitions that are going to be deleted + for (const auto &o : qAsConst(m_PendingOps)) { + if (dynamic_cast(o) && o->targets(*p.partition())) { + toBeDeleted = true; + break; + } + } + + if (toBeDeleted) + continue; + if (!p.isLuks() && p.vgName() == QString() && !LvmDevice::s_DirtyPVs.contains(p.partition())) dialogWidget().listPV().addPartition(*p.partition(), false); + } + + for (const Device *d : qAsConst(m_Devices)) { + if (d->partitionTable() != nullptr) { + for (const Partition *p : qAsConst(d->partitionTable()->children())) { + // Looking if there is another VG creation that contains this partition + if (LvmDevice::s_DirtyPVs.contains(p)) + continue; + + // Including new LVM PVs (that are currently in OperationStack and that aren't at other VG creation) + if (p->state() == Partition::State::New) { + if (p->fileSystem().type() == FileSystem::Type::Lvm2_PV) + dialogWidget().listPV().addPartition(*p, false); + else if (p->fileSystem().type() == FileSystem::Type::Luks || p->fileSystem().type() == FileSystem::Type::Luks2) { + FileSystem *fs = static_cast(&p->fileSystem())->innerFS(); + + if (fs->type() == FileSystem::Type::Lvm2_PV) + dialogWidget().listPV().addPartition(*p, false); + } + } + } + } + } + + for (const Partition *p : qAsConst(LvmDevice::s_OrphanPVs)) + if (!LvmDevice::s_DirtyPVs.contains(p)) + dialogWidget().listPV().addPartition(*p, false); } void CreateVolumeGroupDialog::setupConnections() { connect(&dialogWidget().vgName(), &QLineEdit::textChanged, this, &CreateVolumeGroupDialog::onVGNameChanged); connect(&dialogWidget().spinPESize(), qOverload(&QSpinBox::valueChanged), this, &CreateVolumeGroupDialog::onSpinPESizeChanged); } void CreateVolumeGroupDialog::accept() { QString& tname = targetName(); tname = dialogWidget().vgName().text(); targetPVList().append(dialogWidget().listPV().checkedItems()); qint32& pesize = peSize(); pesize = dialogWidget().spinPESize().value(); QDialog::accept(); } +void CreateVolumeGroupDialog::updateOkButtonStatus() +{ + VolumeGroupDialog::updateOkButtonStatus(); + + if (okButton->isEnabled()) + okButton->setEnabled(!dialogWidget().listPV().checkedItems().empty()); +} + void CreateVolumeGroupDialog::onVGNameChanged(const QString& vgName) { for (const auto &d : m_Devices) { if (dynamic_cast(d)) { if (d->name() == vgName) { m_IsValidName = false; break; } else m_IsValidName = true; } } updateOkButtonStatus(); } void CreateVolumeGroupDialog::onSpinPESizeChanged(int newsize) { Q_UNUSED(newsize); updateOkButtonStatus(); updateSectorInfos(); } diff --git a/src/gui/createvolumegroupdialog.h b/src/gui/createvolumegroupdialog.h index 70d4867..4dcf2dc 100644 --- a/src/gui/createvolumegroupdialog.h +++ b/src/gui/createvolumegroupdialog.h @@ -1,55 +1,57 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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(CREATEVOLUMEGROUPDIALOG_H) - +#ifndef CREATEVOLUMEGROUPDIALOG_H #define CREATEVOLUMEGROUPDIALOG_H #include #include #include "gui/volumegroupdialog.h" class Device; +class Operation; class CreateVolumeGroupDialog : public VolumeGroupDialog { Q_DISABLE_COPY(CreateVolumeGroupDialog) public: - CreateVolumeGroupDialog(QWidget* parent, QString& vgName, QVector& pvList, qint32& peSize, QList devices); + CreateVolumeGroupDialog(QWidget* parent, QString& vgName, QVector& pvList, qint32& peSize, QList devices, QList pendingOps = QList()); protected: void accept() override; void setupDialog() override; void setupConnections() override; protected: + virtual void updateOkButtonStatus() override; void onVGNameChanged(const QString& vgname); void onSpinPESizeChanged(int newsize); qint32& peSize() { return m_PESize; } qint32& m_PESize; private: const QList m_Devices; // List of all devices found on the system + const QList m_PendingOps; // List of pending operations in KPM }; #endif diff --git a/src/gui/devicepropsdialog.cpp b/src/gui/devicepropsdialog.cpp index 175e1d7..883d11b 100644 --- a/src/gui/devicepropsdialog.cpp +++ b/src/gui/devicepropsdialog.cpp @@ -1,177 +1,174 @@ /************************************************************************* * Copyright (C) 2008, 2009 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/devicepropsdialog.h" #include "gui/devicepropswidget.h" #include "gui/smartdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /** Creates a new DevicePropsDialog @param parent pointer to the parent widget @param d the Device to show properties for */ DevicePropsDialog::DevicePropsDialog(QWidget* parent, Device& d) : QDialog(parent), m_Device(d), m_DialogWidget(new DevicePropsWidget(this)) { mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&dialogWidget()); setWindowTitle(xi18nc("@title:window", "Device Properties: %1", device().deviceNode())); setupDialog(); setupConnections(); KConfigGroup kcg(KSharedConfig::openConfig(), "devicePropsDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a DevicePropsDialog */ DevicePropsDialog::~DevicePropsDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "devicePropsDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void DevicePropsDialog::setupDialog() { dialogButtonBox = new QDialogButtonBox; okButton = dialogButtonBox->addButton(QDialogButtonBox::Ok); cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); mainLayout->addWidget(dialogButtonBox); okButton->setEnabled(false); cancelButton->setFocus(); cancelButton->setDefault(true); connect(dialogButtonBox, &QDialogButtonBox::accepted, this, &DevicePropsDialog::accept); connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &DevicePropsDialog::reject); QString type = QStringLiteral("---"); QString maxPrimaries = QStringLiteral("---"); if (device().partitionTable() != nullptr) { type = (device().partitionTable()->isReadOnly()) ? xi18nc("@label device", "%1 (read only)", device().partitionTable()->typeName()) : device().partitionTable()->typeName(); maxPrimaries = QStringLiteral("%1/%2").arg(device().partitionTable()->numPrimaries()).arg(device().partitionTable()->maxPrimaries()); dialogWidget().partTableWidget().setReadOnly(true); dialogWidget().partTableWidget().setPartitionTable(device().partitionTable()); if (device().partitionTable()->type() == PartitionTable::msdos) dialogWidget().radioCylinderBased().setChecked(true); else if (device().partitionTable()->type() == PartitionTable::msdos_sectorbased) dialogWidget().radioSectorBased().setChecked(true); else dialogWidget().hideTypeRadioButtons(); } else { dialogWidget().partTableWidget().setVisible(false); dialogWidget().hideTypeRadioButtons(); } dialogWidget().type().setText(type); dialogWidget().capacity().setText(Capacity::formatByteSize(device().capacity())); dialogWidget().totalSectors().setText(QLocale().toString(device().totalLogical())); - if (device().type() == Device::Disk_Device) { + if (device().type() == Device::Type::Disk_Device) { const DiskDevice& disk = dynamic_cast(device()); - const QString cyls = QLocale().toString((disk.cylinders())); - const QString heads = QLocale().toString((disk.heads())); - const QString sectors = QLocale().toString((disk.sectorsPerTrack())); - dialogWidget().chs().setText(QStringLiteral("%1/%2/%3").arg(cyls).arg(heads).arg(sectors)); - dialogWidget().cylinderSize().setText(i18ncp("@label", "1 Sector", "%1 Sectors", disk.cylinderSize())); dialogWidget().primariesMax().setText(maxPrimaries); dialogWidget().logicalSectorSize().setText(Capacity::formatByteSize(disk.logicalSectorSize())); dialogWidget().physicalSectorSize().setText(Capacity::formatByteSize(disk.physicalSectorSize())); if (device().smartStatus().isValid()) { if (device().smartStatus().status()) { dialogWidget().smartStatusText().setText(xi18nc("@label SMART disk status", "good")); dialogWidget().smartStatusIcon().setPixmap(QIcon::fromTheme(QStringLiteral("dialog-ok")).pixmap(IconSize(KIconLoader::Small))); } else { dialogWidget().smartStatusText().setText(xi18nc("@label SMART disk status", "BAD")); dialogWidget().smartStatusIcon().setPixmap(QIcon::fromTheme(QStringLiteral("dialog-warning")).pixmap(IconSize(KIconLoader::Small))); } } else { dialogWidget().smartStatusText().setText(xi18nc("@label", "(unknown)")); dialogWidget().smartStatusIcon().setVisible(false); dialogWidget().buttonSmartMore().setVisible(false); } } else { - if (device().type() == Device::LVM_Device) + if (device().type() == Device::Type::LVM_Device) dialogWidget().type().setText(xi18nc("@label device", "LVM Volume Group")); + else if (device().type() == Device::Type::SoftwareRAID_Device) + dialogWidget().type().setText(xi18nc("@label device", "Software RAID Device")); else dialogWidget().type().setText(xi18nc("@label device", "Volume Manager Device")); //TODO: add Volume Manger Device info dialogWidget().smartStatusText().setVisible(false); dialogWidget().smartStatusIcon().setVisible(false); dialogWidget().buttonSmartMore().setVisible(false); } setMinimumSize(dialogWidget().size()); resize(dialogWidget().size()); } void DevicePropsDialog::setupConnections() { connect(&dialogWidget().radioSectorBased(), &QRadioButton::toggled, this, &DevicePropsDialog::setDirty); connect(&dialogWidget().radioCylinderBased(), &QRadioButton::toggled, this, &DevicePropsDialog::setDirty); connect(&dialogWidget().buttonSmartMore(), &QPushButton::clicked, this, &DevicePropsDialog::onButtonSmartMore); } void DevicePropsDialog::setDirty(bool) { okButton->setEnabled(true); okButton->setDefault(true); } bool DevicePropsDialog::cylinderBasedAlignment() const { return dialogWidget().radioCylinderBased().isChecked(); } bool DevicePropsDialog::sectorBasedAlignment() const { return dialogWidget().radioSectorBased().isChecked(); } void DevicePropsDialog::onButtonSmartMore(bool) { QPointer dlg = new SmartDialog(this, device()); dlg->exec(); delete dlg; } diff --git a/src/gui/devicepropswidget.h b/src/gui/devicepropswidget.h index 9b617ee..5dc8f44 100644 --- a/src/gui/devicepropswidget.h +++ b/src/gui/devicepropswidget.h @@ -1,112 +1,104 @@ /************************************************************************* * Copyright (C) 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(DEVICEPROPSWIDGET_H) #define DEVICEPROPSWIDGET_H #include "ui_devicepropswidgetbase.h" class PartTableWidget; /** Central widget in the DevicePropsDialog. @author Volker Lanz */ class DevicePropsWidget : public QWidget, public Ui::DevicePropsWidgetBase { public: DevicePropsWidget(QWidget* parent); public: PartTableWidget& partTableWidget() { Q_ASSERT(m_PartTableWidget); return *m_PartTableWidget; } - QLabel& chs() { - Q_ASSERT(m_LabelCHS); - return *m_LabelCHS; - } QLabel& capacity() { Q_ASSERT(m_LabelCapacity); return *m_LabelCapacity; } - QLabel& cylinderSize() { - Q_ASSERT(m_LabelCylinderSize); - return *m_LabelCylinderSize; - } QLabel& primariesMax() { Q_ASSERT(m_LabelPrimariesMax); return *m_LabelPrimariesMax; } QLabel& logicalSectorSize() { Q_ASSERT(m_LabelLogicalSectorSize); return *m_LabelLogicalSectorSize; } QLabel& physicalSectorSize() { Q_ASSERT(m_LabelPhysicalSectorSize); return *m_LabelPhysicalSectorSize; } QLabel& totalSectors() { Q_ASSERT(m_LabelTotalSectors); return *m_LabelTotalSectors; } QLabel& type() { Q_ASSERT(m_LabelType); return *m_LabelType; } QRadioButton& radioCylinderBased() { Q_ASSERT(m_RadioCylinderBased); return *m_RadioCylinderBased; } const QRadioButton& radioCylinderBased() const { Q_ASSERT(m_RadioCylinderBased); return *m_RadioCylinderBased; } QRadioButton& radioSectorBased() { Q_ASSERT(m_RadioSectorBased); return *m_RadioSectorBased; } const QRadioButton& radioSectorBased() const { Q_ASSERT(m_RadioSectorBased); return *m_RadioSectorBased; } QSpacerItem& spacerType() { Q_ASSERT(m_SpacerType); return *m_SpacerType; } QLabel& smartStatusText() { Q_ASSERT(m_LabelSmartStatusText); return *m_LabelSmartStatusText; } QLabel& smartStatusIcon() { Q_ASSERT(m_LabelSmartStatusIcon); return *m_LabelSmartStatusIcon; } QPushButton& buttonSmartMore() { Q_ASSERT(m_ButtonSmartMore); return *m_ButtonSmartMore; } void hideTypeRadioButtons(); }; #endif diff --git a/src/gui/devicepropswidgetbase.ui b/src/gui/devicepropswidgetbase.ui index 17b977c..7a6b322 100644 --- a/src/gui/devicepropswidgetbase.ui +++ b/src/gui/devicepropswidgetbase.ui @@ -1,337 +1,291 @@ DevicePropsWidgetBase 0 0 643 496 0 0 0 60 16777215 60 Qt::CustomContextMenu Qt::Vertical QSizePolicy::Fixed 439 17 Partition table: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter &Cylinder alignment - Sector based al&ignment + Sector based align&ment Qt::Horizontal 40 0 Qt::Horizontal Capacity: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Total sectors: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal - - - - 2 - 0 - - - - Cylinders/Heads/Sectors: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 5 - 0 - - - - - - - - Logical sector size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - + Physical sector size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - - - - Cylinder size: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - + + + + Qt::Horizontal - + Qt::Horizontal - + Primaries/Max: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - - - - Qt::Horizontal - - - - + SMART status: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + 16 16777215 2 0 More... - + Qt::Vertical QSizePolicy::Fixed 439 14 PartTableWidget QWidget
gui/parttablewidget.h
1
diff --git a/src/gui/editmountpointdialog.cpp b/src/gui/editmountpointdialog.cpp index 02b4f36..c6d07d2 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);} ); + this, [=] () {accept_(MountPointAction::Edit);} ); connect(dbb, &QDialogButtonBox::rejected, this, &EditMountPointDialog::reject); - connect(widget().m_ButtonRemove, &QPushButton::clicked, this, [=] () {accept_(Remove);} ); + connect(widget().m_ButtonRemove, &QPushButton::clicked, this, [=] () {accept_(MountPointAction::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) + if(action == MountPointAction::Remove) widget().removeMountPoint(); - else if (action == Edit) + else if (action == MountPointAction::Edit) widget().acceptChanges(); if (writeMountpoints(widget().fstabEntries())) { - if (action == Edit) + if (action == MountPointAction::Edit) 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/editmountpointdialog.h b/src/gui/editmountpointdialog.h index fcdc7cc..e1905ad 100644 --- a/src/gui/editmountpointdialog.h +++ b/src/gui/editmountpointdialog.h @@ -1,61 +1,61 @@ /************************************************************************* * Copyright (C) 2009, 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 .* *************************************************************************/ #if !defined(EDITMOUNTPOINTDIALOG_H) #define EDITMOUNTPOINTDIALOG_H #include class EditMountPointDialogWidget; class Partition; class QWidget; class QString; -enum MountPointAction +enum class MountPointAction { Remove, Edit }; class EditMountPointDialog : public QDialog { public: EditMountPointDialog(QWidget* parent, Partition& p); ~EditMountPointDialog(); protected: EditMountPointDialogWidget& widget() { return *m_DialogWidget; } void accept_(MountPointAction action); private: Partition& partition() { return m_Partition; } private: Partition& m_Partition; EditMountPointDialogWidget* m_DialogWidget; }; #endif diff --git a/src/gui/editmountpointdialogwidget.cpp b/src/gui/editmountpointdialogwidget.cpp index 8af681f..768aef4 100644 --- a/src/gui/editmountpointdialogwidget.cpp +++ b/src/gui/editmountpointdialogwidget.cpp @@ -1,234 +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) { + if (partition().roles().has(PartitionRole::Luks) && partition().fileSystem().type() != FileSystem::Type::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 + if (canonicalEntryPath == canonicalDevicePath) { entryFound = true; - entry.append(&e); + entry.push_back(&e); mountPointList = possibleMountPoints(e.deviceNode()); } } if (!entryFound) { FileSystem::Type type = partition().fileSystem().type(); QString fsName; switch (type) { - case FileSystem::LinuxSwap: + case FileSystem::Type::LinuxSwap: fsName = QStringLiteral("swap"); break; - case FileSystem::Fat16: - case FileSystem::Fat32: + case FileSystem::Type::Fat16: + case FileSystem::Type::Fat32: fsName = QStringLiteral("vfat"); break; default: fsName = partition().fileSystem().name(); } - m_fstabEntries.append(FstabEntry(m_deviceNode, QString(), fsName, QString())); - entry.append(&m_fstabEntries.last()); + m_fstabEntries.push_back(FstabEntry(m_deviceNode, QString(), fsName, QString())); + entry.push_back(&m_fstabEntries.back()); } 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; 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) +void EditMountPointDialogWidget::setupRadio(const FstabEntry::Type 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: + case FstabEntry::Type::uuid: radioUUID().setChecked(true); break; - case FstabEntryType::label: + case FstabEntry::Type::label: radioLabel().setChecked(true); break; - case FstabEntryType::partuuid: + case FstabEntry::Type::partuuid: radioUUID().setChecked(true); break; - case FstabEntryType::partlabel: + case FstabEntry::Type::partlabel: radioLabel().setChecked(true); break; - case FstabEntryType::deviceNode: + case FstabEntry::Type::deviceNode: radioDeviceNode().setChecked(true); break; - case FstabEntryType::comment: + case FstabEntry::Type::comment: break; } } void EditMountPointDialogWidget::buttonSelectClicked(bool) { const QString s = QFileDialog::getExistingDirectory(this, editPath().currentText()); if (!s.isEmpty()) editPath().setCurrentText(s); } void EditMountPointDialogWidget::removeMountPoint() { - int i=0; - for (const auto &e : fstabEntries()) { - 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); + for (auto it = fstabEntries().begin(); it != fstabEntries().end(); ) { + if (editPath().count() <= 1 && ( + (it->fsSpec().contains(partition().deviceNode()) && !partition().deviceNode().isEmpty() ) || + (it->fsSpec().contains(partition().fileSystem().uuid()) && !partition().fileSystem().uuid().isEmpty() ) || + (it->fsSpec().contains(partition().fileSystem().label()) && !partition().fileSystem().label().isEmpty()) || + (it->fsSpec().contains(partition().label()) && !partition().label().isEmpty() ) || + (it->fsSpec().contains(partition().uuid()) && !partition().uuid().isEmpty() ))) + { + fstabEntries().erase(it); partition().setMountPoint(QString()); - i--; - } - else if(editPath().count()>1 && ((&e == currentEntry))) - { - fstabEntries().removeAt(i); + } + else if (editPath().count() > 1 && ((&*it == currentEntry))) + { + fstabEntries().erase(it); 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() { currentEntry->setDumpFreq(spinDumpFreq().value()); currentEntry->setPassNumber(spinPassNumber().value()); currentEntry->setMountPoint(editPath().currentText()); currentEntry->setOptions(options()); if (radioUUID().isChecked() && !partition().fileSystem().uuid().isEmpty()) currentEntry->setFsSpec(QStringLiteral("UUID=") + partition().fileSystem().uuid()); else if (radioLabel().isChecked() && !partition().fileSystem().label().isEmpty()) currentEntry->setFsSpec(QStringLiteral("LABEL=") + partition().fileSystem().label()); else currentEntry->setFsSpec(m_deviceNode); } diff --git a/src/gui/editmountpointdialogwidget.h b/src/gui/editmountpointdialogwidget.h index 56705bc..e248b21 100644 --- a/src/gui/editmountpointdialogwidget.h +++ b/src/gui/editmountpointdialogwidget.h @@ -1,115 +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 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; } 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); + void setupRadio(const FstabEntry::Type 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; - QList entry; + QList entry; // All fstab entries for this partition 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/filesystemsupportdialog.cpp b/src/gui/filesystemsupportdialog.cpp index 1d61a1e..487b534 100644 --- a/src/gui/filesystemsupportdialog.cpp +++ b/src/gui/filesystemsupportdialog.cpp @@ -1,120 +1,120 @@ /************************************************************************* * Copyright (C) 2008, 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/filesystemsupportdialog.h" #include "gui/filesystemsupportdialogwidget.h" #include #include #include #include #include #include #include #include /** Creates a new FileSystemSupportDialog @param parent the parent object */ FileSystemSupportDialog::FileSystemSupportDialog(QWidget* parent) : QDialog(parent), m_FileSystemSupportDialogWidget(new FileSystemSupportDialogWidget(this)) { QVBoxLayout *mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&dialogWidget()); setWindowTitle(xi18nc("@title:window", "File System Support")); dialogButtonBox = new QDialogButtonBox(this); dialogButtonBox -> setStandardButtons(QDialogButtonBox::Ok); mainLayout->addWidget(dialogButtonBox); setupDialog(); setupConnections(); KConfigGroup kcg(KSharedConfig::openConfig(), "fileSystemSupportDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a FileSystemSupportDialog */ FileSystemSupportDialog::~FileSystemSupportDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "fileSystemSupportDialog"); kcg.writeEntry("Geometry", saveGeometry()); } QSize FileSystemSupportDialog::sizeHint() const { return QSize(690, 490); } void FileSystemSupportDialog::setupDialog() { QIcon yes = QIcon::fromTheme(QStringLiteral("dialog-ok")).pixmap(IconSize(KIconLoader::Toolbar)); QIcon no = QIcon::fromTheme(QStringLiteral("dialog-error")).pixmap(IconSize(KIconLoader::Toolbar)); dialogWidget().tree().clear(); for (const auto &fs : FileSystemFactory::map()) { - if (fs->type() == FileSystem::Unknown || fs->type() == FileSystem::Extended || - fs->type() == FileSystem::Luks || fs->type() == FileSystem::Luks2) { + if (fs->type() == FileSystem::Type::Unknown || fs->type() == FileSystem::Type::Extended || + fs->type() == FileSystem::Type::Luks || fs->type() == FileSystem::Type::Luks2) { continue; } QTreeWidgetItem* item = new QTreeWidgetItem(); int i = 0; item->setText(i++, fs->name()); item->setIcon(i++, fs->supportCreate() ? yes : no); item->setIcon(i++, fs->supportGrow() ? yes : no); item->setIcon(i++, fs->supportShrink() ? yes : no); item->setIcon(i++, fs->supportMove() ? yes : no); item->setIcon(i++, fs->supportCopy() ? yes : no); item->setIcon(i++, fs->supportCheck() ? yes : no); item->setIcon(i++, fs->supportGetLabel() ? yes : no); item->setIcon(i++, fs->supportSetLabel() ? yes : no); item->setIcon(i++, fs->supportGetUsed() ? yes : no); item->setIcon(i++, fs->supportBackup() ? yes : no); // there is no FileSystem::supportRestore(), because we currently can't tell // if a file is an image of a supported or unsupported (or even invalid) filesystem item->setIcon(i++, yes); item->setText(i++, fs->supportToolName().name.isEmpty() ? QStringLiteral("---") : fs->supportToolName().name); dialogWidget().tree().addTopLevelItem(item); } for (int i = 0; i < dialogWidget().tree().columnCount(); i++) dialogWidget().tree().resizeColumnToContents(i); dialogWidget().tree().sortItems(0, Qt::AscendingOrder); } void FileSystemSupportDialog::setupConnections() { connect(dialogButtonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &FileSystemSupportDialog::close); connect(&dialogWidget().buttonRescan(), &QPushButton::clicked, this, &FileSystemSupportDialog::onButtonRescanClicked); } void FileSystemSupportDialog::onButtonRescanClicked() { FileSystemFactory::init(); setupDialog(); } diff --git a/src/gui/infopane.cpp b/src/gui/infopane.cpp index f3336e6..71160c3 100644 --- a/src/gui/infopane.cpp +++ b/src/gui/infopane.cpp @@ -1,205 +1,214 @@ /************************************************************************* * 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/infopane.h" #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include /** Creates a new InfoPane instance @param parent the parent widget */ InfoPane::InfoPane(QWidget* parent) : QWidget(parent), m_GridLayout(new QGridLayout(this)) { layout()->setMargin(0); } /** Clears the InfoPane, leaving it empty */ void InfoPane::clear() { parentWidget()->parentWidget()->setWindowTitle(xi18nc("@title:window", "Information")); qDeleteAll(findChildren()); qDeleteAll(findChildren()); } int InfoPane::createHeader(const QString& title, const int num_cols) { int y = 0; QLabel* label = new QLabel(title, this); QFont font; font.setBold(true); font.setWeight(75); label->setFont(font); label->setAlignment(Qt::AlignCenter); gridLayout().addWidget(label, y++, 0, 1, num_cols); QFrame* line = new QFrame(this); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); gridLayout().addWidget(line, y++, 0, 1, num_cols); return y; } void InfoPane::createLabels(const QString& title, const QString& value, const int num_cols, int& x, int& y) { QLabel* labelTitle = new QLabel(title, this); labelTitle->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); labelTitle->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter); QPalette palette = labelTitle->palette(); QColor f = palette.color(QPalette::Foreground); f.setAlpha(128); palette.setColor(QPalette::Foreground, f); labelTitle->setPalette(palette); gridLayout().addWidget(labelTitle, y, x, 1, 1); QLabel* labelValue = new QLabel(value, this); labelValue->setTextInteractionFlags(Qt::TextBrowserInteraction); labelValue->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); gridLayout().addWidget(labelValue, y, x + 1, 1, 1); x += 2; if (x % num_cols == 0) { x = 0; y++; } } /** Shows information about a Partition in the InfoPane @param area the current area the widget's dock is in @param p the Partition to show information about */ void InfoPane::showPartition(Qt::DockWidgetArea area, const Partition& p) { clear(); parentWidget()->parentWidget()->setWindowTitle(xi18nc("@title:window", "Partition Information")); int x = 0; int y = createHeader(p.deviceNode(), cols(area)); - if (p.fileSystem().type() == FileSystem::Luks) { // inactive LUKS partition + if (p.fileSystem().type() == FileSystem::Type::Luks) { // inactive LUKS partition const FS::luks* luksFs = static_cast(&p.fileSystem()); QString deviceNode = p.partitionPath(); createLabels(i18nc("@label partition", "File system:"), p.fileSystem().name(), cols(area), x, y); createLabels(i18nc("@label partition", "Capacity:"), Capacity::formatByteSize(p.capacity()), cols(area), x, y); createLabels(i18nc("@label partition", "Cipher name:"), luksFs->cipherName(), cols(area), x, y); createLabels(i18nc("@label partition", "Cipher mode:"), luksFs->cipherMode(), cols(area), x, y); createLabels(i18nc("@label partition", "Hash:"), luksFs->hashName(), cols(area), x, y); createLabels(i18nc("@label partition", "Key size:"), QString::number(luksFs->keySize()), cols(area), x, y); createLabels(i18nc("@label partition", "Payload offset:"), Capacity::formatByteSize(luksFs->payloadOffset()), cols(area), x, y); createLabels(i18nc("@label partition", "First sector:"), QLocale().toString(p.firstSector()), cols(area), x, y); createLabels(i18nc("@label partition", "Last sector:"), QLocale().toString(p.lastSector()), cols(area), x, y); createLabels(i18nc("@label partition", "Number of sectors:"), QLocale().toString(p.length()), cols(area), x, y); - } else if (p.fileSystem().type() == FileSystem::Lvm2_PV) { + } else if (p.fileSystem().type() == FileSystem::Type::Lvm2_PV) { FS::lvm2_pv *lvm2PVFs; innerFS(&p, lvm2PVFs); QString deviceNode = p.partitionPath(); createLabels(i18nc("@label partition", "File system:"), p.fileSystem().name(), cols(area), x, y); createLabels(i18nc("@label partition", "Capacity:"), Capacity::formatByteSize(p.capacity()), cols(area), x, y); createLabels(i18nc("@label partition", "Available:"), Capacity::formatByteSize(p.available()), cols(area), x, y); createLabels(i18nc("@label partition", "Used:"), Capacity::formatByteSize(p.used()), cols(area), x, y); createLabels(i18nc("@label partition", "PE Size:"), Capacity::formatByteSize(lvm2PVFs->peSize()), cols(area), x, y); createLabels(i18nc("@label partition", "Total PE:"), QString::number(lvm2PVFs->totalPE()), cols(area), x, y); createLabels(i18nc("@label partition", "Free PE:"), QString::number(lvm2PVFs->freePE()), cols(area), x, y); createLabels(i18nc("@label partition", "Allocated PE:"), QString::number(lvm2PVFs->allocatedPE()), cols(area), x, y); createLabels(i18nc("@label partition", "First sector:"), QLocale().toString(p.firstSector()), cols(area), x, y); createLabels(i18nc("@label partition", "Last sector:"), QLocale().toString(p.lastSector()), cols(area), x, y); createLabels(i18nc("@label partition", "Number of sectors:"), QLocale().toString(p.length()), cols(area), x, y); } else { createLabels(xi18nc("@label partition", "File system:"), p.fileSystem().name(), cols(area), x, y); createLabels(xi18nc("@label partition", "Capacity:"), Capacity::formatByteSize(p.capacity()), cols(area), x, y); createLabels(xi18nc("@label partition", "Available:"), Capacity::formatByteSize(p.available()), cols(area), x, y); createLabels(xi18nc("@label partition", "Used:"), Capacity::formatByteSize(p.used()), cols(area), x, y); createLabels(xi18nc("@label partition", "First sector:"), QLocale().toString(p.firstSector()), cols(area), x, y); createLabels(xi18nc("@label partition", "Last sector:"), QLocale().toString(p.lastSector()), cols(area), x, y); createLabels(xi18nc("@label partition", "Number of sectors:"), QLocale().toString(p.length()), cols(area), x, y); } } /** Shows information about a Device in the InfoPane @param area the current area the widget's dock is in @param d the Device to show information about */ void InfoPane::showDevice(Qt::DockWidgetArea area, const Device& d) { clear(); parentWidget()->parentWidget()->setWindowTitle(xi18nc("@title:window", "Device Information")); int x = 0; int y = createHeader(d.name(), cols(area)); createLabels(xi18nc("@label device", "Path:"), d.deviceNode(), cols(area), x, y); QString type = QStringLiteral("---"); QString maxPrimaries = QStringLiteral("---"); if (d.partitionTable() != nullptr) { type = (d.partitionTable()->isReadOnly()) ? xi18nc("@label device", "%1 (read only)", d.partitionTable()->typeName()) : d.partitionTable()->typeName(); maxPrimaries = QStringLiteral("%1/%2").arg(d.partitionTable()->numPrimaries()).arg(d.partitionTable()->maxPrimaries()); } - if (d.type() == Device::Disk_Device) { - const DiskDevice& disk = dynamic_cast(d); + if (d.type() == Device::Type::Disk_Device) { + const DiskDevice& disk = static_cast(d); createLabels(i18nc("@label device", "Type:"), type, cols(area), x, y); createLabels(i18nc("@label device", "Capacity:"), Capacity::formatByteSize(disk.capacity()), cols(area), x, y); createLabels(i18nc("@label device", "Total sectors:"), QLocale().toString(disk.totalSectors()), cols(area), x, y); createLabels(i18nc("@label device", "Logical sector size:"), Capacity::formatByteSize(disk.logicalSectorSize()), cols(area), x, y); createLabels(i18nc("@label device", "Physical sector size:"), Capacity::formatByteSize(disk.physicalSectorSize()), cols(area), x, y); createLabels(i18nc("@label device", "Primaries/Max:"), maxPrimaries, cols(area), x, y); - } else if (d.type() == Device::LVM_Device) { - const LvmDevice& lvm = dynamic_cast(d); + } else if (d.type() == Device::Type::LVM_Device) { + const LvmDevice& lvm = static_cast(d); createLabels(i18nc("@label device", "Volume Type:"), QStringLiteral("LVM"), cols(area), x, y); createLabels(i18nc("@label device", "Capacity:"), Capacity::formatByteSize(lvm.capacity()), cols(area), x, y); createLabels(i18nc("@label device", "PE Size:"), Capacity::formatByteSize(lvm.peSize()), cols(area), x, y); createLabels(i18nc("@label device", "Total PE:"),QString::number(lvm.totalPE()), cols(area), x, y); createLabels(i18nc("@label device", "Allocated PE:"), QString::number(lvm.allocatedPE()), cols(area), x, y); createLabels(i18nc("@label device", "Free PE:"), QString::number(lvm.freePE()), cols(area), x, y); + } else if (d.type() == Device::Type::SoftwareRAID_Device) { + const SoftwareRAID& raid = static_cast(d); + createLabels(i18nc("@label device", "Volume Type:"), QStringLiteral("RAID"), cols(area), x, y); + createLabels(i18nc("@label device", "Capacity:"), Capacity::formatByteSize(raid.capacity()), cols(area), x, y); + createLabels(i18nc("@label device", "RAID Level:"), raid.raidLevel() < 0 ? QStringLiteral("---") : QString::number(raid.raidLevel()), cols(area), x, y); + createLabels(i18nc("@label device", "Chunk Size:"),Capacity::formatByteSize(raid.chunkSize()), cols(area), x, y); + createLabels(i18nc("@label device", "Total Chunk:"), Capacity::formatByteSize(raid.totalChunk()), cols(area), x, y); + createLabels(i18nc("@label device", "Array Size:"), Capacity::formatByteSize(raid.arraySize()), cols(area), x, y); } } qint32 InfoPane::cols(Qt::DockWidgetArea area) const { if (area == Qt::LeftDockWidgetArea || area == Qt::RightDockWidgetArea) return 2; return 6; } diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index d288d0b..404150e 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1,1326 +1,1327 @@ /************************************************************************* * Copyright (C) 2008, 2009, 2010, 2012 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/mainwindow.h" #include "gui/infopane.h" #include "gui/applyprogressdialog.h" #include "gui/scanprogressdialog.h" #include "gui/createpartitiontabledialog.h" #include "gui/createvolumegroupdialog.h" #include "gui/resizevolumegroupdialog.h" #include "gui/filesystemsupportdialog.h" #include "gui/devicepropsdialog.h" #include "gui/smartdialog.h" #include "config/configureoptionsdialog.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 #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 #include - -#include - -#include -#include +#include "config.h" /** Creates a new MainWindow instance. @param parent the parent widget */ MainWindow::MainWindow(QWidget* parent) : KXmlGuiWindow(parent), Ui::MainWindowBase(), m_OperationStack(new OperationStack(this)), m_OperationRunner(new OperationRunner(this, operationStack())), m_DeviceScanner(new DeviceScanner(this, operationStack())), m_ApplyProgressDialog(new ApplyProgressDialog(this, operationRunner())), m_ScanProgressDialog(new ScanProgressDialog(this)), m_StatusText(new QLabel(this)) { setupObjectNames(); setupUi(this); connect(&m_ListDevices->listDevices(), &QListWidget::customContextMenuRequested, this, &MainWindow::listDevicesContextMenuRequested); connect(&m_TreeLog->treeLog(), &QTreeWidget::customContextMenuRequested, this, &MainWindow::treeLogContextMenuRequested); connect(&m_ListOperations->listOperations(), &QListWidget::customContextMenuRequested, this, &MainWindow::listOperationsContextMenuRequested); init(); } void MainWindow::setupObjectNames() { m_OperationStack->setObjectName(QStringLiteral("m_OperationStack")); m_OperationRunner->setObjectName(QStringLiteral("m_OperationRunner")); m_DeviceScanner->setObjectName(QStringLiteral("m_DeviceScanner")); m_ApplyProgressDialog->setObjectName(QStringLiteral("m_ApplyProgressDialog")); m_ScanProgressDialog->setObjectName(QStringLiteral("m_ScanProgressDialog")); } void MainWindow::init() { treeLog().init(); connect(GlobalLog::instance(), &GlobalLog::newMessage, &treeLog(), &TreeLog::onNewLogMessage); setupActions(); setupStatusBar(); setupConnections(); listDevices().setActionCollection(actionCollection()); listOperations().setActionCollection(actionCollection()); - pmWidget().init(&operationStack()); setupGUI(); loadConfig(); + show(); + ExternalCommand::setParentWidget(this); + pmWidget().init(&operationStack()); + scanDevices(); } void MainWindow::closeEvent(QCloseEvent* event) { if (applyProgressDialog().isVisible()) { event->ignore(); return; } if (operationStack().size() > 0) { if (KMessageBox::warningContinueCancel(this, xi18ncp("@info", "Do you really want to quit the application?There is still an operation pending.", "Do you really want to quit the application?There are still %1 operations pending.", operationStack().size()), xi18nc("@title:window", "Discard Pending Operations and Quit?"), KGuiItem(xi18nc("@action:button", "Quit %1", QGuiApplication::applicationDisplayName()), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyQuit")) == KMessageBox::Cancel) { event->ignore(); return; } } saveConfig(); KXmlGuiWindow::closeEvent(event); + ExternalCommand::stopHelper(); } void MainWindow::changeEvent(QEvent* event) { if ((event->type() == QEvent::ActivationChange || event->type() == QEvent::WindowStateChange) && event->spontaneous() && isActiveWindow()) { QWidget* w = nullptr; if (applyProgressDialog().isVisible()) w = &applyProgressDialog(); else if (scanProgressDialog().isVisible()) w = &scanProgressDialog(); if (w != nullptr) { w->activateWindow(); w->raise(); w->setFocus(); } } KXmlGuiWindow::changeEvent(event); } void MainWindow::setupActions() { // File actions KStandardAction::quit(this, &MainWindow::close, actionCollection()); // Edit actions QAction* undoOperation = actionCollection()->addAction(QStringLiteral("undoOperation")); connect(undoOperation, &QAction::triggered, this, &MainWindow::onUndoOperation); undoOperation->setEnabled(false); undoOperation->setText(xi18nc("@action:inmenu", "Undo")); undoOperation->setToolTip(xi18nc("@info:tooltip", "Undo the last operation")); undoOperation->setStatusTip(xi18nc("@info:status", "Remove the last operation from the list.")); actionCollection()->setDefaultShortcut(undoOperation, QKeySequence(Qt::CTRL + Qt::Key_Z)); undoOperation->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* clearAllOperations = actionCollection()->addAction(QStringLiteral("clearAllOperations")); connect(clearAllOperations, &QAction::triggered, this, &MainWindow::onClearAllOperations); clearAllOperations->setEnabled(false); clearAllOperations->setText(xi18nc("@action:inmenu clear the list of operations", "Clear")); clearAllOperations->setToolTip(xi18nc("@info:tooltip", "Clear all operations")); clearAllOperations->setStatusTip(xi18nc("@info:status", "Empty the list of pending operations.")); clearAllOperations->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* applyAllOperations = actionCollection()->addAction(QStringLiteral("applyAllOperations")); connect(applyAllOperations, &QAction::triggered, this, &MainWindow::onApplyAllOperations); applyAllOperations->setEnabled(false); applyAllOperations->setText(xi18nc("@action:inmenu apply all operations", "Apply")); applyAllOperations->setToolTip(xi18nc("@info:tooltip", "Apply all operations")); applyAllOperations->setStatusTip(xi18nc("@info:status", "Apply the pending operations in the list.")); applyAllOperations->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok-apply")).pixmap(IconSize(KIconLoader::Toolbar))); // Device actions QAction* createNewPartitionTable = actionCollection()->addAction(QStringLiteral("createNewPartitionTable")); connect(createNewPartitionTable, &QAction::triggered, this, &MainWindow::onCreateNewPartitionTable); createNewPartitionTable->setEnabled(false); createNewPartitionTable->setText(xi18nc("@action:inmenu", "New Partition Table")); createNewPartitionTable->setToolTip(xi18nc("@info:tooltip", "Create a new partition table")); createNewPartitionTable->setStatusTip(xi18nc("@info:status", "Create a new and empty partition table on a device.")); actionCollection()->setDefaultShortcut(createNewPartitionTable, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N)); createNewPartitionTable->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* exportPartitionTable = actionCollection()->addAction(QStringLiteral("exportPartitionTable")); connect(exportPartitionTable, &QAction::triggered, this, &MainWindow::onExportPartitionTable); exportPartitionTable->setEnabled(false); exportPartitionTable->setText(xi18nc("@action:inmenu", "Export Partition Table")); exportPartitionTable->setToolTip(xi18nc("@info:tooltip", "Export a partition table")); exportPartitionTable->setStatusTip(xi18nc("@info:status", "Export the device's partition table to a text file.")); exportPartitionTable->setIcon(QIcon::fromTheme(QStringLiteral("document-export")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* importPartitionTable = actionCollection()->addAction(QStringLiteral("importPartitionTable")); connect(importPartitionTable, &QAction::triggered, this, &MainWindow::onImportPartitionTable); importPartitionTable->setEnabled(false); importPartitionTable->setText(xi18nc("@action:inmenu", "Import Partition Table")); importPartitionTable->setToolTip(xi18nc("@info:tooltip", "Import a partition table")); importPartitionTable->setStatusTip(xi18nc("@info:status", "Import a partition table from a text file.")); importPartitionTable->setIcon(QIcon::fromTheme(QStringLiteral("document-import")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* removeVolumeGroup = actionCollection()->addAction(QStringLiteral("removeVolumeGroup")); connect(removeVolumeGroup, &QAction::triggered, this, &MainWindow::onRemoveVolumeGroup); removeVolumeGroup->setEnabled(false); removeVolumeGroup->setVisible(false); removeVolumeGroup->setText(i18nc("@action:inmenu", "Remove Volume Group")); removeVolumeGroup->setToolTip(i18nc("@info:tooltip", "Remove selected Volume Group")); removeVolumeGroup->setStatusTip(i18nc("@info:status", "Remove selected Volume Group.")); //actionCollection()->setDefaultShortcut(removeVolumeGroup, QKeySequence(/*SHORTCUT KEY HERE*/)); removeVolumeGroup->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* resizeVolumeGroup = actionCollection()->addAction(QStringLiteral("resizeVolumeGroup")); connect(resizeVolumeGroup, &QAction::triggered, this, &MainWindow::onResizeVolumeGroup); resizeVolumeGroup->setEnabled(false); resizeVolumeGroup->setVisible(false); resizeVolumeGroup->setText(i18nc("@action:inmenu", "Resize Volume Group")); resizeVolumeGroup->setToolTip(i18nc("@info:tooltip", "Resize selected Volume Group")); resizeVolumeGroup->setStatusTip(i18nc("@info:status", "Extend or reduce selected Volume Group.")); //actionCollection()->setDefaultShortcut(resizeVolumeGroup, QKeySequence(/*SHORTCUT KEY HERE*/)); resizeVolumeGroup->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right-double")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* deactivateVolumeGroup = actionCollection()->addAction(QStringLiteral("deactivateVolumeGroup")); connect(deactivateVolumeGroup, &QAction::triggered, this, &MainWindow::onDeactivateVolumeGroup); deactivateVolumeGroup->setEnabled(false); deactivateVolumeGroup->setVisible(false); deactivateVolumeGroup->setText(i18nc("@action:inmenu", "Deactivate Volume Group")); deactivateVolumeGroup->setToolTip(i18nc("@info:tooltip", "Deactivate selected Volume Group")); deactivateVolumeGroup->setStatusTip(i18nc("@info:status", "Deactivate selected Volume Group before unplugging removable devices.")); deactivateVolumeGroup->setIcon(QIcon::fromTheme(QStringLiteral("media-eject")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* smartStatusDevice = actionCollection()->addAction(QStringLiteral("smartStatusDevice")); connect(smartStatusDevice, &QAction::triggered, this, &MainWindow::onSmartStatusDevice); smartStatusDevice->setEnabled(false); smartStatusDevice->setText(xi18nc("@action:inmenu", "SMART Status")); smartStatusDevice->setToolTip(xi18nc("@info:tooltip", "Show SMART status")); smartStatusDevice->setStatusTip(xi18nc("@info:status", "Show the device's SMART status if supported")); QAction* propertiesDevice = actionCollection()->addAction(QStringLiteral("propertiesDevice")); connect(propertiesDevice, &QAction::triggered, [this] {onPropertiesDevice({});}); propertiesDevice->setEnabled(false); propertiesDevice->setText(xi18nc("@action:inmenu", "Properties")); propertiesDevice->setToolTip(xi18nc("@info:tooltip", "Show device properties dialog")); propertiesDevice->setStatusTip(xi18nc("@info:status", "View and modify device properties")); propertiesDevice->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")).pixmap(IconSize(KIconLoader::Toolbar))); // Partition actions QAction* newPartition = actionCollection()->addAction(QStringLiteral("newPartition")); connect(newPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onNewPartition); newPartition->setEnabled(false); newPartition->setText(xi18nc("@action:inmenu create a new partition", "New")); newPartition->setToolTip(xi18nc("@info:tooltip", "New partition")); newPartition->setStatusTip(xi18nc("@info:status", "Create a new partition.")); actionCollection()->setDefaultShortcut(newPartition, QKeySequence(Qt::CTRL + Qt::Key_N)); newPartition->setIcon(QIcon::fromTheme(QStringLiteral("document-new")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* resizePartition = actionCollection()->addAction(QStringLiteral("resizePartition")); connect(resizePartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onResizePartition); resizePartition->setEnabled(false); resizePartition->setText(xi18nc("@action:inmenu", "Resize/Move")); resizePartition->setToolTip(xi18nc("@info:tooltip", "Resize or move partition")); resizePartition->setStatusTip(xi18nc("@info:status", "Shrink, grow or move an existing partition.")); actionCollection()->setDefaultShortcut(resizePartition, QKeySequence(Qt::CTRL + Qt::Key_R)); resizePartition->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right-double")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* deletePartition = actionCollection()->addAction(QStringLiteral("deletePartition")); connect(deletePartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onDeletePartition); deletePartition->setEnabled(false); deletePartition->setText(xi18nc("@action:inmenu", "Delete")); deletePartition->setToolTip(xi18nc("@info:tooltip", "Delete partition")); deletePartition->setStatusTip(xi18nc("@info:status", "Delete a partition.")); actionCollection()->setDefaultShortcut(deletePartition, QKeySequence::Delete); deletePartition->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* shredPartition = actionCollection()->addAction(QStringLiteral("shredPartition")); connect(shredPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onShredPartition); shredPartition->setEnabled(false); shredPartition->setText(xi18nc("@action:inmenu", "Shred")); shredPartition->setToolTip(xi18nc("@info:tooltip", "Shred partition")); shredPartition->setStatusTip(xi18nc("@info:status", "Shred a partition so that its contents cannot be restored.")); actionCollection()->setDefaultShortcut(shredPartition, QKeySequence(Qt::SHIFT + Qt::Key_Delete)); shredPartition->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete-shred")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* copyPartition = actionCollection()->addAction(QStringLiteral("copyPartition")); connect(copyPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onCopyPartition); copyPartition->setEnabled(false); copyPartition->setText(xi18nc("@action:inmenu", "Copy")); copyPartition->setToolTip(xi18nc("@info:tooltip", "Copy partition")); copyPartition->setStatusTip(xi18nc("@info:status", "Copy an existing partition.")); actionCollection()->setDefaultShortcut(copyPartition, QKeySequence(Qt::CTRL + Qt::Key_C)); copyPartition->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* pastePartition = actionCollection()->addAction(QStringLiteral("pastePartition")); connect(pastePartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onPastePartition); pastePartition->setEnabled(false); pastePartition->setText(xi18nc("@action:inmenu", "Paste")); pastePartition->setToolTip(xi18nc("@info:tooltip", "Paste partition")); pastePartition->setStatusTip(xi18nc("@info:status", "Paste a copied partition.")); actionCollection()->setDefaultShortcut(pastePartition, QKeySequence(Qt::CTRL + Qt::Key_V)); pastePartition->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* editMountPoint = actionCollection()->addAction(QStringLiteral("editMountPoint")); connect(editMountPoint, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onEditMountPoint); editMountPoint->setEnabled(false); editMountPoint->setText(xi18nc("@action:inmenu", "Edit Mount Point")); editMountPoint->setToolTip(xi18nc("@info:tooltip", "Edit mount point")); editMountPoint->setStatusTip(xi18nc("@info:status", "Edit a partition's mount point and options.")); QAction* mountPartition = actionCollection()->addAction(QStringLiteral("mountPartition")); connect(mountPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onMountPartition); mountPartition->setEnabled(false); mountPartition->setText(xi18nc("@action:inmenu", "Mount")); mountPartition->setToolTip(xi18nc("@info:tooltip", "Mount or unmount partition")); mountPartition->setStatusTip(xi18nc("@info:status", "Mount or unmount a partition.")); QAction* decryptPartition = actionCollection()->addAction(QStringLiteral("decryptPartition")); connect(decryptPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onDecryptPartition); decryptPartition->setEnabled(false); decryptPartition->setText(xi18nc("@action:inmenu", "Unlock")); decryptPartition->setToolTip(xi18nc("@info:tooltip", "Unlock or lock encrypted partition")); decryptPartition->setStatusTip(xi18nc("@info:status", "Unlock or lock encrypted partition.")); QAction* checkPartition = actionCollection()->addAction(QStringLiteral("checkPartition")); connect(checkPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onCheckPartition); checkPartition->setEnabled(false); checkPartition->setText(xi18nc("@action:inmenu", "Check")); checkPartition->setToolTip(xi18nc("@info:tooltip", "Check partition")); checkPartition->setStatusTip(xi18nc("@info:status", "Check a filesystem on a partition for errors.")); checkPartition->setIcon(QIcon::fromTheme(QStringLiteral("flag")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* propertiesPartition = actionCollection()->addAction(QStringLiteral("propertiesPartition")); connect(propertiesPartition, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onPropertiesPartition); propertiesPartition->setEnabled(false); propertiesPartition->setText(xi18nc("@action:inmenu", "Properties")); propertiesPartition->setToolTip(xi18nc("@info:tooltip", "Show partition properties dialog")); propertiesPartition->setStatusTip(xi18nc("@info:status", "View and modify partition properties (label, partition flags, etc.)")); propertiesPartition->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* backup = actionCollection()->addAction(QStringLiteral("backupPartition")); connect(backup, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onBackupPartition); backup->setEnabled(false); backup->setText(xi18nc("@action:inmenu", "Backup")); backup->setToolTip(xi18nc("@info:tooltip", "Backup partition")); backup->setStatusTip(xi18nc("@info:status", "Backup a partition to an image file.")); backup->setIcon(QIcon::fromTheme(QStringLiteral("document-export")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* restore = actionCollection()->addAction(QStringLiteral("restorePartition")); connect(restore, &QAction::triggered, &pmWidget(), &PartitionManagerWidget::onRestorePartition); restore->setEnabled(false); restore->setText(xi18nc("@action:inmenu", "Restore")); restore->setToolTip(xi18nc("@info:tooltip", "Restore partition")); restore->setStatusTip(xi18nc("@info:status", "Restore a partition from an image file.")); restore->setIcon(QIcon::fromTheme(QStringLiteral("document-import")).pixmap(IconSize(KIconLoader::Toolbar))); // Tools actions QAction* createVolumeGroup = actionCollection()->addAction(QStringLiteral("createVolumeGroup")); connect(createVolumeGroup, &QAction::triggered, this, &MainWindow::onCreateNewVolumeGroup); createVolumeGroup->setEnabled(false); createVolumeGroup->setText(i18nc("@action:inmenu", "New Volume Group")); createVolumeGroup->setToolTip(i18nc("@info:tooltip", "Create a new LVM Volume Group")); createVolumeGroup->setStatusTip(i18nc("@info:status", "Create a new LVM Volume Group as a device.")); actionCollection()->setDefaultShortcut(createVolumeGroup, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_L)); createVolumeGroup->setIcon(QIcon::fromTheme(QStringLiteral("document-new")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* fileSystemSupport = actionCollection()->addAction(QStringLiteral("fileSystemSupport")); connect(fileSystemSupport, &QAction::triggered, this, &MainWindow::onFileSystemSupport); fileSystemSupport->setText(xi18nc("@action:inmenu", "File System Support")); fileSystemSupport->setToolTip(xi18nc("@info:tooltip", "View file system support information")); fileSystemSupport->setStatusTip(xi18nc("@info:status", "Show information about supported file systems.")); QAction* refreshDevices = actionCollection()->addAction(QStringLiteral("refreshDevices")); connect(refreshDevices, &QAction::triggered, this, &MainWindow::onRefreshDevices); refreshDevices->setText(xi18nc("@action:inmenu refresh list of devices", "Refresh Devices")); refreshDevices->setToolTip(xi18nc("@info:tooltip", "Refresh all devices")); refreshDevices->setStatusTip(xi18nc("@info:status", "Renew the devices list.")); actionCollection()->setDefaultShortcut(refreshDevices, Qt::Key_F5); refreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")).pixmap(IconSize(KIconLoader::Toolbar))); // Settings Actions actionCollection()->addAction(QStringLiteral("toggleDockDevices"), dockDevices().toggleViewAction()); actionCollection()->addAction(QStringLiteral("toggleDockOperations"), dockOperations().toggleViewAction()); actionCollection()->addAction(QStringLiteral("toggleDockInformation"), dockInformation().toggleViewAction()); actionCollection()->addAction(QStringLiteral("toggleDockLog"), dockLog().toggleViewAction()); KStandardAction::preferences(this, &MainWindow::onConfigureOptions, actionCollection()); // Log Actions QAction* clearLog = actionCollection()->addAction(QStringLiteral("clearLog")); connect(clearLog, &QAction::triggered, &treeLog(), &TreeLog::onClearLog); clearLog->setText(xi18nc("@action:inmenu", "Clear Log")); clearLog->setToolTip(xi18nc("@info:tooltip", "Clear the log output")); clearLog->setStatusTip(xi18nc("@info:status", "Clear the log output panel.")); clearLog->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-list")).pixmap(IconSize(KIconLoader::Toolbar))); QAction* saveLog = actionCollection()->addAction(QStringLiteral("saveLog")); connect(saveLog, &QAction::triggered, &treeLog(), &TreeLog::onSaveLog); saveLog->setText(xi18nc("@action:inmenu", "Save Log")); saveLog->setToolTip(xi18nc("@info:tooltip", "Save the log output")); saveLog->setStatusTip(xi18nc("@info:status", "Save the log output to a file.")); saveLog->setIcon(QIcon::fromTheme(QStringLiteral("document-save")).pixmap(IconSize(KIconLoader::Toolbar))); // Help Actions QAction* aboutKPMcore = actionCollection()->addAction(QStringLiteral("aboutKPMcore")); connect(aboutKPMcore, &QAction::triggered, this, &MainWindow::onShowAboutKPMcore); aboutKPMcore->setText(xi18nc("@action:inmenu", "About KPMcore Library")); aboutKPMcore->setToolTip(xi18nc("@info:tooltip", "Show About KPMcore dialog")); aboutKPMcore->setStatusTip(xi18nc("@info:status", "Show About KPMcore dialog.")); aboutKPMcore->setIcon(QIcon::fromTheme(QStringLiteral("partitionmanager")).pixmap(IconSize(KIconLoader::Toolbar))); } void MainWindow::setupConnections() { connect(&listDevices(), &ListDevices::selectionChanged, &pmWidget(), qOverload(&PartitionManagerWidget::setSelectedDevice)); connect(&listDevices(), &ListDevices::deviceDoubleClicked, this, &MainWindow::onPropertiesDevice); } void MainWindow::setupStatusBar() { statusBar()->addWidget(&statusText()); } void MainWindow::loadConfig() { if (Config::firstRun()) { dockLog().setVisible(false); dockInformation().setVisible(false); } PartitionAlignment::setSectorAlignment(Config::sectorAlignment()); } void MainWindow::saveConfig() const { Config::setFirstRun(false); Config::self()->save(); } void MainWindow::enableActions() { actionCollection()->action(QStringLiteral("createNewPartitionTable")) ->setEnabled(CreatePartitionTableOperation::canCreate(pmWidget().selectedDevice())); actionCollection()->action(QStringLiteral("createNewPartitionTable")) - ->setVisible(pmWidget().selectedDevice() && pmWidget().selectedDevice()->type() == Device::Disk_Device); + ->setVisible(pmWidget().selectedDevice() && (pmWidget().selectedDevice()->type() == Device::Type::Disk_Device || + pmWidget().selectedDevice()->type() == Device::Type::SoftwareRAID_Device)); actionCollection()->action(QStringLiteral("exportPartitionTable")) ->setEnabled(pmWidget().selectedDevice() && pmWidget().selectedDevice()->partitionTable() && operationStack().size() == 0); actionCollection()->action(QStringLiteral("importPartitionTable")) ->setEnabled(CreatePartitionTableOperation::canCreate(pmWidget().selectedDevice())); actionCollection()->action(QStringLiteral("smartStatusDevice")) - ->setEnabled(pmWidget().selectedDevice() != nullptr && pmWidget().selectedDevice()->type() == Device::Disk_Device && + ->setEnabled(pmWidget().selectedDevice() != nullptr && pmWidget().selectedDevice()->type() == Device::Type::Disk_Device && pmWidget().selectedDevice()->smartStatus().isValid()); actionCollection()->action(QStringLiteral("smartStatusDevice")) - ->setVisible(pmWidget().selectedDevice() != nullptr && pmWidget().selectedDevice()->type() == Device::Disk_Device); + ->setVisible(pmWidget().selectedDevice() != nullptr && pmWidget().selectedDevice()->type() == Device::Type::Disk_Device); actionCollection()->action(QStringLiteral("propertiesDevice")) ->setEnabled(pmWidget().selectedDevice() != nullptr); actionCollection()->action(QStringLiteral("undoOperation")) ->setEnabled(operationStack().size() > 0); actionCollection()->action(QStringLiteral("clearAllOperations")) ->setEnabled(operationStack().size() > 0); actionCollection()->action(QStringLiteral("applyAllOperations")) - ->setEnabled(operationStack().size() > 0 && (geteuid() == 0 || - Config::allowApplyOperationsAsNonRoot())); + ->setEnabled(operationStack().size() > 0); const bool readOnly = pmWidget().selectedDevice() == nullptr || pmWidget().selectedDevice()->partitionTable() == nullptr || pmWidget().selectedDevice()->partitionTable()->isReadOnly(); actionCollection()->action(QStringLiteral("createVolumeGroup")) ->setEnabled(CreateVolumeGroupOperation::canCreate()); - bool lvmDevice = pmWidget().selectedDevice() && pmWidget().selectedDevice()->type() == Device::LVM_Device; + bool lvmDevice = pmWidget().selectedDevice() && pmWidget().selectedDevice()->type() == Device::Type::LVM_Device; bool removable = false; if (lvmDevice) removable = RemoveVolumeGroupOperation::isRemovable(dynamic_cast(pmWidget().selectedDevice())); actionCollection()->action(QStringLiteral("removeVolumeGroup"))->setEnabled(removable); actionCollection()->action(QStringLiteral("removeVolumeGroup"))->setVisible(lvmDevice); bool deactivatable = lvmDevice ? DeactivateVolumeGroupOperation::isDeactivatable(dynamic_cast(pmWidget().selectedDevice())) : false; actionCollection()->action(QStringLiteral("deactivateVolumeGroup"))->setEnabled(deactivatable); actionCollection()->action(QStringLiteral("deactivateVolumeGroup"))->setVisible(lvmDevice); actionCollection()->action(QStringLiteral("resizeVolumeGroup"))->setEnabled(lvmDevice); actionCollection()->action(QStringLiteral("resizeVolumeGroup"))->setVisible(lvmDevice); const Partition* part = pmWidget().selectedPartition(); actionCollection()->action(QStringLiteral("newPartition")) ->setEnabled(!readOnly && NewOperation::canCreateNew(part)); const bool canResize = ResizeOperation::canGrow(part) || ResizeOperation::canShrink(part) || ResizeOperation::canMove(part); actionCollection()->action(QStringLiteral("resizePartition")) ->setEnabled(!readOnly && canResize); actionCollection()->action(QStringLiteral("copyPartition")) ->setEnabled(CopyOperation::canCopy(part)); actionCollection()->action(QStringLiteral("deletePartition")) ->setEnabled(!readOnly && DeleteOperation::canDelete(part)); actionCollection()->action(QStringLiteral("shredPartition")) ->setEnabled(!readOnly && DeleteOperation::canDelete(part)); actionCollection()->action(QStringLiteral("pastePartition")) ->setEnabled(!readOnly && CopyOperation::canPaste(part, pmWidget().clipboardPartition())); actionCollection()->action(QStringLiteral("propertiesPartition")) ->setEnabled(part != nullptr); actionCollection()->action(QStringLiteral("editMountPoint")) ->setEnabled(part && !part->isMounted() && part->fileSystem().canMount(part->deviceNode(), QStringLiteral("/"))); actionCollection()->action(QStringLiteral("mountPartition")) ->setEnabled(part && (part->canMount() || part->canUnmount())); if (part != nullptr) actionCollection()->action(QStringLiteral("mountPartition")) ->setText(part->isMounted() ? part->fileSystem().unmountTitle() : part->fileSystem().mountTitle()); if (part && part->roles().has(PartitionRole::Luks)) { const FileSystem& fsRef = part->fileSystem(); const FS::luks* luksFs = dynamic_cast(&fsRef); actionCollection()->action(QStringLiteral("decryptPartition")) ->setVisible(true); actionCollection()->action(QStringLiteral("decryptPartition")) ->setEnabled(luksFs && !operationStack().contains(part) && (luksFs->canCryptOpen(part->partitionPath()) || luksFs->canCryptClose(part->partitionPath()))); if (luksFs) { actionCollection()->action(QStringLiteral("decryptPartition")) ->setText(luksFs->isCryptOpen() ? luksFs->cryptCloseTitle() : luksFs->cryptOpenTitle()); } } else { actionCollection()->action(QStringLiteral("decryptPartition")) ->setEnabled(false); actionCollection()->action(QStringLiteral("decryptPartition")) ->setVisible(false); } actionCollection()->action(QStringLiteral("checkPartition")) ->setEnabled(!readOnly && CheckOperation::canCheck(part)); actionCollection()->action(QStringLiteral("backupPartition")) ->setEnabled(BackupOperation::canBackup(part)); actionCollection()->action(QStringLiteral("restorePartition")) ->setEnabled(RestoreOperation::canRestore(part)); } void MainWindow::on_m_ApplyProgressDialog_finished() { scanDevices(); } void MainWindow::on_m_OperationStack_operationsChanged() { listOperations().updateOperations(operationStack().operations()); pmWidget().updatePartitions(); enableActions(); // this will make sure that the info pane gets updated on_m_PartitionManagerWidget_selectedPartitionChanged(pmWidget().selectedPartition()); statusText().setText(xi18ncp("@info:status", "One pending operation", "%1 pending operations", operationStack().size())); } void MainWindow::on_m_OperationStack_devicesChanged() { QReadLocker lockDevices(&operationStack().lock()); listDevices().updateDevices(operationStack().previewDevices()); if (pmWidget().selectedDevice()) infoPane().showDevice(dockWidgetArea(&dockInformation()), *pmWidget().selectedDevice()); else infoPane().clear(); updateWindowTitle(); } void MainWindow::on_m_DockInformation_dockLocationChanged(Qt::DockWidgetArea) { on_m_PartitionManagerWidget_selectedPartitionChanged(pmWidget().selectedPartition()); } void MainWindow::updateWindowTitle() { QString title; if (pmWidget().selectedDevice()) title = pmWidget().selectedDevice()->deviceNode(); setWindowTitle(title); } void MainWindow::listOperationsContextMenuRequested(const QPoint& pos) { QMenu* menu = static_cast(guiFactory()->container(QStringLiteral("edit"), this)); if (menu) menu->exec(m_ListOperations->listOperations().viewport()->mapToGlobal(pos)); } void MainWindow::treeLogContextMenuRequested(const QPoint& pos) { QMenu* menu = static_cast(guiFactory()->container(QStringLiteral("log"), this)); if (menu) menu->exec(m_TreeLog->treeLog().viewport()->mapToGlobal(pos)); } void MainWindow::listDevicesContextMenuRequested(const QPoint& pos) { QMenu* menu = static_cast(guiFactory()->container(QStringLiteral("device"), this)); if (menu) menu->exec(m_ListDevices->listDevices().viewport()->mapToGlobal(pos)); } void MainWindow::on_m_PartitionManagerWidget_contextMenuRequested(const QPoint& pos) { QMenu* menu = nullptr; if (pmWidget().selectedPartition() == nullptr) { if (pmWidget().selectedDevice() != nullptr) menu = static_cast(guiFactory()->container(QStringLiteral("device"), this)); } else menu = static_cast(guiFactory()->container(QStringLiteral("partition"), this)); if (menu) menu->exec(pos); } void MainWindow::on_m_PartitionManagerWidget_deviceDoubleClicked(const Device*) { actionCollection()->action(QStringLiteral("propertiesDevice"))->trigger(); } void MainWindow::on_m_PartitionManagerWidget_partitionDoubleClicked(const Partition*) { actionCollection()->action(QStringLiteral("propertiesPartition"))->trigger(); } void MainWindow::on_m_PartitionManagerWidget_selectedPartitionChanged(const Partition* p) { if (p) infoPane().showPartition(dockWidgetArea(&dockInformation()), *p); else if (pmWidget().selectedDevice()) infoPane().showDevice(dockWidgetArea(&dockInformation()), *pmWidget().selectedDevice()); else infoPane().clear(); updateWindowTitle(); enableActions(); } void MainWindow::scanDevices() { - Log(Log::information) << xi18nc("@info:progress", "Using backend plugin: %1 (%2)", + Log(Log::Level::information) << xi18nc("@info:progress", "Using backend plugin: %1 (%2)", CoreBackendManager::self()->backend()->id(), CoreBackendManager::self()->backend()->version()); Log() << xi18nc("@info:progress", "Scanning devices..."); // remember the currently selected device's node setSavedSelectedDeviceNode(pmWidget().selectedDevice() ? pmWidget().selectedDevice()->deviceNode() : QString()); pmWidget().clear(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); scanProgressDialog().setEnabled(true); scanProgressDialog().show(); deviceScanner().start(); } void MainWindow::on_m_DeviceScanner_progress(const QString& deviceNode, int percent) { scanProgressDialog().setProgress(percent); scanProgressDialog().setDeviceName(deviceNode); } void MainWindow::on_m_DeviceScanner_finished() { QReadLocker lockDevices(&operationStack().lock()); scanProgressDialog().setProgress(100); if (!operationStack().previewDevices().isEmpty()) pmWidget().setSelectedDevice(operationStack().previewDevices()[0]); pmWidget().updatePartitions(); Log() << xi18nc("@info:progress", "Scan finished."); QApplication::restoreOverrideCursor(); // try to set the seleted device, either from the saved one or just select the // first device if (!listDevices().setSelectedDevice(savedSelectedDeviceNode()) && !operationStack().previewDevices().isEmpty()) listDevices().setSelectedDevice(operationStack().previewDevices()[0]->deviceNode()); updateSeletedDeviceMenu(); checkFileSystemSupport(); } void MainWindow::updateSeletedDeviceMenu() { QMenu* devicesMenu = static_cast(guiFactory()->container(QStringLiteral("selectedDevice"), this)); if (!devicesMenu) return; devicesMenu->clear(); devicesMenu->setEnabled(!operationStack().previewDevices().isEmpty()); const auto previewDevices = operationStack().previewDevices(); for (auto const &d : previewDevices) { QAction* action = new QAction(d->prettyName(), devicesMenu); action->setCheckable(true); action->setChecked(d->deviceNode() == pmWidget().selectedDevice()->deviceNode()); action->setData(d->deviceNode()); connect(action, &QAction::triggered, this, &MainWindow::onSelectedDeviceMenuTriggered); devicesMenu->addAction(action); } } void MainWindow::onSelectedDeviceMenuTriggered(bool) { QAction* action = qobject_cast(sender()); QMenu* devicesMenu = static_cast(guiFactory()->container(QStringLiteral("selectedDevice"), this)); if (action == nullptr || action->parent() != devicesMenu || !devicesMenu) return; const auto children = devicesMenu->findChildren(); for (auto &entry : children) entry->setChecked(entry == action); listDevices().setSelectedDevice(action->data().toString()); } void MainWindow::on_m_ListDevices_selectionChanged(const QString& device_node) { QMenu* devicesMenu = static_cast(guiFactory()->container(QStringLiteral("selectedDevice"), this)); if (!devicesMenu) return; const auto children = devicesMenu->findChildren(); for (auto &entry : children) entry->setChecked(entry->data().toString() == device_node); } void MainWindow::onRefreshDevices() { if (operationStack().size() == 0 || KMessageBox::warningContinueCancel(this, xi18nc("@info", "Do you really want to rescan the devices?" "This will also clear the list of pending operations."), xi18nc("@title:window", "Really Rescan the Devices?"), KGuiItem(xi18nc("@action:button", "Rescan Devices"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyRescanDevices")) == KMessageBox::Continue) { scanDevices(); } } void MainWindow::onApplyAllOperations() { QStringList opList; const auto operations = operationStack().operations(); for (const auto &op : operations) opList.append(op->description()); if (KMessageBox::warningContinueCancelList(this, xi18nc("@info", "Do you really want to apply the pending operations listed below?" "This will permanently modify your disks."), opList, xi18nc("@title:window", "Apply Pending Operations?"), KGuiItem(xi18nc("@action:button", "Apply Pending Operations"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel()) == KMessageBox::Continue) { Log() << xi18nc("@info:status", "Applying operations..."); applyProgressDialog().show(); operationRunner().setReport(&applyProgressDialog().report()); // Undo all operations so the runner has a defined starting point for (int i = operationStack().operations().size() - 1; i >= 0; i--) { operationStack().operations()[i]->undo(); operationStack().operations()[i]->setStatus(Operation::StatusNone); } pmWidget().updatePartitions(); operationRunner().start(); } } void MainWindow::onUndoOperation() { Q_ASSERT(operationStack().size() > 0); if (operationStack().size() == 0) return; Log() << xi18nc("@info:status", "Undoing operation: %1", operationStack().operations().last()->description()); operationStack().pop(); // it's possible the undo killed the partition in the clipboard. if there's a partition in the clipboard, try // to find a device for it (OperationStack::findDeviceForPartition() only compares pointers, so an invalid // pointer is not a problem). if no device is found, the pointer must be dangling, so clear the clipboard. if (pmWidget().clipboardPartition() != nullptr && operationStack().findDeviceForPartition(pmWidget().clipboardPartition()) == nullptr) pmWidget().setClipboardPartition(nullptr); pmWidget().updatePartitions(); enableActions(); } void MainWindow::onClearAllOperations() { if (KMessageBox::warningContinueCancel(this, xi18nc("@info", "Do you really want to clear the list of pending operations?"), xi18nc("@title:window", "Clear Pending Operations?"), KGuiItem(xi18nc("@action:button", "Clear Pending Operations"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyClearPendingOperations")) == KMessageBox::Continue) { Log() << xi18nc("@info:status", "Clearing the list of pending operations."); operationStack().clearOperations(); pmWidget().updatePartitions(); enableActions(); } } void MainWindow::onCreateNewPartitionTable() { Q_ASSERT(pmWidget().selectedDevice()); if (pmWidget().selectedDevice() == nullptr) { qWarning() << "selected device is null."; return; } QPointer dlg = new CreatePartitionTableDialog(this, *pmWidget().selectedDevice()); if (dlg->exec() == QDialog::Accepted) operationStack().push(new CreatePartitionTableOperation(*pmWidget().selectedDevice(), dlg->type())); delete dlg; } void MainWindow::onImportPartitionTable() { Q_ASSERT(pmWidget().selectedDevice()); const QUrl url = QFileDialog::getOpenFileUrl(this, QStringLiteral("Import Partition Table")); if (url.isEmpty()) return; QFile file; if (url.isLocalFile()) { file.setFileName(url.toLocalFile()); if (!file.open(QFile::ReadOnly)) { KMessageBox::error(this, xi18nc("@info", "Could not open input file %1 for import", url.toLocalFile()), xi18nc("@title:window", "Error Importing Partition Table")); return; } } else { QTemporaryFile tempFile; if (!tempFile.open()) { KMessageBox::error(this, xi18nc("@info", "Could not create temporary file when trying to save to %1.", tempFile.fileName()), xi18nc("@title:window", "Error Importing Partition Table")); return; } KIO::FileCopyJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tempFile.fileName())); KJobWidgets::setWindow(job, this); job->exec(); if (job->error()) { KMessageBox::error(this, xi18nc("@info", "Could not open input file %1 for import: %2", url.fileName(), job->errorString()), xi18nc("@title:window", "Error Importing Partition Table")); return; } file.setFileName(tempFile.fileName()); if (!file.open(QFile::ReadOnly)) { KMessageBox::error(this, xi18nc("@info", "Could not open temporary file %1 while trying to import from %2.", tempFile.fileName(), url.fileName()), xi18nc("@title:window", "Error Importing Partition Table")); return; } } Device& device = *pmWidget().selectedDevice(); QString line; quint32 lineNo = 0; bool haveMagic = false; PartitionTable* ptable = nullptr; PartitionTable::TableType tableType = PartitionTable::unknownTableType; while (!(line = QString::fromUtf8(file.readLine())).isEmpty()) { lineNo++; line = line.trimmed(); if (line.isEmpty()) continue; QRegularExpression re(QStringLiteral("(\\d+);(\\d+);(\\d+);(\\w+);(\\w+);(\"\\w*\");(\"[^\"]*\")")); QRegularExpressionMatch rePartition = re.match(line); re.setPattern(QStringLiteral("type:\\s\"(.+)\"")); QRegularExpressionMatch reType = re.match(line); re.setPattern(QStringLiteral("align:\\s\"(cylinder|sector)\"")); QRegularExpressionMatch reAlign = re.match(line); re.setPattern(QStringLiteral("^##|v(\\d+)|##")); QRegularExpressionMatch reMagic = re.match(line); if (!(haveMagic || reMagic.hasMatch())) { KMessageBox::error(this, xi18nc("@info", "The import file %1 does not contain a valid partition table.", url.fileName()), xi18nc("@title:window", "Error While Importing Partition Table")); return; } else haveMagic = true; if (line.startsWith(QStringLiteral("#"))) continue; if (reType.hasMatch()) { if (ptable != nullptr) { KMessageBox::error(this, xi18nc("@info", "Found more than one partition table type in import file (line %1).", lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } tableType = PartitionTable::nameToTableType(reType.captured(1)); if (tableType == PartitionTable::unknownTableType) { KMessageBox::error(this, xi18nc("@info", "Partition table type \"%1\" is unknown (line %2).", reType.captured(1), lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } if (tableType != PartitionTable::msdos && tableType != PartitionTable::gpt) { KMessageBox::error(this, xi18nc("@info", "Partition table type \"%1\" is not supported for import (line %2).", reType.captured(1), lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } ptable = new PartitionTable(tableType, PartitionTable::defaultFirstUsable(device, tableType), PartitionTable::defaultLastUsable(device, tableType)); operationStack().push(new CreatePartitionTableOperation(device, ptable)); } else if (reAlign.hasMatch()) { // currently ignored } else if (rePartition.hasMatch()) { if (ptable == nullptr) { KMessageBox::error(this, xi18nc("@info", "Found partition but no partition table type (line %1).", lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } qint32 num = rePartition.captured(1).toInt(); qint64 firstSector = rePartition.captured(2).toLongLong(); qint64 lastSector = rePartition.captured(3).toLongLong(); QLatin1String fsName = QLatin1String(rePartition.captured(4).toLatin1()); QString roleNames = rePartition.captured(5); QString volumeLabel = rePartition.captured(6).replace(QStringLiteral("\""), QString()); QStringList flags = rePartition.captured(7).replace(QStringLiteral("\""), QString()).split(QStringLiteral(",")); if (firstSector < ptable->firstUsable() || lastSector > ptable->lastUsable()) { KMessageBox::error(this, xi18nc("@info the partition is NOT a device path, just a number", "Partition %1 would be outside the device's boundaries (line %2).", num, lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } if (firstSector >= lastSector) { KMessageBox::error(this, xi18nc("@info", "Partition %1 has end before start sector (line %2).", num, lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } PartitionNode* parent = ptable; Q_ASSERT(parent); PartitionRole role(PartitionRole::None); if (roleNames == QStringLiteral("extended")) role = PartitionRole(PartitionRole::Extended); else if (roleNames == QStringLiteral("logical")) { role = PartitionRole(PartitionRole::Logical); parent = ptable->findPartitionBySector(firstSector, PartitionRole(PartitionRole::Extended)); } else if (roleNames == QStringLiteral("primary")) role = PartitionRole(PartitionRole::Primary); if (role == PartitionRole(PartitionRole::None)) { KMessageBox::error(this, xi18nc("@info the partition is NOT a device path, just a number", "Unrecognized partition role \"%1\" for partition %2 (line %3).", roleNames, num, lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } if (parent == nullptr) { KMessageBox::error(this, xi18nc("@info the partition is NOT a device path, just a number", "No parent partition or partition table found for partition %1 (line %2).", num, lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } if (role.has(PartitionRole::Extended) && !PartitionTable::tableTypeSupportsExtended(tableType)) { KMessageBox::error(this, xi18nc("@info", "The partition table type \"%1\" does not support extended partitions, but one was found (line %2).", PartitionTable::tableTypeToName(tableType), lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } FileSystem* fs = FileSystemFactory::create(FileSystem::typeForName(fsName, { QStringLiteral("C") }), firstSector, lastSector, device.logicalSize()); if (fs == nullptr) { KMessageBox::error(this, xi18nc("@info the partition is NOT a device path, just a number", "Could not create file system \"%1\" for partition %2 (line %3).", fsName, num, lineNo), xi18nc("@title:window", "Error While Importing Partition Table")); return; } if (fs->supportSetLabel() != FileSystem::cmdSupportNone && !volumeLabel.isEmpty()) fs->setLabel(volumeLabel); - Partition* p = new Partition(parent, device, role, fs, firstSector, lastSector, QString(), PartitionTable::FlagNone, QString(), false, PartitionTable::FlagNone, Partition::StateNew); + Partition* p = new Partition(parent, device, role, fs, firstSector, lastSector, QString(), PartitionTable::FlagNone, QString(), false, PartitionTable::FlagNone, Partition::State::New); operationStack().push(new NewOperation(device, p)); } else - Log(Log::warning) << xi18nc("@info:status", "Could not parse line %1 from import file. Ignoring it.", lineNo); + Log(Log::Level::warning) << xi18nc("@info:status", "Could not parse line %1 from import file. Ignoring it.", lineNo); } if (ptable->type() == PartitionTable::msdos && ptable->isSectorBased(device)) ptable->setType(device, PartitionTable::msdos_sectorbased); } void MainWindow::onExportPartitionTable() { Q_ASSERT(pmWidget().selectedDevice()); Q_ASSERT(pmWidget().selectedDevice()->partitionTable()); const QUrl url = QFileDialog::getSaveFileUrl(); if (url.isEmpty()) return; QTemporaryFile tempFile; if (!tempFile.open()) { KMessageBox::error(this, xi18nc("@info", "Could not create temporary file when trying to save to %1.", url.fileName()), xi18nc("@title:window", "Error Exporting Partition Table")); return; } QTextStream stream(&tempFile); stream << "##|v1|## partition table of " << pmWidget().selectedDevice()->deviceNode() << "\n"; stream << "# on " << QLocale::c().toString(QDateTime::currentDateTime()) << "\n"; stream << *pmWidget().selectedDevice()->partitionTable(); tempFile.close(); KIO::CopyJob* job = KIO::move(QUrl::fromLocalFile(tempFile.fileName()), url, KIO::HideProgressInfo); job->exec(); if (job->error()) job->uiDelegate()->showErrorMessage(); } void MainWindow::onCreateNewVolumeGroup() { QString vgName; QVector pvList; qint32 peSize = 4; // *NOTE*: vgName & pvList will be modified and validated by the dialog - QPointer dlg = new CreateVolumeGroupDialog(this, vgName, pvList, peSize, operationStack().previewDevices()); + QPointer dlg = new CreateVolumeGroupDialog(this, vgName, pvList, peSize, operationStack().previewDevices(), operationStack().operations()); if (dlg->exec() == QDialog::Accepted) operationStack().push(new CreateVolumeGroupOperation(vgName, pvList, peSize)); delete dlg; } void MainWindow::onResizeVolumeGroup() { - if (pmWidget().selectedDevice()->type() == Device::LVM_Device) { + if (pmWidget().selectedDevice()->type() == Device::Type::LVM_Device) { LvmDevice* d = dynamic_cast(pmWidget().selectedDevice()); QVector pvList; // *NOTE*: pvList will be modified and validated by the dialog - QPointer dlg = new ResizeVolumeGroupDialog(this, d, pvList); + QPointer dlg = new ResizeVolumeGroupDialog(this, d, pvList, operationStack().previewDevices(), operationStack().operations()); if (dlg->exec() == QDialog::Accepted) operationStack().push(new ResizeVolumeGroupOperation(*d, pvList)); delete dlg; } } void MainWindow::onRemoveVolumeGroup() { Device* tmpDev = pmWidget().selectedDevice(); - if (tmpDev->type() == Device::LVM_Device) { + if (tmpDev->type() == Device::Type::LVM_Device) { operationStack().push(new RemoveVolumeGroupOperation(*(dynamic_cast(tmpDev)))); } } void MainWindow::onDeactivateVolumeGroup() { Device* tmpDev = pmWidget().selectedDevice(); - if (tmpDev->type() == Device::LVM_Device) { + if (tmpDev->type() == Device::Type::LVM_Device) { DeactivateVolumeGroupOperation* deactivate = new DeactivateVolumeGroupOperation( *(dynamic_cast(tmpDev)) ); Report* tmpReport = new Report(nullptr); if (deactivate->execute(*tmpReport)) { deactivate->preview(); actionCollection()->action(QStringLiteral("resizeVolumeGroup"))->setEnabled(false); actionCollection()->action(QStringLiteral("deactivateVolumeGroup"))->setEnabled(false); } delete tmpReport; pmWidget().updatePartitions(); enableActions(); } } void MainWindow::onFileSystemSupport() { FileSystemSupportDialog dlg(this); dlg.exec(); } void MainWindow::onShowAboutKPMcore() { KAboutApplicationDialog dlg(aboutKPMcore(), this); dlg.exec(); } void MainWindow::onSettingsChanged() { if (CoreBackendManager::self()->backend()->id() != Config::backend()) { CoreBackendManager::self()->unload(); // FIXME: if loadBackend() fails to load the configured backend and loads the default // one instead it also sets the default backend in the config; the config dialog will // overwrite that again, however, after we're done here. if (loadBackend()) { deviceScanner().setupConnections(); scanDevices(); FileSystemFactory::init(); } else close(); } enableActions(); pmWidget().updatePartitions(); PartitionAlignment::setSectorAlignment(Config::sectorAlignment()); emit settingsChanged(); } void MainWindow::onConfigureOptions() { if (ConfigureOptionsDialog::showDialog(QStringLiteral("Settings"))) return; QPointer dlg = new ConfigureOptionsDialog(this, operationStack(), QStringLiteral("Settings")); // FIXME: we'd normally use settingsChanged(), according to the kde api docs. however, this // is emitted each time the user changes any of our own settings (backend, default file system), without // applying or clicking ok. so the below is the workaround for that. connect(dlg->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &MainWindow::onSettingsChanged); connect(dlg->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &MainWindow::onSettingsChanged); dlg->show(); } void MainWindow::onSmartStatusDevice() { Q_ASSERT(pmWidget().selectedDevice()); if (pmWidget().selectedDevice()) { QPointer dlg = new SmartDialog(this, *pmWidget().selectedDevice()); dlg->exec(); delete dlg; } } void MainWindow::onPropertiesDevice(const QString&) { Q_ASSERT(pmWidget().selectedDevice()); if (pmWidget().selectedDevice()) { Device& d = *pmWidget().selectedDevice(); QPointer dlg = new DevicePropsDialog(this, d); if (dlg->exec() == QDialog::Accepted) { if (d.partitionTable()->type() == PartitionTable::msdos && dlg->sectorBasedAlignment()) d.partitionTable()->setType(d, PartitionTable::msdos_sectorbased); else if (d.partitionTable()->type() == PartitionTable::msdos_sectorbased && dlg->cylinderBasedAlignment()) d.partitionTable()->setType(d, PartitionTable::msdos); on_m_OperationStack_devicesChanged(); pmWidget().updatePartitions(); } delete dlg; } } static KLocalizedString checkSupportInNode(const PartitionNode* parent) { if (parent == nullptr) return KLocalizedString(); KLocalizedString rval; for (const auto &node : parent->children()) { const Partition* p = dynamic_cast(node); if (p == nullptr) continue; if (node->children().size() > 0 && !rval.isEmpty()) rval = kxi18n("%1%2").subs(rval).subs(checkSupportInNode(node)); else rval = checkSupportInNode(node); if ((!p->fileSystem().supportToolFound() && !p->fileSystem().supportToolName().name.isEmpty()) && !rval.isEmpty()) rval = kxi18n("%1%2").subs(rval).subs(kxi18n("" "%1" "%2" "%3" "%4" "") .subs(p->deviceNode()) .subs(p->fileSystem().name()) .subs(p->fileSystem().supportToolName().name) .subs(p->fileSystem().supportToolName().url.toString())); else if (!p->fileSystem().supportToolFound() && !p->fileSystem().supportToolName().name.isEmpty()) rval =kxi18n("" "%1" "%2" "%3" "%4" "") .subs(p->deviceNode()) .subs(p->fileSystem().name()) .subs(p->fileSystem().supportToolName().name) .subs(p->fileSystem().supportToolName().url.toString()); } return rval; } void MainWindow::checkFileSystemSupport() { KLocalizedString supportList, supportInNode; bool missingSupportTools = false; const auto previewDevices = operationStack().previewDevices(); for (auto const &d : previewDevices ) { supportInNode = checkSupportInNode(d->partitionTable()); if (!supportInNode.isEmpty() && !supportList.isEmpty()) { missingSupportTools = true; supportList = kxi18n("%1%2").subs(supportList).subs(supportInNode); } else if (!supportInNode.isEmpty()) { missingSupportTools = true; supportList = supportInNode; } } if (missingSupportTools) KMessageBox::information(this, xi18nc("@info", "No support tools were found for file systems currently present on hard disks in this computer:" "" "" "" "" "" "" "" "%1" "
PartitionFile SystemSupport ToolsURL
" "As long as the support tools for these file systems are not installed you will not be able to modify them." "You should find packages with these support tools in your distribution's package manager.", supportList), xi18nc("@title:window", "Missing File System Support Packages"), QStringLiteral("showInformationOnMissingFileSystemSupport"), KMessageBox::Notify | KMessageBox::AllowLink); } diff --git a/src/gui/newdialog.cpp b/src/gui/newdialog.cpp index cebba96..f1686e3 100644 --- a/src/gui/newdialog.cpp +++ b/src/gui/newdialog.cpp @@ -1,292 +1,292 @@ /************************************************************************* * Copyright (C) 2008, 2010 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * Copyright (C) 2016 by Teo Mrnjavac * * * * 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/newdialog.h" #include "gui/sizedialogwidget.h" #include "gui/sizedetailswidget.h" #include #include #include #include #include #include #include "util/guihelpers.h" #include #include #include #include #include #include /** Creates a NewDialog @param parent the parent widget @param device the Device on which a new Partition is to be created @param unallocatedPartition the unallocated space on the Device to create a Partition in @param r the permitted Roles for the new Partition */ NewDialog::NewDialog(QWidget* parent, Device& device, Partition& unallocatedPartition, PartitionRole::Roles r) : SizeDialogBase(parent, device, unallocatedPartition, unallocatedPartition.firstSector(), unallocatedPartition.lastSector()), m_PartitionRoles(r), m_IsValidPassword(true) { setWindowTitle(xi18nc("@title:window", "Create a new partition")); setupDialog(); setupConstraints(); setupConnections(); updateOkButtonStatus(); KConfigGroup kcg(KSharedConfig::openConfig(), "newDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } NewDialog::~NewDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "newDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void NewDialog::setupDialog() { QStringList fsNames; for (const auto &fs : FileSystemFactory::map()) { if (fs->supportCreate() != FileSystem::cmdSupportNone && - fs->type() != FileSystem::Extended && - fs->type() != FileSystem::Luks && - fs->type() != FileSystem::Luks2) + fs->type() != FileSystem::Type::Extended && + fs->type() != FileSystem::Type::Luks && + fs->type() != FileSystem::Type::Luks2) fsNames.append(fs->name()); } std::sort(fsNames.begin(), fsNames.end(), caseInsensitiveLessThan); for (const auto &fsName : qAsConst(fsNames)) dialogWidget().comboFileSystem().addItem(createFileSystemColor(FileSystem::typeForName(fsName), 8), fsName); QString selected = FileSystem::nameForType(GuiHelpers::defaultFileSystem()); const int idx = dialogWidget().comboFileSystem().findText(selected); dialogWidget().comboFileSystem().setCurrentIndex(idx != -1 ? idx : 0); dialogWidget().radioPrimary().setVisible(partitionRoles() & PartitionRole::Primary); dialogWidget().radioExtended().setVisible(partitionRoles() & PartitionRole::Extended); dialogWidget().radioLogical().setVisible(partitionRoles() & PartitionRole::Logical); if (partitionRoles() & PartitionRole::Primary) dialogWidget().radioPrimary().setChecked(true); else dialogWidget().radioLogical().setChecked(true); SizeDialogBase::setupDialog(); dialogWidget().checkBoxEncrypt().hide(); dialogWidget().editPassphrase().hide(); - if (device().type() == Device::LVM_Device) { + if (device().type() == Device::Type::LVM_Device) { dialogWidget().comboFileSystem().removeItem(dialogWidget().comboFileSystem().findText(QStringLiteral("lvm2 pv"))); } dialogWidget().editPassphrase().setMinimumPasswordLength(1); dialogWidget().editPassphrase().setMaximumPasswordLength(512); // cryptsetup does not support longer passwords // set a background warning color (taken from the current color scheme) KColorScheme colorScheme(QPalette::Active, KColorScheme::View); dialogWidget().editPassphrase().setBackgroundWarningColor(colorScheme.background(KColorScheme::NegativeBackground).color()); // don't move these above the call to parent's setupDialog, because only after that has // run there is a valid partition set in the part resizer widget and they will need that. onRoleChanged(false); onFilesystemChanged(dialogWidget().comboFileSystem().currentIndex()); } void NewDialog::setupConnections() { connect(&dialogWidget().radioPrimary(), &QRadioButton::toggled, this, &NewDialog::onRoleChanged); connect(&dialogWidget().radioExtended(), &QRadioButton::toggled, this, &NewDialog::onRoleChanged); connect(&dialogWidget().radioLogical(), &QRadioButton::toggled, this, &NewDialog::onRoleChanged); connect(&dialogWidget().checkBoxEncrypt(), &QCheckBox::toggled, this, &NewDialog::onRoleChanged); connect(&dialogWidget().comboFileSystem(), qOverload(&QComboBox::currentIndexChanged), this, &NewDialog::onFilesystemChanged); connect(&dialogWidget().label(), &QLineEdit::textChanged, this, &NewDialog::onLabelChanged); // listen to password status updates connect(&dialogWidget().editPassphrase(), &KNewPasswordWidget::passwordStatusChanged, this, &NewDialog::slotPasswordStatusChanged); SizeDialogBase::setupConnections(); } bool NewDialog::canMove() const { - return (device().type() == Device::LVM_Device) ? false : true; + return (device().type() == Device::Type::LVM_Device) ? false : true; } void NewDialog::accept() { if (partition().roles().has(PartitionRole::Extended)) { partition().deleteFileSystem(); - partition().setFileSystem(FileSystemFactory::create(FileSystem::Extended, + partition().setFileSystem(FileSystemFactory::create(FileSystem::Type::Extended, partition().firstSector(), partition().lastSector(), partition().sectorSize())); } else if (partition().roles().has(PartitionRole::Luks)) { FileSystem::Type innerFsType = partition().fileSystem().type(); partition().deleteFileSystem(); FS::luks* luksFs = dynamic_cast< FS::luks* >( - FileSystemFactory::create(FileSystem::Luks, + FileSystemFactory::create(FileSystem::Type::Luks, partition().firstSector(), partition().lastSector(), partition().sectorSize())); luksFs->createInnerFileSystem(innerFsType); luksFs->setPassphrase(dialogWidget().editPassphrase().password()); partition().setFileSystem(luksFs); partition().fileSystem().setLabel(dialogWidget().label().text()); } QDialog::accept(); } void NewDialog::onRoleChanged(bool) { PartitionRole::Roles r = PartitionRole::None; if (dialogWidget().radioPrimary().isChecked()) r = PartitionRole::Primary; else if (dialogWidget().radioExtended().isChecked()) r = PartitionRole::Extended; else if (dialogWidget().radioLogical().isChecked()) r = PartitionRole::Logical; bool doEncrypt = dialogWidget().checkBoxEncrypt().isVisible() && dialogWidget().checkBoxEncrypt().isChecked(); if (doEncrypt) r |= PartitionRole::Luks; dialogWidget().editPassphrase().setVisible(doEncrypt); // Make sure an extended partition gets correctly displayed: Set its file system to extended. // Also make sure to set a primary's or logical's file system once the user goes back from // extended to any of those. if (r == PartitionRole::Extended) - updateFileSystem(FileSystem::Extended); + updateFileSystem(FileSystem::Type::Extended); else updateFileSystem(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText())); dialogWidget().comboFileSystem().setEnabled(r != PartitionRole::Extended); partition().setRoles(PartitionRole(r)); setupConstraints(); dialogWidget().partResizerWidget().resizeLogicals(0, 0, true); dialogWidget().partResizerWidget().update(); updateHideAndShow(); } void NewDialog::updateFileSystem(FileSystem::Type t) { partition().deleteFileSystem(); partition().setFileSystem(FileSystemFactory::create(t, partition().firstSector(), partition().lastSector(), partition().sectorSize())); } void NewDialog::onFilesystemChanged(int idx) { updateFileSystem(FileSystem::typeForName(dialogWidget().comboFileSystem().itemText(idx))); setupConstraints(); updateOkButtonStatus(); const FileSystem* fs = FileSystemFactory::create(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText()), -1, -1, -1, -1, QString()); dialogWidget().m_EditLabel->setMaxLength(fs->maxLabelLength()); dialogWidget().m_EditLabel->setValidator(fs->labelValidator(dialogWidget().m_EditLabel)); updateSpinCapacity(partition().length()); dialogWidget().partResizerWidget().update(); updateHideAndShow(); } void NewDialog::onLabelChanged(const QString& newLabel) { partition().fileSystem().setLabel(newLabel); } void NewDialog::slotPasswordStatusChanged() { // You may want to extend this switch with more cases, // in order to warn the user about all the possible password issues. switch (dialogWidget().editPassphrase().passwordStatus()) { case KNewPasswordWidget::WeakPassword: case KNewPasswordWidget::StrongPassword: m_IsValidPassword = true; break; default: m_IsValidPassword = false; break; } updateOkButtonStatus(); } void NewDialog::updateHideAndShow() { // this is mostly copy'n'pasted from PartPropsDialog::updateHideAndShow() if (partition().roles().has(PartitionRole::Extended) || (partition().fileSystem().supportSetLabel() == FileSystem::cmdSupportNone && partition().fileSystem().supportCreateWithLabel() == FileSystem::cmdSupportNone) ) { dialogWidget().label().setReadOnly(true); dialogWidget().noSetLabel().setVisible(true); dialogWidget().noSetLabel().setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); QPalette palette = dialogWidget().noSetLabel().palette(); QColor f = palette.color(QPalette::Foreground); f.setAlpha(128); palette.setColor(QPalette::Foreground, f); dialogWidget().noSetLabel().setPalette(palette); dialogWidget().checkBoxEncrypt().hide(); dialogWidget().editPassphrase().hide(); } else { dialogWidget().label().setReadOnly(false); dialogWidget().noSetLabel().setVisible(false); } - if (FS::luks::canEncryptType(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText())) && !partition().roles().has(PartitionRole::Extended) ) + if (FileSystemFactory::map()[FileSystem::Type::Luks]->supportCreate() && FS::luks::canEncryptType(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText())) && !partition().roles().has(PartitionRole::Extended)) { dialogWidget().checkBoxEncrypt().show(); if (dialogWidget().checkBoxEncrypt().isChecked()) { dialogWidget().editPassphrase().show(); slotPasswordStatusChanged(); } } else { dialogWidget().checkBoxEncrypt().hide(); dialogWidget().editPassphrase().hide(); } } void NewDialog::updateOkButtonStatus() { okButton->setEnabled(isValidPassword() && isValidLVName()); } diff --git a/src/gui/partitionmanagerwidget.cpp b/src/gui/partitionmanagerwidget.cpp index 806fea2..4bdb11d 100644 --- a/src/gui/partitionmanagerwidget.cpp +++ b/src/gui/partitionmanagerwidget.cpp @@ -1,800 +1,800 @@ /************************************************************************* * Copyright (C) 2008-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/partitionmanagerwidget.h" #include "gui/partpropsdialog.h" #include "gui/resizedialog.h" #include "gui/newdialog.h" #include "gui/applyprogressdialog.h" #include "gui/insertdialog.h" #include "gui/editmountpointdialog.h" #include "util/guihelpers.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 #include #include #include #include #include class PartitionTreeWidgetItem : public QTreeWidgetItem { Q_DISABLE_COPY(PartitionTreeWidgetItem) public: PartitionTreeWidgetItem(const Partition* p) : QTreeWidgetItem(), m_Partition(p) {} const Partition* partition() const { return m_Partition; } private: const Partition* m_Partition; }; /** Creates a new PartitionManagerWidget instance. @param parent the parent widget */ PartitionManagerWidget::PartitionManagerWidget(QWidget* parent) : QWidget(parent), Ui::PartitionManagerWidgetBase(), m_OperationStack(nullptr), m_SelectedDevice(nullptr), m_ClipboardPartition(nullptr) { setupUi(this); treePartitions().header()->setStretchLastSection(false); treePartitions().header()->setContextMenuPolicy(Qt::CustomContextMenu); } PartitionManagerWidget::~PartitionManagerWidget() { saveConfig(); } void PartitionManagerWidget::init(OperationStack* ostack) { m_OperationStack = ostack; // TODO: shouldn't this also go to the main window class? FileSystemFactory::init(); loadConfig(); setupConnections(); } void PartitionManagerWidget::loadConfig() { QList colWidths = Config::treePartitionColumnWidths(); QList colPositions = Config::treePartitionColumnPositions(); QList colVisible = Config::treePartitionColumnVisible(); QHeaderView* header = treePartitions().header(); for (int i = 0; i < treePartitions().columnCount(); i++) { if (colPositions[0] != -1 && colPositions.size() > i) header->moveSection(header->visualIndex(i), colPositions[i]); if (colVisible[0] != -1 && colVisible.size() > i) treePartitions().setColumnHidden(i, colVisible[i] == 0); if (colWidths[0] != -1 && colWidths.size() > i) treePartitions().setColumnWidth(i, colWidths[i]); } } void PartitionManagerWidget::saveConfig() const { QList colWidths; QList colPositions; QList colVisible; for (int i = 0; i < treePartitions().columnCount(); i++) { colPositions.append(treePartitions().header()->visualIndex(i)); colVisible.append(treePartitions().isColumnHidden(i) ? 0 : 1); colWidths.append(treePartitions().columnWidth(i)); } Config::setTreePartitionColumnPositions(colPositions); Config::setTreePartitionColumnVisible(colVisible); Config::setTreePartitionColumnWidths(colWidths); Config::self()->save(); } void PartitionManagerWidget::setupConnections() { connect(treePartitions().header(), &QHeaderView::customContextMenuRequested, this, &PartitionManagerWidget::onHeaderContextMenu); } void PartitionManagerWidget::clear() { setSelectedDevice(nullptr); setClipboardPartition(nullptr); treePartitions().clear(); partTableWidget().clear(); } void PartitionManagerWidget::setSelectedPartition(const Partition* p) { if (p == nullptr) { treePartitions().setCurrentItem(nullptr); emit selectedPartitionChanged(nullptr); updatePartitions(); } else partTableWidget().setActivePartition(p); } Partition* PartitionManagerWidget::selectedPartition() { if (selectedDevice() == nullptr || selectedDevice()->partitionTable() == nullptr || partTableWidget().activeWidget() == nullptr) return nullptr; return partTableWidget().activeWidget()->partition(); } void PartitionManagerWidget::setSelectedDevice(const QString& deviceNode) { QReadLocker lockDevices(&operationStack().lock()); const auto previewDevices = operationStack().previewDevices(); for (const auto &d : previewDevices) { if (d->deviceNode() == deviceNode) { setSelectedDevice(d); return; } } setSelectedDevice(nullptr); } void PartitionManagerWidget::setSelectedDevice(Device* d) { m_SelectedDevice = d; setSelectedPartition(nullptr); } static QTreeWidgetItem* createTreeWidgetItem(const Partition& p) { QTreeWidgetItem* item = new PartitionTreeWidgetItem(&p); int i = 0; item->setText(i++, p.deviceNode()); - if (p.roles().has(PartitionRole::Luks) && (p.fileSystem().name() != p.fileSystem().nameForType(FileSystem::Luks) && p.fileSystem().name() != p.fileSystem().nameForType(FileSystem::Luks2))) + if (p.roles().has(PartitionRole::Luks) && (p.fileSystem().name() != p.fileSystem().nameForType(FileSystem::Type::Luks) && p.fileSystem().name() != p.fileSystem().nameForType(FileSystem::Type::Luks2))) item->setText(i, xi18nc("@item:intable Encrypted file systems, e.g. btrfs[Encrypted]", "%1 [Encrypted]", p.fileSystem().name())); else item->setText(i, p.fileSystem().name()); item->setIcon(i, createFileSystemColor(p.fileSystem().type(), 14)); i++; item->setText(i, p.mountPoint()); if (p.isMounted()) item->setIcon(i, QIcon::fromTheme(QStringLiteral("object-locked")).pixmap(IconSize(KIconLoader::Panel))); i++; item->setText(i++, p.fileSystem().label()); item->setText(i++, p.fileSystem().uuid()); item->setText(i++, p.label()); item->setText(i++, p.uuid()); item->setText(i++, Capacity::formatByteSize(p.capacity())); item->setText(i++, Capacity::formatByteSize(p.used())); item->setText(i++, Capacity::formatByteSize(p.available())); item->setText(i++, QLocale().toString(p.firstSector())); item->setText(i++, QLocale().toString(p.lastSector())); item->setText(i++, QLocale().toString(p.length())); item->setText(i++, PartitionTable::flagNames(p.activeFlags()).join(QStringLiteral(", "))); item->setSizeHint(0, QSize(0, 32)); return item; } void PartitionManagerWidget::updatePartitions() { if (selectedDevice() == nullptr) return; treePartitions().clear(); partTableWidget().clear(); partTableWidget().setPartitionTable(selectedDevice()->partitionTable()); QTreeWidgetItem* deviceItem = new QTreeWidgetItem(); QFont font; font.setBold(true); font.setWeight(75); deviceItem->setFont(0, font); deviceItem->setText(0, selectedDevice()->prettyName()); deviceItem->setIcon(0, QIcon::fromTheme(selectedDevice()->iconName()).pixmap(IconSize(KIconLoader::Desktop))); deviceItem->setSizeHint(0, QSize(0, 32)); treePartitions().addTopLevelItem(deviceItem); if (selectedDevice()->partitionTable() != nullptr) { const auto children = selectedDevice()->partitionTable()->children(); for (const auto * p : children) { QTreeWidgetItem* item = createTreeWidgetItem(*p); for (const auto &child : p->children()) { QTreeWidgetItem* childItem = createTreeWidgetItem(*child); item->addChild(childItem); } deviceItem->addChild(item); item->setExpanded(true); } } treePartitions().setFirstItemColumnSpanned(deviceItem, true); deviceItem->setExpanded(true); deviceItem->setFlags(Qt::ItemIsEnabled); partTableWidget().update(); } void PartitionManagerWidget::on_m_TreePartitions_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem*) { if (current) { const PartitionTreeWidgetItem* ptwItem = dynamic_cast(current); partTableWidget().setActivePartition(ptwItem ? ptwItem->partition() : nullptr); } else partTableWidget().setActiveWidget(nullptr); } void PartitionManagerWidget::on_m_TreePartitions_itemDoubleClicked(QTreeWidgetItem* item, int) { if (item == treePartitions().topLevelItem(0)) { if (selectedDevice() != nullptr) emit deviceDoubleClicked(selectedDevice()); } else { if (selectedPartition() != nullptr) emit partitionDoubleClicked(selectedPartition()); } } void PartitionManagerWidget::onHeaderContextMenu(const QPoint& p) { showColumnsContextMenu(p, treePartitions()); } void PartitionManagerWidget::on_m_PartTableWidget_itemSelectionChanged(PartWidget* item) { if (item == nullptr) { treePartitions().setCurrentItem(nullptr); emit selectedPartitionChanged(nullptr); return; } const Partition* p = item->partition(); Q_ASSERT(p); if (p) { QList findResult = treePartitions().findItems(p->deviceNode(), Qt::MatchFixedString | Qt::MatchRecursive, 0); for (const auto &treeWidgetItem : findResult) { const PartitionTreeWidgetItem* ptwItem = dynamic_cast(treeWidgetItem); if (ptwItem && ptwItem->partition() == p) { treePartitions().setCurrentItem(treeWidgetItem); break; } } } emit selectedPartitionChanged(p); } void PartitionManagerWidget::on_m_PartTableWidget_customContextMenuRequested(const QPoint& pos) { emit contextMenuRequested(partTableWidget().mapToGlobal(pos)); } void PartitionManagerWidget::on_m_PartTableWidget_itemDoubleClicked() { if (selectedPartition()) emit partitionDoubleClicked(selectedPartition()); } void PartitionManagerWidget::on_m_TreePartitions_customContextMenuRequested(const QPoint& pos) { emit contextMenuRequested(treePartitions().viewport()->mapToGlobal(pos)); } void PartitionManagerWidget::onPropertiesPartition() { if (selectedPartition()) { Partition& p = *selectedPartition(); Q_ASSERT(selectedDevice()); QPointer dlg = new PartPropsDialog(this, *selectedDevice(), p); if (dlg->exec() == QDialog::Accepted) { if (dlg->newFileSystemType() != p.fileSystem().type() || dlg->forceRecreate()) operationStack().push(new CreateFileSystemOperation(*selectedDevice(), p, dlg->newFileSystemType())); if (dlg->newLabel() != p.fileSystem().label()) operationStack().push(new SetFileSystemLabelOperation(p, dlg->newLabel())); if (dlg->newFlags() != p.activeFlags()) operationStack().push(new SetPartFlagsOperation(*selectedDevice(), p, dlg->newFlags())); } delete dlg; } } void PartitionManagerWidget::onMountPartition() { Partition* p = selectedPartition(); Q_ASSERT(p); if (p == nullptr) { qWarning() << "no partition selected"; return; } Report report(nullptr); if (p->canMount()) { if (!p->mount(report)) KMessageBox::detailedSorry(this, xi18nc("@info", "The file system on partition %1 could not be mounted.", p->deviceNode()), QStringLiteral("
%1
").arg(report.toText()), xi18nc("@title:window", "Could Not Mount File System.")); } else if (p->canUnmount()) { if (!p->unmount(report)) KMessageBox::detailedSorry(this, xi18nc("@info", "The file system on partition %1 could not be unmounted.", p->deviceNode()), QStringLiteral("
%1
").arg(report.toText()), xi18nc("@title:window", "Could Not Unmount File System.")); } if (p->roles().has(PartitionRole::Logical)) { Partition* parent = dynamic_cast(p->parent()); Q_ASSERT(parent); if (parent != nullptr) parent->checkChildrenMounted(); else qWarning() << "parent is null"; } updatePartitions(); } void PartitionManagerWidget::onDecryptPartition() { Partition* p = selectedPartition(); Q_ASSERT(p); if (p == nullptr) { qWarning() << "no partition selected"; return; } if (!p->roles().has(PartitionRole::Luks)) return; const FileSystem& fsRef = p->fileSystem(); FS::luks* luksFs = const_cast(dynamic_cast(&fsRef)); if (!luksFs) return; if (luksFs->canCryptOpen(p->partitionPath())) { if (!luksFs->cryptOpen(this, p->partitionPath())) KMessageBox::detailedSorry(this, xi18nc("@info", "The encrypted file system on partition " "%1 could not be " "unlocked.", p->deviceNode()), QString(), xi18nc("@title:window", "Could Not Unlock Encrypted File System.")); } else if (luksFs->canCryptClose(p->partitionPath())) { if (!luksFs->cryptClose(p->partitionPath())) KMessageBox::detailedSorry(this, xi18nc("@info", "The encrypted file system on partition " "%1 could not be " "locked.", p->deviceNode()), QString(), xi18nc("@title:window", "Could Not Lock Encrypted File System.")); } updatePartitions(); } void PartitionManagerWidget::onEditMountPoint() { Partition* p = selectedPartition(); Q_ASSERT(p); if (p == nullptr) return; QPointer dlg = new EditMountPointDialog(this, *p); if (dlg->exec() == QDialog::Accepted) updatePartitions(); delete dlg; } static bool checkTooManyPartitions(QWidget* parent, const Device& d, const Partition& p) { Q_ASSERT(d.partitionTable()); if (p.roles().has(PartitionRole::Unallocated) && d.partitionTable()->numPrimaries() >= d.partitionTable()->maxPrimaries() && !p.roles().has(PartitionRole::Logical)) { KMessageBox::sorry(parent, xi18ncp("@info", "There is already one primary partition on this device. This is the maximum number its partition table type can handle." "You cannot create, paste or restore a primary partition on it before you delete an existing one.", "There are already %1 primary partitions on this device. This is the maximum number its partition table type can handle." "You cannot create, paste or restore a primary partition on it before you delete an existing one.", d.partitionTable()->numPrimaries()), xi18nc("@title:window", "Too Many Primary Partitions.")); return true; } return false; } void PartitionManagerWidget::onNewPartition() { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } Q_ASSERT(selectedDevice()->partitionTable()); if (selectedDevice()->partitionTable() == nullptr) { qWarning() << "partition table on selected device is null"; return; } if (checkTooManyPartitions(this, *selectedDevice(), *selectedPartition())) return; Partition* newPartition = NewOperation::createNew(*selectedPartition(), static_cast(Config::defaultFileSystem())); QPointer dlg = new NewDialog(this, *selectedDevice(), *newPartition, selectedDevice()->partitionTable()->childRoles(*selectedPartition())); if (dlg->exec() == QDialog::Accepted) operationStack().push(new NewOperation(*selectedDevice(), newPartition)); else delete newPartition; delete dlg; } void PartitionManagerWidget::onDeletePartition(bool shred) { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } if (selectedPartition()->roles().has(PartitionRole::Logical)) { Q_ASSERT(selectedPartition()->parent()); if (selectedPartition()->parent() == nullptr) { qWarning() << "parent of selected partition is null."; return; } if (selectedPartition()->number() > 0 && selectedPartition()->parent()->highestMountedChild() > selectedPartition()->number()) { KMessageBox::sorry(this, xi18nc("@info", "The partition %1 cannot currently be deleted because one or more partitions with higher logical numbers are still mounted." "Please unmount all partitions with higher logical numbers than %2 first.", selectedPartition()->deviceNode(), selectedPartition()->number()), xi18nc("@title:window", "Cannot Delete Partition.")); return; } } if (clipboardPartition() == selectedPartition()) { if (KMessageBox::warningContinueCancel(this, xi18nc("@info", "Do you really want to delete the partition that is currently in the clipboard? " "It will no longer be available for pasting after it has been deleted."), xi18nc("@title:window", "Really Delete Partition in the Clipboard?"), KGuiItem(xi18nc("@action:button", "Delete It"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyDeleteClipboardPartition")) == KMessageBox::Cancel) return; setClipboardPartition(nullptr); } if (shred && Config::shredSource() == Config::EnumShredSource::random) - operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::RandomShred)); + operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::ShredAction::RandomShred)); else if (shred && Config::shredSource() == Config::EnumShredSource::zeros) - operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::ZeroShred)); + operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::ShredAction::ZeroShred)); else - operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::NoShred)); + operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::ShredAction::NoShred)); } void PartitionManagerWidget::onShredPartition() { onDeletePartition(true); } void PartitionManagerWidget::onResizePartition() { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } Q_ASSERT(selectedDevice()->partitionTable()); if (selectedDevice()->partitionTable() == nullptr) { qWarning() << "partition table on selected device is null"; return; } // we cannot work with selectedPartition() here because opening and closing the dialog will // clear the selection, so we'll lose the partition after the dialog's been exec'd Partition& p = *selectedPartition(); qint64 freeBefore = selectedDevice()->partitionTable()->freeSectorsBefore(p); qint64 freeAfter = selectedDevice()->partitionTable()->freeSectorsAfter(p); - if (selectedDevice()->type() == Device::LVM_Device) { + if (selectedDevice()->type() == Device::Type::LVM_Device) { freeBefore = 0; freeAfter = selectedDevice()->partitionTable()->freeSectors(); } QPointer dlg = new ResizeDialog(this, *selectedDevice(), p, p.firstSector() - freeBefore, p.lastSector() + freeAfter); if (dlg->exec() == QDialog::Accepted) { if (dlg->resizedFirstSector() == p.firstSector() && dlg->resizedLastSector() == p.lastSector()) - Log(Log::information) << xi18nc("@info:status", "Partition %1 has the same position and size after resize/move. Ignoring operation.", p.deviceNode()); + Log(Log::Level::information) << xi18nc("@info:status", "Partition %1 has the same position and size after resize/move. Ignoring operation.", p.deviceNode()); else operationStack().push(new ResizeOperation(*selectedDevice(), p, dlg->resizedFirstSector(), dlg->resizedLastSector())); } if (p.roles().has(PartitionRole::Extended)) { // Even if the user dismissed the resize dialog we must update the partitions // if it's an extended partition: // The dialog has to remove and create unallocated children if the user resizes // an extended partition. We can't know if that has happened, so to avoid // any problems (like, the user resized an extended and then canceled, which would // lead to the unallocated children having the wrong size) do this now. updatePartitions(); } delete dlg; } void PartitionManagerWidget::onCopyPartition() { Q_ASSERT(selectedPartition()); if (selectedPartition() == nullptr) { qWarning() << "selected partition: " << selectedPartition(); return; } setClipboardPartition(selectedPartition()); Log() << xi18nc("@info:status", "Partition %1 has been copied to the clipboard.", selectedPartition()->deviceNode()); } void PartitionManagerWidget::onPastePartition() { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } if (clipboardPartition() == nullptr) { qWarning() << "no partition in the clipboard."; return; } if (checkTooManyPartitions(this, *selectedDevice(), *selectedPartition())) return; Device* dSource = operationStack().findDeviceForPartition(clipboardPartition()); Q_ASSERT(dSource); if (dSource == nullptr) { qWarning() << "source partition is null."; return; } Partition* copiedPartition = CopyOperation::createCopy(*selectedPartition(), *clipboardPartition()); if (showInsertDialog(*copiedPartition, clipboardPartition()->length())) operationStack().push(new CopyOperation(*selectedDevice(), copiedPartition, *dSource, clipboardPartition())); else delete copiedPartition; } bool PartitionManagerWidget::showInsertDialog(Partition& insertedPartition, qint64 sourceLength) { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return false; } const bool overwrite = !selectedPartition()->roles().has(PartitionRole::Unallocated); // Make sure the inserted partition has the right parent and logical or primary set. Only then // can PartitionTable::alignPartition() work correctly. selectedPartition()->parent()->reparent(insertedPartition); if (!overwrite) { QPointer dlg = new InsertDialog(this, *selectedDevice(), insertedPartition, *selectedPartition()); int result = dlg->exec(); delete dlg; if (result != QDialog::Accepted) return false; } else if (KMessageBox::warningContinueCancel(this, xi18nc("@info", "You are about to lose all data on partition " "%1." "Overwriting one partition with another (or with an image file) will " "destroy all data on this target partition." "If you continue now and apply the resulting operation in the main " "window, all data currently stored on %1 will " "unrecoverably be overwritten.", selectedPartition()->deviceNode()), xi18nc("@title:window", "Really Overwrite Existing Partition?"), KGuiItem(xi18nc("@action:button", "Overwrite Partition"), QStringLiteral("arrow-right")), KStandardGuiItem::cancel(), QStringLiteral("reallyOverwriteExistingPartition")) == KMessageBox::Cancel) return false; if (insertedPartition.length() < sourceLength) { if (overwrite) KMessageBox::error(this, xi18nc("@info", "The selected partition is not large enough to hold the source partition or the backup file." "Pick another target or resize this partition so it is as large as the source."), xi18nc("@title:window", "Target Not Large Enough")); else KMessageBox::sorry(this, xi18nc("@info", "It is not possible to create the target partition large enough to hold the source." "This may happen if not all partitions on a device are correctly aligned " "or when copying a primary partition into an extended partition."), xi18nc("@title:window", "Cannot Create Target Partition.")); return false; } return true; } void PartitionManagerWidget::onCheckPartition() { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } operationStack().push(new CheckOperation(*selectedDevice(), *selectedPartition())); } void PartitionManagerWidget::onBackupPartition() { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } QString fileName = QFileDialog::getSaveFileName(this); if (fileName.isEmpty()) return; operationStack().push(new BackupOperation(*selectedDevice(), *selectedPartition(), fileName)); } void PartitionManagerWidget::onRestorePartition() { Q_ASSERT(selectedDevice()); Q_ASSERT(selectedPartition()); if (selectedDevice() == nullptr || selectedPartition() == nullptr) { qWarning() << "selected device: " << selectedDevice() << ", selected partition: " << selectedPartition(); return; } if (checkTooManyPartitions(this, *selectedDevice(), *selectedPartition())) return; QString fileName = QFileDialog::getOpenFileName(this); // QString fileName = "/tmp/backuptest.img"; if (!fileName.isEmpty() && QFile::exists(fileName)) { Partition* restorePartition = RestoreOperation::createRestorePartition(*selectedDevice(), *selectedPartition()->parent(), selectedPartition()->firstSector(), fileName); if (restorePartition->length() > selectedPartition()->length()) { KMessageBox::error(this, xi18nc("@info", "The file system in the image file %1 is too large to be restored to the selected partition.", fileName), xi18nc("@title:window", "Not Enough Space to Restore File System.")); delete restorePartition; return; } if (showInsertDialog(*restorePartition, restorePartition->length())) operationStack().push(new RestoreOperation(*selectedDevice(), restorePartition, fileName)); else delete restorePartition; } } diff --git a/src/gui/partpropsdialog.cpp b/src/gui/partpropsdialog.cpp index 8221e4a..e586fe1 100644 --- a/src/gui/partpropsdialog.cpp +++ b/src/gui/partpropsdialog.cpp @@ -1,391 +1,391 @@ /************************************************************************* * Copyright (C) 2008, 2009 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/partpropsdialog.h" #include "gui/partpropswidget.h" #include #include #include #include #include #include "util/guihelpers.h" #include #include #include #include #include #include #include #include #include #include /** Creates a new PartPropsDialog @param parent pointer to the parent widget @param d the Device the Partition is on @param p the Partition to show properties for */ PartPropsDialog::PartPropsDialog(QWidget* parent, Device& d, Partition& p) : QDialog(parent), m_Device(d), m_Partition(p), m_WarnFileSystemChange(false), m_DialogWidget(new PartPropsWidget(this)), - m_ReadOnly(partition().isMounted() || partition().state() == Partition::StateCopy || partition().state() == Partition::StateRestore || d.partitionTable()->isReadOnly()), + m_ReadOnly(partition().isMounted() || partition().state() == Partition::State::Copy || partition().state() == Partition::State::Restore || d.partitionTable()->isReadOnly()), m_ForceRecreate(false) { mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&dialogWidget()); setWindowTitle(xi18nc("@title:window", "Partition properties: %1", partition().deviceNode())); setupDialog(); setupConnections(); KConfigGroup kcg(KSharedConfig::openConfig(), "partPropsDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a PartPropsDialog */ PartPropsDialog::~PartPropsDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "partPropsDialog"); kcg.writeEntry("Geometry", saveGeometry()); } /** @return the new label */ QString PartPropsDialog::newLabel() const { return dialogWidget().label().text(); } /** @return the new Partition flags */ PartitionTable::Flags PartPropsDialog::newFlags() const { PartitionTable::Flags flags; for (int i = 0; i < dialogWidget().listFlags().count(); i++) if (dialogWidget().listFlags().item(i)->checkState() == Qt::Checked) flags |= static_cast(dialogWidget().listFlags().item(i)->data(Qt::UserRole).toInt()); return flags; } /** @return the new FileSystem type */ FileSystem::Type PartPropsDialog::newFileSystemType() const { return FileSystem::typeForName(dialogWidget().fileSystem().currentText()); } void PartPropsDialog::setupDialog() { dialogButtonBox = new QDialogButtonBox; okButton = dialogButtonBox->addButton(QDialogButtonBox::Ok); cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); mainLayout->addWidget(dialogButtonBox); okButton->setEnabled(false); cancelButton->setFocus(); cancelButton->setDefault(true); connect(dialogButtonBox, &QDialogButtonBox::accepted, this, &PartPropsDialog::accept); connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &PartPropsDialog::reject); dialogWidget().partWidget().init(&partition()); const QString mp = partition().mountPoint().isEmpty() ? xi18nc("@item mountpoint", "(none found)") : partition().mountPoint(); dialogWidget().mountPoint().setText(mp); dialogWidget().role().setText(partition().roles().toString()); QString statusText = xi18nc("@label partition state", "idle"); if (partition().isMounted()) { if (partition().roles().has(PartitionRole::Extended)) statusText = xi18nc("@label partition state", "At least one logical partition is mounted."); else if (!partition().mountPoint().isEmpty()) statusText = xi18nc("@label partition state", "mounted on %1", mp); else statusText = xi18nc("@label partition state", "mounted"); } dialogWidget().status().setText(statusText); dialogWidget().uuid().setText(partition().fileSystem().uuid().isEmpty() ? xi18nc("@item uuid", "(none)") : partition().fileSystem().uuid()); if(device().partitionTable()->type() == PartitionTable::gpt){ QString PartitionLabel = partition().label().isEmpty() ? xi18nc("@item uuid", "(none)") : partition().label(); QString PartitionUUID = partition().uuid().isEmpty() ? xi18nc("@item uuid", "(none)") : partition().uuid(); dialogWidget().partitionLabel().setText(PartitionLabel); dialogWidget().partitionUuid().setText(PartitionUUID); } else{ dialogWidget().partitionLabel().hide(); dialogWidget().partitionTextLabel().hide(); dialogWidget().partitionUuid().hide(); dialogWidget().partitionTextUuid().hide(); } setupFileSystemComboBox(); // don't do this before the file system combo box has been set up! dialogWidget().label().setText(newLabel().isEmpty() ? partition().fileSystem().label() : newLabel()); dialogWidget().capacity().setText(Capacity::formatByteSize(partition().capacity())); - if (Capacity(partition(), Capacity::Available).isValid()) { + if (Capacity(partition(), Capacity::Type::Available).isValid()) { const qint64 availPercent = (partition().fileSystem().length() - partition().fileSystem().sectorsUsed()) * 100 / partition().fileSystem().length(); const QString availString = QStringLiteral("%1% - %2") .arg(availPercent) .arg(Capacity::formatByteSize(partition().available())); const QString usedString = QStringLiteral("%1% - %2") .arg(100 - availPercent) .arg(Capacity::formatByteSize(partition().used())); dialogWidget().available().setText(availString); dialogWidget().used().setText(usedString); } else { dialogWidget().available().setText(Capacity::invalidString()); dialogWidget().used().setText(Capacity::invalidString()); } dialogWidget().firstSector().setText(QLocale().toString(partition().firstSector())); dialogWidget().lastSector().setText(QLocale().toString(partition().lastSector())); dialogWidget().numSectors().setText(QLocale().toString(partition().length())); setupFlagsList(); updateHideAndShow(); setMinimumSize(dialogWidget().size()); resize(dialogWidget().size()); } void PartPropsDialog::setupFlagsList() { int f = 1; QString s; while (!(s = PartitionTable::flagName(static_cast(f))).isEmpty()) { if (partition().availableFlags() & f) { QListWidgetItem* item = new QListWidgetItem(s); dialogWidget().listFlags().addItem(item); item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); item->setData(Qt::UserRole, f); item->setCheckState((partition().activeFlags() & f) ? Qt::Checked : Qt::Unchecked); } f <<= 1; } } void PartPropsDialog::updateHideAndShow() { // create a temporary fs for some checks const FileSystem* fs = FileSystemFactory::create(newFileSystemType(), -1, -1, -1, -1, QString()); if (fs == nullptr || fs->supportSetLabel() == FileSystem::cmdSupportNone) { dialogWidget().label().setReadOnly(true); dialogWidget().noSetLabel().setVisible(true); dialogWidget().noSetLabel().setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); QPalette palette = dialogWidget().noSetLabel().palette(); QColor f = palette.color(QPalette::Foreground); f.setAlpha(128); palette.setColor(QPalette::Foreground, f); dialogWidget().noSetLabel().setPalette(palette); } else { dialogWidget().label().setReadOnly(isReadOnly() && !partition().fileSystem().supportSetLabelOnline()); dialogWidget().noSetLabel().setVisible(false); } // when do we show the uuid? const bool showUuid = - partition().state() != Partition::StateNew && // not for new partitions + partition().state() != Partition::State::New && // not for new partitions !(fs == nullptr || fs->supportGetUUID() == FileSystem::cmdSupportNone); // not if the FS doesn't support it dialogWidget().showUuid(showUuid); delete fs; // when do we show available and used capacity? const bool showAvailableAndUsed = - partition().state() != Partition::StateNew && // not for new partitions + partition().state() != Partition::State::New && // not for new partitions !partition().roles().has(PartitionRole::Extended) && // neither for extended !partition().roles().has(PartitionRole::Unallocated) && // or for unallocated - newFileSystemType() != FileSystem::Unformatted; // and not for unformatted file systems + newFileSystemType() != FileSystem::Type::Unformatted; // and not for unformatted file systems dialogWidget().showAvailable(showAvailableAndUsed); dialogWidget().showUsed(showAvailableAndUsed); // when do we show the file system combo box? const bool showFileSystem = !partition().roles().has(PartitionRole::Extended) && // not for extended, they have no file system !partition().roles().has(PartitionRole::Unallocated) && // and not for unallocated: no choice there // do now show file system comboBox for open luks volumes. - !(partition().roles().has(PartitionRole::Luks) && partition().fileSystem().type() != FileSystem::Luks); + !(partition().roles().has(PartitionRole::Luks) && partition().fileSystem().type() != FileSystem::Type::Luks); dialogWidget().showFileSystem(showFileSystem); // when do we show the recreate file system check box? const bool showCheckRecreate = showFileSystem && // only if we also show the file system partition().fileSystem().supportCreate() != FileSystem::cmdSupportNone && // and support creating this file system - partition().fileSystem().type() != FileSystem::Unknown && // and not for unknown file systems - partition().state() != Partition::StateNew && // or new partitions + partition().fileSystem().type() != FileSystem::Type::Unknown && // and not for unknown file systems + partition().state() != Partition::State::New && // or new partitions !partition().roles().has(PartitionRole::Luks); // or encrypted filesystems dialogWidget().showCheckRecreate(showCheckRecreate); // when do we show the list of partition flags? const bool showListFlags = - partition().state() != Partition::StateNew && // not for new partitions + partition().state() != Partition::State::New && // not for new partitions !partition().roles().has(PartitionRole::Unallocated); // and not for unallocated space dialogWidget().showListFlags(showListFlags); dialogWidget().checkRecreate().setEnabled(!isReadOnly()); dialogWidget().listFlags().setEnabled(!isReadOnly()); dialogWidget().fileSystem().setEnabled(!isReadOnly() && !forceRecreate()); } void PartPropsDialog::setupConnections() { connect(&dialogWidget().label(), &QLineEdit::textEdited, [this] (const QString &) {setDirty();}); connect(&dialogWidget().fileSystem(), qOverload(&QComboBox::currentIndexChanged), this, &PartPropsDialog::onFilesystemChanged); connect(&dialogWidget().checkRecreate(), &QCheckBox::stateChanged, this, &PartPropsDialog::onRecreate); // We want to enable the OK-button whenever the user checks or unchecks a flag in the flag list. // But it seems Qt doesn't offer a foolproof way to detect if this has happened: The currentRow/ItemChanged // signal only means the _current_ item has changed, but not necessarily that it was checked/unchecked. And // itemClicked alone isn't enough either. We choose to rather enable the OK-button too often than too // seldom. connect(&dialogWidget().listFlags(), &QListWidget::itemClicked, this, &PartPropsDialog::setDirty); connect(&dialogWidget().listFlags(), &QListWidget::currentRowChanged, [this] (int) {setDirty();}); } void PartPropsDialog::setDirty(void*) { okButton->setEnabled(true); okButton->setDefault(true); } void PartPropsDialog::setupFileSystemComboBox() { dialogWidget().fileSystem().clear(); QString selected; QStringList fsNames; for(const auto &fs : FileSystemFactory::map()) { // If the partition isn't encrypted, skip the luks FS - if (fs->type() == FileSystem::Luks && partition().fileSystem().type() != FileSystem::Luks) + if (fs->type() == FileSystem::Type::Luks && partition().fileSystem().type() != FileSystem::Type::Luks) continue; if (partition().fileSystem().type() == fs->type() || (fs->supportCreate() != FileSystem::cmdSupportNone && partition().capacity() >= fs->minCapacity() && partition().capacity() <= fs->maxCapacity())) { QString name = fs->name(); if (partition().fileSystem().type() == fs->type()) selected = name; // If the partition isn't extended, skip the extended FS - if (fs->type() == FileSystem::Extended && !partition().roles().has(PartitionRole::Extended)) + if (fs->type() == FileSystem::Type::Extended && !partition().roles().has(PartitionRole::Extended)) continue; // The user cannot change the filesystem back to "unformatted" once a filesystem has been created. - if (fs->type() == FileSystem::Unformatted) { + if (fs->type() == FileSystem::Type::Unformatted) { // .. but if the file system is unknown to us, show the unformatted option as the currently selected one - if (partition().fileSystem().type() == FileSystem::Unknown) { - name = FileSystem::nameForType(FileSystem::Unformatted); + if (partition().fileSystem().type() == FileSystem::Type::Unknown) { + name = FileSystem::nameForType(FileSystem::Type::Unformatted); selected = name; - } else if (partition().fileSystem().type() != FileSystem::Unformatted && partition().state() != Partition::StateNew) + } else if (partition().fileSystem().type() != FileSystem::Type::Unformatted && partition().state() != Partition::State::New) continue; } fsNames.append(name); } } std::sort(fsNames.begin(), fsNames.end(), caseInsensitiveLessThan); for (const auto &fsName : qAsConst(fsNames)) dialogWidget().fileSystem().addItem(createFileSystemColor(FileSystem::typeForName(fsName), 8), fsName); dialogWidget().fileSystem().setCurrentIndex(dialogWidget().fileSystem().findText(selected)); const FileSystem* fs = FileSystemFactory::create(FileSystem::typeForName(dialogWidget().fileSystem().currentText()), -1, -1, -1, -1, QString()); dialogWidget().m_EditLabel->setMaxLength(fs->maxLabelLength()); dialogWidget().m_EditLabel->setValidator(fs->labelValidator(dialogWidget().m_EditLabel)); } void PartPropsDialog::updatePartitionFileSystem() { FileSystem* fs = FileSystemFactory::create(newFileSystemType(), partition().firstSector(), partition().lastSector(), partition().sectorSize()); partition().deleteFileSystem(); partition().setFileSystem(fs); dialogWidget().partWidget().update(); } void PartPropsDialog::onFilesystemChanged(int) { - if (partition().state() == Partition::StateNew || warnFileSystemChange() || KMessageBox::warningContinueCancel(this, + if (partition().state() == Partition::State::New || warnFileSystemChange() || KMessageBox::warningContinueCancel(this, xi18nc("@info", "You are about to lose all data on partition %1." "Changing the file system on a partition already on disk will erase all its contents. If you continue now and apply the resulting operation in the main window, all data on %1 will unrecoverably be lost.", partition().deviceNode()), xi18nc("@title:window", "Really Recreate %1 with File System %2?", partition().deviceNode(), dialogWidget().fileSystem().currentText()), KGuiItem(xi18nc("@action:button", "Change the File System"), QStringLiteral("arrow-right")), KGuiItem(xi18nc("@action:button", "Do Not Change the File System"), QStringLiteral("dialog-cancel")), QStringLiteral("reallyChangeFileSystem")) == KMessageBox::Continue) { setDirty(); updateHideAndShow(); setWarnFileSystemChange(); updatePartitionFileSystem(); const FileSystem* fs = FileSystemFactory::create(FileSystem::typeForName(dialogWidget().fileSystem().currentText()), -1, -1, -1, -1, QString()); dialogWidget().m_EditLabel->setMaxLength(fs->maxLabelLength()); dialogWidget().m_EditLabel->setValidator(fs->labelValidator(dialogWidget().m_EditLabel)); } else { dialogWidget().fileSystem().disconnect(this); setupFileSystemComboBox(); connect(&dialogWidget().fileSystem(), qOverload(&QComboBox::currentIndexChanged), this, &PartPropsDialog::onFilesystemChanged); } } void PartPropsDialog::onRecreate(int state) { if (state == Qt::Checked && (warnFileSystemChange() || KMessageBox::warningContinueCancel(this, xi18nc("@info", "You are about to lose all data on partition %1." "Recreating a file system will erase all its contents. If you continue now and apply the resulting operation in the main window, all data on %1 will unrecoverably be lost.", partition().deviceNode()), xi18nc("@title:window", "Really Recreate File System on %1?", partition().deviceNode()), KGuiItem(xi18nc("@action:button", "Recreate the File System"), QStringLiteral("arrow-right")), KGuiItem(xi18nc("@action:button", "Do Not Recreate the File System"), QStringLiteral("dialog-cancel")), QStringLiteral("reallyRecreateFileSystem")) == KMessageBox::Continue)) { setDirty(); setWarnFileSystemChange(); setForceRecreate(true); dialogWidget().fileSystem().setCurrentIndex(dialogWidget().fileSystem().findText(partition().fileSystem().name())); dialogWidget().fileSystem().setEnabled(false); updateHideAndShow(); updatePartitionFileSystem(); } else { setForceRecreate(false); dialogWidget().checkRecreate().setCheckState(Qt::Unchecked); dialogWidget().fileSystem().setEnabled(true); updateHideAndShow(); } } diff --git a/src/gui/resizedialog.cpp b/src/gui/resizedialog.cpp index 886e614..6e45b6e 100644 --- a/src/gui/resizedialog.cpp +++ b/src/gui/resizedialog.cpp @@ -1,166 +1,166 @@ /************************************************************************* * Copyright (C) 2008, 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/resizedialog.h" #include "gui/sizedialogwidget.h" #include "gui/sizedetailswidget.h" #include #include #include #include #include #include #include #include #include #include /** Creates a new ResizeDialog @param parent pointer to the parent widget @param d the Device the Partition to resize is on @param p the Partition to resize @param minFirst the first free sector before the Partition to resize @param maxLast the last free sector free after the Partition to resize */ ResizeDialog::ResizeDialog(QWidget* parent, Device& d, Partition& p, qint64 minFirst, qint64 maxLast) : SizeDialogBase(parent, d, p, minFirst, maxLast), m_OriginalFirstSector(p.firstSector()), m_OriginalLastSector(p.lastSector()), m_ResizedFirstSector(p.firstSector()), m_ResizedLastSector(p.lastSector()) { setWindowTitle(xi18nc("@title:window", "Resize/move partition: %1", partition().deviceNode())); dialogWidget().hideRole(); dialogWidget().hideFileSystem(); dialogWidget().hideLabel(); dialogWidget().textLVName().hide(); dialogWidget().lvName().hide(); setupDialog(); setupConstraints(); setupConnections(); KConfigGroup kcg(KSharedConfig::openConfig(), "resizeDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } /** Destroys a ResizeDialog */ ResizeDialog::~ResizeDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "resizeDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void ResizeDialog::rollback() { partition().setFirstSector(originalFirstSector()); partition().fileSystem().setFirstSector(originalFirstSector()); partition().setLastSector(originalLastSector()); partition().fileSystem().setLastSector(originalLastSector()); if (partition().roles().has(PartitionRole::Extended)) { device().partitionTable()->removeUnallocated(&partition()); device().partitionTable()->insertUnallocated(device(), &partition(), partition().firstSector()); } } void ResizeDialog::accept() { if (partition().roles().has(PartitionRole::Luks)) { FS::luks2* luksFs = dynamic_cast(&partition().fileSystem()); if (luksFs) { - if (luksFs->keyLocation() == FS::luks::keyring) { + if (luksFs->keyLocation() == FS::luks::KeyLocation::keyring) { bool validPassphrase = false; QString errorMessage; QString passphrase; while(!validPassphrase) { KPasswordDialog dlg( this ); dlg.setPrompt(i18nc("%2 is either empty or says Invalid passphrase.", "%2Enter passphrase for %1:", partition().deviceNode(), errorMessage)); if( !dlg.exec() ) { reject(); return; } passphrase = dlg.password(); validPassphrase = luksFs->testPassphrase(partition().deviceNode(), passphrase); if(!validPassphrase) errorMessage = i18nc("Part of %2Enter passphrase for %1:", "Invalid passphrase. "); } luksFs->setPassphrase(passphrase); } } } setResizedFirstSector(partition().firstSector()); setResizedLastSector(partition().lastSector()); rollback(); QDialog::accept(); } void ResizeDialog::reject() { rollback(); QDialog::reject(); } void ResizeDialog::setupDialog() { SizeDialogBase::setupDialog(); - if (device().type() == Device::LVM_Device) { + if (device().type() == Device::Type::LVM_Device) { dialogWidget().hideBeforeAndAfter(); detailsWidget().checkAlign().setChecked(false); detailsWidget().checkAlign().setEnabled(false); detailsButton->hide(); } okButton->setEnabled(false); } void ResizeDialog::setDirty() { okButton->setEnabled(isModified()); } /** @return true if the user modified anything */ bool ResizeDialog::isModified() const { return partition().firstSector() != originalFirstSector() || partition().lastSector() != originalLastSector(); } bool ResizeDialog::canGrow() const { return ResizeOperation::canGrow(&partition()); } bool ResizeDialog::canShrink() const { return ResizeOperation::canShrink(&partition()); } bool ResizeDialog::canMove() const { - return (device().type() == Device::LVM_Device) ? false : ResizeOperation::canMove(&partition()); + return (device().type() == Device::Type::LVM_Device) ? false : ResizeOperation::canMove(&partition()); } diff --git a/src/gui/resizevolumegroupdialog.cpp b/src/gui/resizevolumegroupdialog.cpp index 7326c13..9acfc28 100644 --- a/src/gui/resizevolumegroupdialog.cpp +++ b/src/gui/resizevolumegroupdialog.cpp @@ -1,88 +1,131 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * 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/resizevolumegroupdialog.h" #include "gui/volumegroupwidget.h" #include #include #include #include +#include + #include #include #include #include #include /** Creates a new ResizeVolumeGroupDialog @param parent pointer to the parent widget @param d the Device to show properties for */ -ResizeVolumeGroupDialog::ResizeVolumeGroupDialog(QWidget* parent, VolumeManagerDevice* d, QVector& partList) +ResizeVolumeGroupDialog::ResizeVolumeGroupDialog(QWidget* parent, VolumeManagerDevice* d, QVector& partList, QList devices, QList pendingOps) : VolumeGroupDialog(parent, d->name(), partList) + , m_Devices(devices) , m_Device(d) + , m_PendingOps(pendingOps) { setWindowTitle(xi18nc("@title:window", "Resize Volume Group")); setupDialog(); setupConstraints(); KConfigGroup kcg(KSharedConfig::openConfig(), "resizeVolumeDialog"); restoreGeometry(kcg.readEntry("Geometry", QByteArray())); } void ResizeVolumeGroupDialog::setupDialog() { if (dialogWidget().volumeType().currentText() == QStringLiteral("LVM")) { - for (const auto &p : qAsConst(LVM::pvList)) { + for (const auto &p : qAsConst(LVM::pvList::list())) { + bool toBeDeleted = false; + + // Ignore partitions that are going to be deleted + for (const auto &o : qAsConst(m_PendingOps)) { + if (dynamic_cast(o) && o->targets(*p.partition())) { + toBeDeleted = true; + break; + } + } + + if (toBeDeleted) + continue; + if (p.isLuks()) continue; if (p.vgName() == device()->name()) dialogWidget().listPV().addPartition(*p.partition(), true); else if (p.vgName() == QString() && !LvmDevice::s_DirtyPVs.contains(p.partition())) // TODO: Remove LVM PVs in current VG dialogWidget().listPV().addPartition(*p.partition(), false); } + + for (const Device *d : qAsConst(m_Devices)) { + if (d->partitionTable() != nullptr) { + for (const Partition *p : qAsConst(d->partitionTable()->children())) { + // Looking if there is another VG creation that contains this partition + if (LvmDevice::s_DirtyPVs.contains(p)) + continue; + + // Including new LVM PVs (that are currently in OperationStack and that aren't at other VG creation) + if (p->state() == Partition::State::New) { + if (p->fileSystem().type() == FileSystem::Type::Lvm2_PV) + dialogWidget().listPV().addPartition(*p, false); + else if (p->fileSystem().type() == FileSystem::Type::Luks || p->fileSystem().type() == FileSystem::Type::Luks2) { + FileSystem *fs = static_cast(&p->fileSystem())->innerFS(); + + if (fs->type() == FileSystem::Type::Lvm2_PV) + dialogWidget().listPV().addPartition(*p, false); + } + } + } + } + } + + for (const Partition *p : qAsConst(LvmDevice::s_OrphanPVs)) + if (!LvmDevice::s_DirtyPVs.contains(p)) + dialogWidget().listPV().addPartition(*p, false); } //update used size and LV infos qint32 totalLV = 0; LvmDevice *lvmDevice = dynamic_cast(device()); if (lvmDevice != nullptr) { m_TotalUsedSize = lvmDevice->allocatedPE() * lvmDevice->peSize(); totalLV = lvmDevice->partitionTable()->children().count(); } dialogWidget().totalUsedSize().setText(Capacity::formatByteSize(m_TotalUsedSize)); dialogWidget().totalLV().setText(QString::number(totalLV)); } void ResizeVolumeGroupDialog::setupConstraints() { dialogWidget().vgName().setEnabled(false); dialogWidget().spinPESize().setEnabled(false); dialogWidget().volumeType().setEnabled(false); VolumeGroupDialog::setupConstraints(); } void ResizeVolumeGroupDialog::accept() { targetPVList().append(dialogWidget().listPV().checkedItems()); QDialog::accept(); } diff --git a/src/gui/resizevolumegroupdialog.h b/src/gui/resizevolumegroupdialog.h index 138161a..986ffc8 100644 --- a/src/gui/resizevolumegroupdialog.h +++ b/src/gui/resizevolumegroupdialog.h @@ -1,49 +1,51 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * * * 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(RESIZEVOLUMEGROUPDIALOG_H) - +#ifndef RESIZEVOLUMEGROUPDIALOG_H #define RESIZEVOLUMEGROUPDIALOG_H #include #include "gui/volumegroupdialog.h" class Device; +class Operation; class VolumeManagerDevice; class ResizeVolumeGroupDialog : public VolumeGroupDialog { Q_DISABLE_COPY(ResizeVolumeGroupDialog) public: - ResizeVolumeGroupDialog(QWidget* parent, VolumeManagerDevice *d, QVector& partList); + ResizeVolumeGroupDialog(QWidget* parent, VolumeManagerDevice *d, QVector& partList, QList devices, QList pendingOps = QList()); protected: void accept() override; void setupDialog() override; void setupConstraints() override; VolumeManagerDevice* device() const { return m_Device; } private: + const QList m_Devices; // List of all devices found on the system VolumeManagerDevice* m_Device; + const QList m_PendingOps; // List of pending operations in KPM }; #endif diff --git a/src/gui/scanprogressdialog.cpp b/src/gui/scanprogressdialog.cpp index 0e7740e..b14049e 100644 --- a/src/gui/scanprogressdialog.cpp +++ b/src/gui/scanprogressdialog.cpp @@ -1,45 +1,53 @@ /************************************************************************* * 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/scanprogressdialog.h" +#include + #include ScanProgressDialog::ScanProgressDialog(QWidget* parent) : QProgressDialog(parent) { setWindowTitle(xi18nc("@title:window", "Scanning devices...")); setMinimumWidth(280); setMinimumDuration(150); + setValue(0); setAttribute(Qt::WA_ShowModal, true); } +void ScanProgressDialog::closeEvent(QCloseEvent* e) +{ + e->ignore(); +} + void ScanProgressDialog::setDeviceName(const QString& d) { if (d.isEmpty()) setLabelText(xi18nc("@label", "Scanning...")); else setLabelText(xi18nc("@label", "Scanning device: %1", d)); } void ScanProgressDialog::showEvent(QShowEvent* e) { - setCancelButton(0); + setCancelButton(nullptr); QProgressDialog::showEvent(e); } diff --git a/src/gui/scanprogressdialog.h b/src/gui/scanprogressdialog.h index c3bbb93..94e3261 100644 --- a/src/gui/scanprogressdialog.h +++ b/src/gui/scanprogressdialog.h @@ -1,42 +1,40 @@ /************************************************************************* * Copyright (C) 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(SCANPROGRESSDIALOG_H) - +#ifndef SCANPROGRESSDIALOG_H #define SCANPROGRESSDIALOG_H #include -class QShowEvent; - class ScanProgressDialog : public QProgressDialog { public: ScanProgressDialog(QWidget* parent); void setProgress(int p) { setValue(p); } void setDeviceName(const QString& d); protected: + void closeEvent(QCloseEvent* e) override; void showEvent(QShowEvent* e) override; }; #endif diff --git a/src/gui/sizedialogbase.cpp b/src/gui/sizedialogbase.cpp index 7a2d499..7116756 100644 --- a/src/gui/sizedialogbase.cpp +++ b/src/gui/sizedialogbase.cpp @@ -1,472 +1,472 @@ /************************************************************************* * Copyright (C) 2008, 2010 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * Copyright (C) 2016 by Teo Mrnjavac * * * * 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/sizedialogbase.h" #include "gui/sizedetailswidget.h" #include "gui/sizedialogwidget.h" #include "util/guihelpers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static double sectorsToDialogUnit(const Device& d, qint64 v); static qint64 dialogUnitToSectors(const Device& d, double v); SizeDialogBase::SizeDialogBase(QWidget* parent, Device& d, Partition& part, qint64 minFirst, qint64 maxLast) : QDialog(parent), m_SizeDialogWidget(new SizeDialogWidget(this)), m_SizeDetailsWidget(new SizeDetailsWidget(this)), m_Device(d), m_Partition(part), m_MinimumFirstSector(minFirst), m_MaximumLastSector(maxLast), m_MinimumLength(-1), m_MaximumLength(-1), m_IsValidLVName(true) { 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(); QDialogButtonBox* dialogButtonBox = new QDialogButtonBox(this); detailsButton = new QPushButton(dialogButtonBox); okButton = dialogButtonBox->addButton(QDialogButtonBox::Ok); cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); detailsButton->setText(xi18nc("@action:button advanced settings button", "Advanced") + QStringLiteral(" >>")); dialogButtonBox->addButton(detailsButton, QDialogButtonBox::ActionRole); mainLayout->setSizeConstraint(QLayout::SetFixedSize); mainLayout->addWidget(dialogButtonBox); connect(dialogButtonBox, &QDialogButtonBox::accepted, this, &SizeDialogBase::accept); connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &SizeDialogBase::reject); connect(detailsButton, &QPushButton::clicked, this, &SizeDialogBase::toggleDetails); } void SizeDialogBase::setupDialog() { dialogWidget().spinFreeBefore().setValue(sectorsToDialogUnit(device(), partition().firstSector() - minimumFirstSector())); dialogWidget().spinFreeAfter().setValue(sectorsToDialogUnit(device(), maximumLastSector() - partition().lastSector())); dialogWidget().spinCapacity().setValue(Capacity(partition().capacity()).toDouble(preferredUnit())); dialogWidget().spinFreeBefore().setSuffix(QStringLiteral(" ") + Capacity::unitName(preferredUnit())); dialogWidget().spinFreeAfter().setSuffix(QStringLiteral(" ") + Capacity::unitName(preferredUnit())); dialogWidget().spinCapacity().setSuffix(QStringLiteral(" ") + Capacity::unitName(preferredUnit())); detailsWidget().spinFirstSector().setValue(partition().firstSector()); detailsWidget().spinLastSector().setValue(partition().lastSector()); detailsWidget().checkAlign().setChecked(Config::alignDefault()); if (canGrow() || canShrink()) dialogWidget().partResizerWidget().init(device(), partition(), minimumFirstSector(), maximumLastSector(), false, canMove()); else dialogWidget().partResizerWidget().init(device(), partition(), minimumFirstSector(), maximumLastSector(), true, canMove()); dialogWidget().partResizerWidget().setAlign(Config::alignDefault()); - if (device().type() == Device::Disk_Device) { + if (device().type() == Device::Type::Disk_Device) { dialogWidget().lvName().hide(); dialogWidget().textLVName().hide(); } - if (device().type() == Device::LVM_Device) { + if (device().type() == Device::Type::LVM_Device) { dialogWidget().hideBeforeAndAfter(); detailsWidget().checkAlign().setChecked(false); detailsWidget().checkAlign().setEnabled(false); detailsButton->hide(); m_IsValidLVName = false; /* LVM logical volume name can consist of: letters numbers _ . - + * It cannot start with underscore _ and must not be equal to . or .. or any entry in /dev/ * QLineEdit accepts QValidator::Intermediate, so we just disable . at the beginning */ QRegularExpression re(QStringLiteral(R"(^(?!_|\.)[\w\-.+]+)")); QRegularExpressionValidator *validator = new QRegularExpressionValidator(re, this); dialogWidget().lvName().setValidator(validator); } } void SizeDialogBase::setupConstraints() { // Do not allow moving first sector if moving partition is disabled bool moveAllowed = canMove(); if (!moveAllowed) m_MinimumFirstSector = partition().firstSector(); dialogWidget().spinFreeBefore().setEnabled(moveAllowed); dialogWidget().spinFreeAfter().setEnabled(moveAllowed); detailsWidget().spinFirstSector().setEnabled(moveAllowed); setMinimumLength(!canShrink() ? partition().length() : std::max(partition().sectorsUsed(), partition().minimumSectors())); setMaximumLength(!canGrow() ? partition().length() : std::min(maximumLastSector() - minimumFirstSector() + 1, partition().maximumSectors())); dialogWidget().partResizerWidget().setMinimumLength(minimumLength()); dialogWidget().partResizerWidget().setMaximumLength(maximumLength()); dialogWidget().labelMinSize().setText(Capacity::formatByteSize(minimumLength() * device().logicalSize())); dialogWidget().labelMaxSize().setText(Capacity::formatByteSize(maximumLength() * device().logicalSize())); dialogWidget().spinCapacity().setEnabled(canShrink() || canGrow()); dialogWidget().partResizerWidget().setMaximumFirstSector(maximumFirstSector()); dialogWidget().partResizerWidget().setMinimumLastSector(minimumLastSector()); const qint64 totalCapacity = sectorsToDialogUnit(device(), maximumLastSector() - minimumFirstSector() + 1); const qint64 minCapacity = sectorsToDialogUnit(device(), minimumLength()); const qint64 maxCapacity = sectorsToDialogUnit(device(), maximumLength()); dialogWidget().spinCapacity().setRange(minCapacity, maxCapacity); minCapacity > maxCapacity ? okButton->setEnabled(false) : okButton->setEnabled(true); const qint64 maxFree = totalCapacity - minCapacity; dialogWidget().spinFreeBefore().setRange(0, maxFree); dialogWidget().spinFreeAfter().setRange(0, maxFree); detailsWidget().spinFirstSector().setRange(minimumFirstSector(), maximumLastSector()); detailsWidget().spinLastSector().setRange(minimumFirstSector(), maximumLastSector()); onAlignToggled(align()); } void SizeDialogBase::setupConnections() { connect(&dialogWidget().partResizerWidget(), &PartResizerWidget::firstSectorChanged, this, &SizeDialogBase::onResizerWidgetFirstSectorChanged); connect(&dialogWidget().partResizerWidget(), &PartResizerWidget::lastSectorChanged, this, &SizeDialogBase::onResizerWidgetLastSectorChanged); connect(&dialogWidget().spinFreeBefore(), qOverload(&QDoubleSpinBox::valueChanged), this, &SizeDialogBase::onSpinFreeBeforeChanged); connect(&dialogWidget().spinFreeAfter(), qOverload(&QDoubleSpinBox::valueChanged), this, &SizeDialogBase::onSpinFreeAfterChanged); connect(&dialogWidget().spinCapacity(), qOverload(&QDoubleSpinBox::valueChanged), this, &SizeDialogBase::onSpinCapacityChanged); connect(&detailsWidget().spinFirstSector(), qOverload(&QDoubleSpinBox::valueChanged), this, &SizeDialogBase::onSpinFirstSectorChanged); connect(&detailsWidget().spinLastSector(), qOverload(&QDoubleSpinBox::valueChanged), this, &SizeDialogBase::onSpinLastSectorChanged); connect(&detailsWidget().checkAlign(), &QCheckBox::toggled, this, &SizeDialogBase::onAlignToggled); connect(&dialogWidget().lvName(), &QLineEdit::textChanged, this, &SizeDialogBase::onLVNameChanged); } void SizeDialogBase::toggleDetails() { const bool isVisible = detailsWidget().isVisible(); detailsWidget().setVisible(!isVisible); detailsButton->setText(xi18nc("@action:button", "&Advanced") + (isVisible ? QStringLiteral(" >>") : QStringLiteral(" <<"))); } void SizeDialogBase::onSpinFreeBeforeChanged(double newBefore) { bool success = false; const double oldBefore = sectorsToDialogUnit(device(), partition().firstSector() - minimumFirstSector()); const qint64 newFirstSector = minimumFirstSector() + dialogUnitToSectors(device(), newBefore); const qint64 deltaCorrection = newBefore > oldBefore ? PartitionAlignment::firstDelta(device(), partition(), newFirstSector) : 0; // We need different alignFirstSector parameters for moving the first sector (which // has to take into account min and max length of the partition) and for moving // the whole partition (which must NOT take min and max length into account since // the length is fixed in this case anyway) qint64 alignedFirstSector = align() ? PartitionAlignment::alignedFirstSector(device(), partition(), newFirstSector + deltaCorrection, minimumFirstSector(), -1, -1, -1) : newFirstSector; if (dialogWidget().partResizerWidget().movePartition(alignedFirstSector)) success = true; else { alignedFirstSector = align() ? PartitionAlignment::alignedFirstSector(device(), partition(), newFirstSector + deltaCorrection, minimumFirstSector(), -1, minimumLength(), maximumLength()) : newFirstSector; success = dialogWidget().partResizerWidget().updateFirstSector(alignedFirstSector); } if (success) setDirty(); else // TODO: this is not the best solution: we should prevent the user from entering // illegal values with a validator updateSpinFreeBefore(dialogUnitToSectors(device(), oldBefore)); } void SizeDialogBase::onSpinCapacityChanged(double newCapacity) { bool success = false; qint64 newLength = qBound( minimumLength(), dialogUnitToSectors(device(), newCapacity), std::min(maximumLastSector() - minimumFirstSector() + 1, maximumLength()) ); if (newLength == partition().length()) return; qint64 delta = newLength - partition().length(); qint64 tmp = std::min(delta, maximumLastSector() - partition().lastSector()); delta -= tmp; const bool signalState = dialogWidget().partResizerWidget().blockSignals(true); if (tmp != 0) { qint64 newLastSector = partition().lastSector() + tmp; if (align()) newLastSector = PartitionAlignment::alignedLastSector(device(), partition(), newLastSector, minimumLastSector(), maximumLastSector(), minimumLength(), maximumLength()); if (dialogWidget().partResizerWidget().updateLastSector(newLastSector)) { success = true; updateSpinFreeAfter(maximumLastSector() - newLastSector); updateSpinLastSector(newLastSector); } } tmp = std::min(delta, partition().firstSector() - minimumFirstSector()); delta -= tmp; if (tmp != 0) { qint64 newFirstSector = partition().firstSector() - tmp; if (align()) newFirstSector = PartitionAlignment::alignedFirstSector(device(), partition(), newFirstSector, minimumFirstSector(), maximumFirstSector(), minimumLength(), maximumLength()); if (dialogWidget().partResizerWidget().updateFirstSector(newFirstSector)) { success = true; updateSpinFreeBefore(newFirstSector - minimumFirstSector()); updateSpinFirstSector(newFirstSector); } } dialogWidget().partResizerWidget().blockSignals(signalState); if (success) setDirty(); } void SizeDialogBase::onSpinFreeAfterChanged(double newAfter) { bool success = false; const double oldAfter = sectorsToDialogUnit(device(), maximumLastSector() - partition().lastSector()); const qint64 newLastSector = maximumLastSector() - dialogUnitToSectors(device(), newAfter); const qint64 deltaCorrection = newAfter > oldAfter ? PartitionAlignment::lastDelta(device(), partition(), newLastSector) : 0; // see onSpinFreeBeforeChanged on why this is as complicated as it is qint64 alignedLastSector = align() ? PartitionAlignment::alignedLastSector(device(), partition(), newLastSector - deltaCorrection, -1, maximumLastSector(), -1, -1) : newLastSector; if (dialogWidget().partResizerWidget().movePartition(alignedLastSector - partition().length() + 1)) success = true; else { alignedLastSector = align() ? PartitionAlignment::alignedLastSector(device(), partition(), newLastSector - deltaCorrection, -1, maximumLastSector(), minimumLength(), maximumLength()) : newLastSector; success = dialogWidget().partResizerWidget().updateLastSector(alignedLastSector); } if (success) setDirty(); else // TODO: this is not the best solution: we should prevent the user from entering // illegal values with a validator updateSpinFreeAfter(dialogUnitToSectors(device(), oldAfter)); } void SizeDialogBase::onSpinFirstSectorChanged(qint64 newFirst) { if (newFirst >= minimumFirstSector() && dialogWidget().partResizerWidget().updateFirstSector(newFirst)) setDirty(); else // TODO: this is not the best solution: we should prevent the user from entering // illegal values with a validator updateSpinFirstSector(partition().firstSector()); } void SizeDialogBase::onSpinLastSectorChanged(qint64 newLast) { if (newLast <= maximumLastSector() && dialogWidget().partResizerWidget().updateLastSector(newLast)) setDirty(); else // TODO: this is not the best solution: we should prevent the user from entering // illegal values with a validator updateSpinLastSector(partition().lastSector()); } void SizeDialogBase::onResizerWidgetFirstSectorChanged(qint64 newFirst) { updateSpinFreeBefore(newFirst - minimumFirstSector()); updateSpinFirstSector(newFirst); updateSpinCapacity(partition().length()); setDirty(); } void SizeDialogBase::onResizerWidgetLastSectorChanged(qint64 newLast) { updateSpinFreeAfter(maximumLastSector() - newLast); updateSpinLastSector(newLast); updateSpinCapacity(partition().length()); setDirty(); } void SizeDialogBase::onAlignToggled(bool align) { dialogWidget().partResizerWidget().setAlign(align); detailsWidget().spinFirstSector().setSingleStep(align ? PartitionAlignment::sectorAlignment(device()) : 1); detailsWidget().spinLastSector().setSingleStep(align ? PartitionAlignment::sectorAlignment(device()) : 1); const double capacityStep = align ? sectorsToDialogUnit(device(), PartitionAlignment::sectorAlignment(device())) : 1; dialogWidget().spinFreeBefore().setSingleStep(capacityStep); dialogWidget().spinFreeBefore().setSingleStep(capacityStep); dialogWidget().spinCapacity().setSingleStep(capacityStep); // if align is on, turn off keyboard tracking for all spin boxes to avoid the two clashing const auto children = dialogWidget().findChildren() + detailsWidget().findChildren(); for (const auto &box : children) box->setKeyboardTracking(!align); if (align) { onSpinFirstSectorChanged(partition().firstSector()); onSpinLastSectorChanged(partition().lastSector()); } } void SizeDialogBase::onLVNameChanged(const QString& newName) { partition().setPartitionPath(device().deviceNode() + QStringLiteral("/") + newName.trimmed()); if ((dialogWidget().lvName().isVisible() && dialogWidget().lvName().text().isEmpty()) || - (device().type() == Device::LVM_Device && + (device().type() == Device::Type::LVM_Device && dynamic_cast(device()).partitionNodes().contains(partition().partitionPath())) ) { m_IsValidLVName = false; } else { m_IsValidLVName = true; } updateOkButtonStatus(); } void SizeDialogBase::updateOkButtonStatus() { okButton->setEnabled(isValidLVName()); } void SizeDialogBase::updateSpinFreeBefore(qint64 sectorsFreeBefore) { const bool signalState = dialogWidget().spinFreeBefore().blockSignals(true); dialogWidget().spinFreeBefore().setValue(sectorsToDialogUnit(device(), sectorsFreeBefore)); dialogWidget().spinFreeBefore().blockSignals(signalState); } void SizeDialogBase::updateSpinCapacity(qint64 newLengthInSectors) { bool state = dialogWidget().spinCapacity().blockSignals(true); dialogWidget().spinCapacity().setValue(sectorsToDialogUnit(device(), newLengthInSectors)); dialogWidget().spinCapacity().blockSignals(state); } void SizeDialogBase::updateSpinFreeAfter(qint64 sectorsFreeAfter) { const bool signalState = dialogWidget().spinFreeAfter().blockSignals(true); dialogWidget().spinFreeAfter().setValue(sectorsToDialogUnit(device(), sectorsFreeAfter)); dialogWidget().spinFreeAfter().blockSignals(signalState); } void SizeDialogBase::updateSpinFirstSector(qint64 newFirst) { const bool signalState = detailsWidget().spinFirstSector().blockSignals(true); detailsWidget().spinFirstSector().setValue(newFirst); detailsWidget().spinFirstSector().blockSignals(signalState); } void SizeDialogBase::updateSpinLastSector(qint64 newLast) { const bool signalState = detailsWidget().spinLastSector().blockSignals(true); detailsWidget().spinLastSector().setValue(newLast); detailsWidget().spinLastSector().blockSignals(signalState); } const PartitionTable& SizeDialogBase::partitionTable() const { Q_ASSERT(device().partitionTable()); return *device().partitionTable(); } bool SizeDialogBase::align() const { return detailsWidget().checkAlign().isChecked(); } qint64 SizeDialogBase::minimumLastSector() const { return partition().minLastSector(); } qint64 SizeDialogBase::maximumFirstSector() const { return partition().maxFirstSector(); } qint64 SizeDialogBase::minimumLength() const { return m_MinimumLength; } qint64 SizeDialogBase::maximumLength() const { return m_MaximumLength; } static double sectorsToDialogUnit(const Device& d, qint64 v) { return Capacity(v * d.logicalSize()).toDouble(preferredUnit()); } static qint64 dialogUnitToSectors(const Device& d, double v) { - return v * Capacity::unitFactor(Capacity::Byte, preferredUnit()) / d.logicalSize(); + return v * Capacity::unitFactor(Capacity::Unit::Byte, preferredUnit()) / d.logicalSize(); } diff --git a/src/gui/smartdialog.cpp b/src/gui/smartdialog.cpp index cacffbe..78c6c64 100644 --- a/src/gui/smartdialog.cpp +++ b/src/gui/smartdialog.cpp @@ -1,238 +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")) + << (a.failureType() == SmartAttribute::FailureType::PreFailure ? xi18nc("@item:intable", "Pre-Failure") : xi18nc("@item:intable", "Old-Age")) + << (a.updateType() == SmartAttribute::UpdateType::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" << "\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")) << "" << (a.failureType() == SmartAttribute::FailureType::PreFailure ? xi18nc("@item:intable", "Pre-Failure") : xi18nc("@item:intable", "Old-Age")) << "" << (a.updateType() == SmartAttribute::UpdateType::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.")); } diff --git a/src/gui/treelog.cpp b/src/gui/treelog.cpp index d1bb792..9cd0f6d 100644 --- a/src/gui/treelog.cpp +++ b/src/gui/treelog.cpp @@ -1,163 +1,163 @@ /************************************************************************* * Copyright (C) 2008, 2009 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/treelog.h" #include "gui/partitionmanagerwidget.h" #include "util/guihelpers.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** Creates a new TreeLog instance. @param parent the parent widget */ TreeLog::TreeLog(QWidget* parent) : QWidget(parent), Ui::TreeLogBase() { setupUi(this); treeLog().header()->setContextMenuPolicy(Qt::CustomContextMenu); connect(treeLog().header(), &QHeaderView::customContextMenuRequested, this, &TreeLog::onHeaderContextMenu); } TreeLog::~TreeLog() { saveConfig(); } void TreeLog::init() { loadConfig(); } void TreeLog::loadConfig() { QList colWidths = Config::treeLogColumnWidths(); QList colPositions = Config::treeLogColumnPositions(); QList colVisible = Config::treeLogColumnVisible(); QHeaderView* header = treeLog().header(); for (int i = 0; i < treeLog().columnCount(); i++) { if (colPositions[0] != -1 && colPositions.size() > i) header->moveSection(header->visualIndex(i), colPositions[i]); if (colVisible[0] != -1 && colVisible.size() > i) treeLog().setColumnHidden(i, colVisible[i] == 0); if (colWidths[0] != -1 && colWidths.size() > i) treeLog().setColumnWidth(i, colWidths[i]); } } void TreeLog::saveConfig() const { QList colWidths; QList colPositions; QList colVisible; for (int i = 0; i < treeLog().columnCount(); i++) { colPositions.append(treeLog().header()->visualIndex(i)); colVisible.append(treeLog().isColumnHidden(i) ? 0 : 1); colWidths.append(treeLog().columnWidth(i)); } Config::setTreeLogColumnPositions(colPositions); Config::setTreeLogColumnVisible(colVisible); Config::setTreeLogColumnWidths(colWidths); Config::self()->save(); } void TreeLog::onHeaderContextMenu(const QPoint& pos) { showColumnsContextMenu(pos, treeLog()); } void TreeLog::onClearLog() { while (QTreeWidgetItem* item = treeLog().takeTopLevelItem(0)) delete item; } void TreeLog::onSaveLog() { const QUrl url = QFileDialog::getSaveFileUrl(); if (!url.isEmpty()) { QTemporaryFile tempFile; if (!tempFile.open()) { KMessageBox::error(this, xi18nc("@info", "Could not create temporary output file to save %1.", url.fileName()), xi18nc("@title:window", "Error Saving Log File")); return; } QTextStream stream(&tempFile); for (qint32 idx = 0; idx < treeLog().topLevelItemCount(); idx++) { QTreeWidgetItem* item = treeLog().topLevelItem(idx); stream << item->text(1) << ": " << item->text(2) << "\n"; } tempFile.close(); KIO::CopyJob* job = KIO::move(QUrl::fromLocalFile(tempFile.fileName()), url, KIO::HideProgressInfo); job->exec(); if (job->error()) job->uiDelegate()->showErrorMessage(); } } void TreeLog::onNewLogMessage(Log::Level logLevel, const QString& s) { static const QString icons[] = { QStringLiteral("tools-report-bug"), QStringLiteral("dialog-information"), QStringLiteral("dialog-warning"), QStringLiteral("dialog-error") }; qDebug() << s; - if (logLevel >= Config::minLogLevel()) { + if (static_cast(logLevel) >= Config::minLogLevel()) { QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setIcon(0, QIcon::fromTheme(icons[logLevel]).pixmap(IconSize(KIconLoader::Small))); + item->setIcon(0, QIcon::fromTheme(icons[static_cast(logLevel)]).pixmap(IconSize(KIconLoader::Small))); item->setText(1, QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss"))); item->setText(2, s); treeLog().addTopLevelItem(item); treeLog().scrollToBottom(); } } diff --git a/src/gui/volumegroupdialog.cpp b/src/gui/volumegroupdialog.cpp index 8434bee..70edf02 100644 --- a/src/gui/volumegroupdialog.cpp +++ b/src/gui/volumegroupdialog.cpp @@ -1,164 +1,164 @@ /************************************************************************* * Copyright (C) 2016 by Chantara Tith * * 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/volumegroupdialog.h" #include "gui/volumegroupwidget.h" #include #include #include #include #include #include #include #include #include #include #include /** Creates a new VolumeGroupDialog @param parent pointer to the parent widget @param vgName Volume Group name @param pvList List of LVM Physical Volumes used to create Volume Group */ VolumeGroupDialog::VolumeGroupDialog(QWidget* parent, QString& vgName, QVector& pvList) : QDialog(parent), m_DialogWidget(new VolumeGroupWidget(this)), m_TargetName(vgName), m_TargetPVList(pvList), m_IsValidSize(false), m_IsValidName(true), m_TotalSize(0), m_TotalUsedSize(0), m_ExtentSize(0) { mainLayout = new QVBoxLayout(this); setLayout(mainLayout); mainLayout->addWidget(&dialogWidget()); dialogButtonBox = new QDialogButtonBox; okButton = dialogButtonBox->addButton(QDialogButtonBox::Ok); cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); mainLayout->addWidget(dialogButtonBox); cancelButton->setFocus(); cancelButton->setDefault(true); setupDialog(); setupConstraints(); setupConnections(); } /** Destroys a VolumeGroupDialog */ VolumeGroupDialog::~VolumeGroupDialog() { KConfigGroup kcg(KSharedConfig::openConfig(), "createVolumeGroupDialog"); kcg.writeEntry("Geometry", saveGeometry()); } void VolumeGroupDialog::setupDialog() { /* LVM Volume group name can consist of: letters numbers _ . - + * It cannot start with underscore _ and must not be equal to . or .. or any entry in /dev/ * QLineEdit accepts QValidator::Intermediate, so we just disable . at the beginning */ QRegularExpression re(QStringLiteral(R"(^(?!_|\.)[\w\-.+]+)")); QRegularExpressionValidator *validator = new QRegularExpressionValidator(re, this); dialogWidget().vgName().setValidator(validator); dialogWidget().vgName().setText(targetName()); dialogWidget().volumeType().addItem(QStringLiteral("LVM")); dialogWidget().volumeType().addItem(QStringLiteral("RAID")); dialogWidget().volumeType().setCurrentIndex(0); setMinimumSize(dialogWidget().size()); resize(dialogWidget().size()); } void VolumeGroupDialog::setupConnections() { connect(dialogButtonBox, &QDialogButtonBox::accepted, this, &VolumeGroupDialog::accept); connect(dialogButtonBox, &QDialogButtonBox::rejected, this, &VolumeGroupDialog::reject); connect(&dialogWidget().volumeType(), qOverload(&QComboBox::currentIndexChanged), this, &VolumeGroupDialog::onVolumeTypeChanged); connect(&dialogWidget().listPV().listPhysicalVolumes(), &QListWidget::itemChanged, this, [=] ( QListWidgetItem*) { updateSizeInfos(); }); } void VolumeGroupDialog::setupConstraints() { updateSizeInfos(); updateOkButtonStatus(); } void VolumeGroupDialog::updateOkButtonStatus() { bool enable = isValidSize(); if (dialogWidget().vgName().text().isEmpty() || !isValidName()) { enable = false; } if (dialogWidget().spinPESize().value() <= 0) { enable = false; } okButton->setEnabled(enable); } void VolumeGroupDialog::updateSectorInfos() { qint32 totalSectors = 0; // we can't use LvmDevice mothod here because pv that is not in any VG will return 0 - m_ExtentSize = dialogWidget().spinPESize().value() * Capacity::unitFactor(Capacity::Byte, Capacity::MiB); + m_ExtentSize = dialogWidget().spinPESize().value() * Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::MiB); if (m_ExtentSize > 0) { totalSectors = m_TotalSize / m_ExtentSize; } dialogWidget().totalSectors().setText(QString::number(totalSectors)); } void VolumeGroupDialog::updateSizeInfos() { const QVector checkedPartitions = dialogWidget().listPV().checkedItems(); m_TotalSize = 0; for (const auto &p : checkedPartitions) - m_TotalSize += p->capacity() - p->capacity() % (dialogWidget().spinPESize().value() * Capacity::unitFactor(Capacity::Byte, Capacity::MiB)); // subtract space which is too small to hold PE + m_TotalSize += p->capacity() - p->capacity() % (dialogWidget().spinPESize().value() * Capacity::unitFactor(Capacity::Unit::Byte, Capacity::Unit::MiB)); // subtract space which is too small to hold PE dialogWidget().totalSize().setText(Capacity::formatByteSize(m_TotalSize)); //Probably a bad design for updating state here; the state should be changed inside the update button function. m_IsValidSize = m_TotalSize >= m_TotalUsedSize; updateSectorInfos(); updateOkButtonStatus(); } void VolumeGroupDialog::updatePartitionList() { } void VolumeGroupDialog::onPartitionListChanged() { } void VolumeGroupDialog::onVolumeTypeChanged(int index) { Q_UNUSED(index) updatePartitionList(); } diff --git a/src/main.cpp b/src/main.cpp index ab2c814..578cef5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,90 +1,85 @@ /************************************************************************* * Copyright (C) 2008,2011 by Volker Lanz * + * Copyright (C) 2014-2018 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/mainwindow.h" #include #include #include #include "util/guihelpers.h" #include #include #include #include -#include +#include #include #include #include int Q_DECL_IMPORT main(int argc, char* argv[]) { QApplication app(argc, argv); - Kdelibs4ConfigMigrator migrate(QLatin1Literal("partitionmanager")); - migrate.setConfigFiles({ QLatin1Literal("partitionmanagerrc") }); - migrate.setUiFiles({ QStringLiteral("partitionmanagerui.rc") }); - migrate.migrate(); - KLocalizedString::setApplicationDomain("partitionmanager"); KAboutData aboutData ( QStringLiteral("partitionmanager"), xi18nc("@title", "KDE Partition Manager"), QStringLiteral(VERSION), xi18nc("@title", "Manage your disks, partitions and file systems"), KAboutLicense::GPL_V3, - xi18nc("@info:credit", "© 2008-2013 Volker Lanz\n© 2012-2017 Andrius Štikonas")); + xi18nc("@info:credit", "© 2008-2013 Volker Lanz\n© 2012-2018 Andrius Štikonas")); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.setProductName(QByteArray("partitionmanager")); aboutData.addAuthor(xi18nc("@info:credit", "Volker Lanz"), xi18nc("@info:credit", "Former maintainer")); aboutData.addAuthor(xi18nc("@info:credit", "Andrius Štikonas"), xi18nc("@info:credit", "Maintainer"), QStringLiteral("andrius@stikonas.eu")); aboutData.addCredit(xi18nc("@info:credit", "Teo Mrnjavac"), i18nc("@info:credit", "Former Calamares maintainer"), QStringLiteral("teo@kde.org")); aboutData.addCredit(xi18nc("@info:credit", "Chantara Tith"), i18nc("@info:credit", "LVM support"), QStringLiteral("tith.chantara@gmail.com")); aboutData.addCredit(xi18nc("@info:credit", "Pali Rohár"), i18nc("@info:credit", "UDF support"), QStringLiteral("pali.rohar@gmail.com")); aboutData.setHomepage(QStringLiteral("https://www.kde.org/applications/system/kdepartitionmanager")); aboutData.addCredit(i18n("Hugo Pereira Da Costa"), xi18nc("@info:credit", "Partition Widget Design"), QStringLiteral("hugo@oxygen-icons.org")); KAboutData::setApplicationData(aboutData); app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); KCrash::initialize(); QCommandLineParser parser; aboutData.setupCommandLine(&parser); - parser.addOption(QCommandLineOption(QLatin1Literal("dontsu"), xi18nc("@info:shell", "Do not try to gain super user privileges"))); // FIXME parser.addPositionalArgument(QStringLiteral("device"), xi18nc("@info:shell", "Device(s) to manage"), QStringLiteral("[device...]")); parser.process(app); aboutData.processCommandLine(&parser); + KDBusService service(KDBusService::Unique); + registerMetaTypes(); - if (!checkPermissions()) - return 0; Config::instance(QStringLiteral("partitionmanagerrc")); if (!loadBackend()) return 0; MainWindow* mainWindow = new MainWindow(); - mainWindow->show(); + Q_UNUSED(mainWindow) return app.exec(); } diff --git a/src/partitionmanager.kcfg b/src/partitionmanager.kcfg index ad89c75..1cf4e26 100644 --- a/src/partitionmanager.kcfg +++ b/src/partitionmanager.kcfg @@ -1,127 +1,158 @@ fs/filesystem.h util/capacity.h true 0 2048 false true - - - false - - + - - - 220,205,175 - 187,249,207 - 102,121,150 - 122,145,180 - 143,170,210 - 155,155,130 - 204,179,215 - 229,201,240 - 244,214,255 - 216,220,135 - 251,255,157 - 200,255,254 - 137,200,198 - 210,136,142 - 240,165,171 - 151,220,134 - 220,205,175 - 173,205,255 - 176,155,185 - 170,30,77 - 96,140,85 - 33,137,108 - 250,230,255 - 242,155,104 - 160,210,180 - 255,170,0 - 170,120,255 - 177,82,69 - 223,39,104 - 204,179,255 + + + + Unknown + Extended + Ext2 + Ext3 + Ext4 + LinuxSwap + Fat16 + Fat32 + Ntfs + ReiserFS + Reiser4 + Xfs + Jfs + Hfs + HfsPlus + Ufs + Unformatted + Btrfs + Hpfs + Luks + Ocfs2 + Zfs + Exfat + Nilfs2 + Lvm2_PV + F2fs + Udf + Iso9660 + Luks2 + Fat12 + LinuxRaidMember + + + 220,205,175 + 187,249,207 + 102,121,150 + 122,145,180 + 143,170,210 + 155,155,130 + 204,179,215 + 229,201,240 + 244,214,255 + 216,220,135 + 251,255,157 + 200,255,254 + 137,200,198 + 210,136,142 + 240,165,171 + 151,220,134 + 220,205,175 + 173,205,255 + 176,155,185 + 170,30,77 + 96,140,85 + 33,137,108 + 250,230,255 + 242,155,104 + 160,210,180 + 255,170,0 + 170,120,255 + 177,82,69 + 223,39,104 + 204,179,255 + 255,100,100 true - FileSystem::Ext4 + static_cast<int>(FileSystem::Type::Ext4) Capacity::Byte Capacity::KiB Capacity::MiB Capacity::GiB Capacity::TiB Capacity::PiB Capacity::EiB Capacity::MiB random diff --git a/src/util/guihelpers.cpp b/src/util/guihelpers.cpp index 5efceca..49a537a 100644 --- a/src/util/guihelpers.cpp +++ b/src/util/guihelpers.cpp @@ -1,221 +1,130 @@ /************************************************************************* * Copyright (C) 2008-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 "util/guihelpers.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QIcon createFileSystemColor(FileSystem::Type type, quint32 size) { QPixmap pixmap(size, size); QPainter painter(&pixmap); painter.setPen(QColor(0, 0, 0)); - painter.setBrush(Config::fileSystemColorCode(type)); + painter.setBrush(Config::fileSystemColorCode(static_cast(type))); painter.drawRect(QRect(0, 0, pixmap.width() - 1, pixmap.height() - 1)); painter.end(); return QIcon(pixmap); } -bool checkPermissions() -{ - if (geteuid() != 0) { - // only try to gain root privileges if we have a valid (kde|gk)su(do) command and - // we did not try so before: the dontsu-option is there to make sure there are no - // endless loops of calling the same non-working (kde|gk)su(do) binary again and again. - if (!suCommand().isEmpty() && !QCoreApplication::arguments().contains(QLatin1String("--dontsu"))) { - QString argList; - - const QString suCmd = suCommand(); - - // kdesu broke backward compatibility at some point and now only works with "-c"; - // kdesudo accepts either (with or without "-c"), but the gk* helpers only work - // without. kdesu maintainers won't fix their app, so we need to work around that here. - if (suCmd.indexOf(QStringLiteral("kdesu")) != -1) - argList = QStringLiteral("-c "); - - // Workaround for ugly GUI when kdesu uses sudo - QString DBusString = QStringLiteral("DBUS_SESSION_BUS_ADDRESS"); - const QStringList envVars = { QStringLiteral("KDE_FULL_SESSION"), - QStringLiteral("QT_WAYLAND_FORCE_DPI"), - QStringLiteral("QT_QPA_PLATFORM"), - QStringLiteral("XDG_RUNTIME_DIR"), - DBusString }; - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - for (const auto &var : envVars) - if (env.contains(var)) - argList += var + QStringLiteral("=") + env.value(var) + QStringLiteral(" "); - - QString displayString = QStringLiteral("DISPLAY"); - QString homeString = QStringLiteral("HOME"); - if (!env.contains(DBusString) && env.contains(displayString) && env.contains(homeString)) { - QFile file(QStringLiteral("/var/lib/dbus/machine-id")); - if (file.open(QIODevice::ReadOnly)) { - QTextStream in(&file); - QString machineId = in.readLine(); - file.close(); - QString display = env.value(displayString).remove(0,1); - QFile sessionFile(env.value(homeString) + QStringLiteral("/.dbus/session-bus/") + machineId + QStringLiteral("-") + display); - if (sessionFile.open(QIODevice::ReadOnly)) { - QTextStream in2(&sessionFile); - while (!in2.atEnd()) { - QString line = in2.readLine(); - if (line.startsWith(DBusString)) { - argList += line + QStringLiteral(" "); - break; - } - } - } - } - } - - argList += QCoreApplication::arguments().join(QStringLiteral(" ")) + QStringLiteral(" --dontsu"); - - qDebug() << "Executing: " << suCmd << argList; - if (QProcess::execute(suCmd, QStringList(argList)) == 0) - return false; - } - - return KMessageBox::warningContinueCancel(nullptr, xi18nc("@info", - "You do not have administrative privileges." - "It is possible to run %1 without these privileges. " - "You will, however, not be allowed to apply operations." - "Do you want to continue running %1?" - "If administrator login is disabled and your password is " - "not accepted, then check kdesu " - "configuration.", - QGuiApplication::applicationDisplayName()), - xi18nc("@title:window", "No administrative privileges"), - KGuiItem(xi18nc("@action:button", "Run without administrative privileges"), QStringLiteral("arrow-right")), - KStandardGuiItem::cancel(), - QStringLiteral("runWithoutRootPrivileges"), KMessageBox::AllowLink) == KMessageBox::Continue; - } - - return true; -} - bool loadBackend() { if (CoreBackendManager::self()->load(Config::backend()) == false) { if (CoreBackendManager::self()->load(CoreBackendManager::defaultBackendName())) { if (!Config::firstRun()) KMessageBox::sorry(nullptr, xi18nc("@info", "The configured backend plugin \"%1\" could not be loaded." "Loading the default backend plugin \"%2\" instead.", Config::backend(), CoreBackendManager::defaultBackendName()), xi18nc("@title:window", "Error: Could Not Load Backend Plugin")); Config::setBackend(CoreBackendManager::defaultBackendName()); } else { KMessageBox::error(nullptr, xi18nc("@info", "Neither the configured (\"%1\") nor the default (\"%2\") backend " "plugin could be loaded.Please check your installation.", Config::backend(), CoreBackendManager::defaultBackendName()), xi18nc("@title:window", "Error: Could Not Load Backend Plugin")); return false; } } return true; } -QString suCommand() -{ - // First look for KF5 version of kdesu in libexec folder - const QString candidates[] = { QStringLiteral(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5"/kdesu"), QStringLiteral("kdesu"), QStringLiteral("kdesudo"), QStringLiteral("gksudo"), QStringLiteral("gksu") }; - QString rval; - - for (const auto &candidate : candidates) { - rval = QStandardPaths::findExecutable(candidate); - if (QFileInfo(rval).isExecutable()) - return rval; - } - - return QString(); -} - Capacity::Unit preferredUnit() { return static_cast(Config::preferredUnit()); } void showColumnsContextMenu(const QPoint& p, QTreeWidget& tree) { QMenu headerMenu(xi18nc("@title:menu", "Columns")); QHeaderView* header = tree.header(); for (qint32 i = 0; i < tree.model()->columnCount(); i++) { const int idx = header->logicalIndex(i); const QString text = tree.model()->headerData(idx, Qt::Horizontal).toString(); QAction* action = headerMenu.addAction(text); action->setCheckable(true); action->setChecked(!header->isSectionHidden(idx)); action->setData(idx); action->setEnabled(idx > 0); } QAction* action = headerMenu.exec(tree.header()->mapToGlobal(p)); if (action != nullptr) { const bool hidden = !action->isChecked(); tree.setColumnHidden(action->data().toInt(), hidden); if (!hidden) tree.resizeColumnToContents(action->data().toInt()); } } namespace GuiHelpers { FileSystem::Type defaultFileSystem() { return static_cast(Config::defaultFileSystem()); } -std::array< QColor, FileSystem::__lastType > fileSystemColorCodesFromSettings() +std::vector fileSystemColorCodesFromSettings() { - std::array< QColor, FileSystem::__lastType > cc; - for (int i = 0; i < FileSystem::__lastType; ++i) + std::vector cc; + cc.resize(Config::EnumFileSystem::type::COUNT); + for (int i = 0; i < Config::EnumFileSystem::type::COUNT; ++i) { - cc[ i ] = Config::fileSystemColorCode( i ); + cc[i] = Config::fileSystemColorCode(i); } return cc; } } diff --git a/src/util/guihelpers.h b/src/util/guihelpers.h index 3c857d8..5313045 100644 --- a/src/util/guihelpers.h +++ b/src/util/guihelpers.h @@ -1,44 +1,42 @@ /************************************************************************* * 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 .* *************************************************************************/ -#if !defined(GUIHELPERS_H) - +#ifndef GUIHELPERS_H #define GUIHELPERS_H #include #include +#include + class QIcon; class QPoint; class QString; class QTreeWidget; -bool checkPermissions(); bool loadBackend(); QIcon createFileSystemColor(FileSystem::Type type, quint32 size); Capacity::Unit preferredUnit(); void showColumnsContextMenu(const QPoint& p, QTreeWidget& tree); namespace GuiHelpers { FileSystem::Type defaultFileSystem(); -std::array< QColor, FileSystem::__lastType > fileSystemColorCodesFromSettings(); +std::vector fileSystemColorCodesFromSettings(); } -QString suCommand(); - #endif