diff --git a/src/gui/devicepropsdialog.cpp b/src/gui/devicepropsdialog.cpp index f925911..342bd77 100644 --- a/src/gui/devicepropsdialog.cpp +++ b/src/gui/devicepropsdialog.cpp @@ -1,172 +1,172 @@ /************************************************************************* * 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()); 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 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/infopane.cpp b/src/gui/infopane.cpp index dce3c28..b749719 100644 --- a/src/gui/infopane.cpp +++ b/src/gui/infopane.cpp @@ -1,205 +1,205 @@ /************************************************************************* * 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 /** 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::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::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) { + if (d.type() == Device::Type::Disk_Device) { const DiskDevice& disk = dynamic_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) { + } else if (d.type() == Device::Type::LVM_Device) { const LvmDevice& lvm = dynamic_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); } } 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 107a6f2..dbc8aff 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1,1318 +1,1318 @@ /************************************************************************* * 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 "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(); 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); CoreBackendManager::stopExternalCommandHelper(); } 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); 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); 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)", 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)); 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) 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)); 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); operationStack().push(new NewOperation(device, p)); } else Log(Log::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()); 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); 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 4dc5003..dda216e 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::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::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::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::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) ) { 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 1f5b874..3c8243d 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::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)); else if (shred && Config::shredSource() == Config::EnumShredSource::zeros) operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::ZeroShred)); else operationStack().push(new DeleteOperation(*selectedDevice(), selectedPartition(), DeleteOperation::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()); 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/resizedialog.cpp b/src/gui/resizedialog.cpp index 886e614..6ab5aa8 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) { 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/sizedialogbase.cpp b/src/gui/sizedialogbase.cpp index 7a2d499..02e89b2 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(); } diff --git a/src/partitionmanager.kcfg b/src/partitionmanager.kcfg index 7d5992c..8c858fc 100644 --- a/src/partitionmanager.kcfg +++ b/src/partitionmanager.kcfg @@ -1,156 +1,156 @@ fs/filesystem.h util/capacity.h true 0 2048 false true 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 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 true - static_cast<int>(FileSystem::Type::Ext4) + static_cast<int>(FileSystem::Type::Ext4) Capacity::Byte Capacity::KiB Capacity::MiB Capacity::GiB Capacity::TiB Capacity::PiB Capacity::EiB Capacity::MiB random