File indexing completed on 2024-04-28 05:46:34
0001 /* 0002 SPDX-FileCopyrightText: 2008-2012 Volker Lanz <vl@fidra.de> 0003 SPDX-FileCopyrightText: 2013-2020 Andrius Štikonas <andrius@stikonas.eu> 0004 SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org> 0005 SPDX-FileCopyrightText: 2016 Chantara Tith <tith.chantara@gmail.com> 0006 SPDX-FileCopyrightText: 2018 Caio Jordão Carvalho <caiojcarvalho@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-3.0-or-later 0009 */ 0010 0011 #include "gui/newdialog.h" 0012 #include "gui/sizedialogwidget.h" 0013 #include "gui/sizedetailswidget.h" 0014 0015 #include <core/partition.h> 0016 #include <core/device.h> 0017 0018 #include <fs/filesystemfactory.h> 0019 #include <fs/luks.h> 0020 0021 #include <util/capacity.h> 0022 #include <util/helpers.h> 0023 #include "util/guihelpers.h" 0024 0025 #include <utility> 0026 0027 #include <QtGlobal> 0028 #include <QFontDatabase> 0029 #include <QPalette> 0030 0031 #include <KColorScheme> 0032 #include <KConfigGroup> 0033 #include <KLocalizedString> 0034 #include <KSharedConfig> 0035 0036 /** Creates a NewDialog 0037 @param parent the parent widget 0038 @param device the Device on which a new Partition is to be created 0039 @param unallocatedPartition the unallocated space on the Device to create a Partition in 0040 @param r the permitted Roles for the new Partition 0041 */ 0042 NewDialog::NewDialog(QWidget* parent, Device& device, Partition& unallocatedPartition, PartitionRole::Roles r) : 0043 SizeDialogBase(parent, device, unallocatedPartition, unallocatedPartition.firstSector(), unallocatedPartition.lastSector()), 0044 m_PartitionRoles(r), 0045 m_IsValidPassword(true) 0046 { 0047 setWindowTitle(xi18nc("@title:window", "Create a new partition")); 0048 0049 setupDialog(); 0050 setupConstraints(); 0051 setupConnections(); 0052 0053 updateOkButtonStatus(); 0054 0055 KConfigGroup kcg(KSharedConfig::openConfig(), QStringLiteral("newDialog")); 0056 restoreGeometry(kcg.readEntry<QByteArray>("Geometry", QByteArray())); 0057 } 0058 0059 NewDialog::~NewDialog() 0060 { 0061 KConfigGroup kcg(KSharedConfig::openConfig(), QStringLiteral("newDialog")); 0062 kcg.writeEntry("Geometry", saveGeometry()); 0063 } 0064 0065 void NewDialog::setupDialog() 0066 { 0067 QStringList fsNames; 0068 for (const auto &fs : FileSystemFactory::map()) { 0069 if (fs->supportCreate() != FileSystem::cmdSupportNone && 0070 fs->type() != FileSystem::Type::Extended && 0071 fs->type() != FileSystem::Type::Luks && 0072 fs->type() != FileSystem::Type::Luks2) 0073 fsNames.append(fs->name()); 0074 } 0075 0076 std::sort(fsNames.begin(), fsNames.end(), caseInsensitiveLessThan); 0077 0078 for (const auto &fsName : std::as_const(fsNames)) 0079 dialogWidget().comboFileSystem().addItem(createFileSystemColor(FileSystem::typeForName(fsName), 8), fsName); 0080 0081 QString selected = FileSystem::nameForType(GuiHelpers::defaultFileSystem()); 0082 const int idx = dialogWidget().comboFileSystem().findText(selected); 0083 dialogWidget().comboFileSystem().setCurrentIndex(idx != -1 ? idx : 0); 0084 0085 dialogWidget().radioPrimary().setVisible(partitionRoles() & PartitionRole::Primary); 0086 dialogWidget().radioExtended().setVisible(partitionRoles() & PartitionRole::Extended); 0087 dialogWidget().radioLogical().setVisible(partitionRoles() & PartitionRole::Logical); 0088 0089 if (partitionRoles() & PartitionRole::Primary) 0090 dialogWidget().radioPrimary().setChecked(true); 0091 else 0092 dialogWidget().radioLogical().setChecked(true); 0093 0094 SizeDialogBase::setupDialog(); 0095 0096 dialogWidget().checkBoxEncrypt().hide(); 0097 dialogWidget().editPassphrase().hide(); 0098 0099 if (device().type() == Device::Type::LVM_Device) { 0100 dialogWidget().comboFileSystem().removeItem(dialogWidget().comboFileSystem().findText(QStringLiteral("lvm2 pv"))); 0101 } 0102 0103 0104 dialogWidget().editPassphrase().setMinimumPasswordLength(1); 0105 dialogWidget().editPassphrase().setMaximumPasswordLength(512); // cryptsetup does not support longer passwords 0106 0107 // set a background warning color (taken from the current color scheme) 0108 KColorScheme colorScheme(QPalette::Active, KColorScheme::View); 0109 dialogWidget().editPassphrase().setBackgroundWarningColor(colorScheme.background(KColorScheme::NegativeBackground).color()); 0110 0111 0112 // don't move these above the call to parent's setupDialog, because only after that has 0113 // run there is a valid partition set in the part resizer widget and they will need that. 0114 onRoleChanged(false); 0115 onFilesystemChanged(dialogWidget().comboFileSystem().currentIndex()); 0116 0117 auto showPermissionsGroup = [this] { 0118 const QString currText = dialogWidget().comboFileSystem().currentText(); 0119 const bool enablePosixPermission = QList<QString>({ 0120 QStringLiteral("btrfs"), 0121 QStringLiteral("ext2"), 0122 QStringLiteral("ext3"), 0123 QStringLiteral("ext4"), 0124 QStringLiteral("f2fs"), 0125 QStringLiteral("hfsplus"), 0126 QStringLiteral("jfs"), 0127 QStringLiteral("minix"), 0128 QStringLiteral("ocfs2"), 0129 QStringLiteral("reiserfs"), 0130 QStringLiteral("reiser4"), 0131 QStringLiteral("udf"), 0132 QStringLiteral("xfs"), 0133 QStringLiteral("zfs"),} 0134 ).contains(currText); 0135 if (enablePosixPermission) { 0136 dialogWidget().showPosixPermissions(); 0137 } else { 0138 dialogWidget().hidePosixPermissions(); 0139 } 0140 }; 0141 connect(&dialogWidget().comboFileSystem(), QOverload<int>::of(&QComboBox::currentIndexChanged), this, showPermissionsGroup); 0142 showPermissionsGroup(); 0143 dialogWidget().radioRootPermissions().setChecked(true); 0144 } 0145 0146 void NewDialog::setupConnections() 0147 { 0148 connect(&dialogWidget().radioPrimary(), &QRadioButton::toggled, this, &NewDialog::onRoleChanged); 0149 connect(&dialogWidget().radioExtended(), &QRadioButton::toggled, this, &NewDialog::onRoleChanged); 0150 connect(&dialogWidget().radioLogical(), &QRadioButton::toggled, this, &NewDialog::onRoleChanged); 0151 connect(&dialogWidget().checkBoxEncrypt(), &QCheckBox::toggled, this, &NewDialog::onRoleChanged); 0152 connect(&dialogWidget().comboFileSystem(), &QComboBox::currentIndexChanged, this, &NewDialog::onFilesystemChanged); 0153 connect(&dialogWidget().label(), &QLineEdit::textChanged, this, &NewDialog::onLabelChanged); 0154 // listen to password status updates 0155 connect(&dialogWidget().editPassphrase(), &KNewPasswordWidget::passwordStatusChanged, this, &NewDialog::slotPasswordStatusChanged); 0156 0157 SizeDialogBase::setupConnections(); 0158 } 0159 0160 bool NewDialog::canMove() const 0161 { 0162 return (device().type() == Device::Type::LVM_Device) ? false : true; 0163 } 0164 0165 void NewDialog::accept() 0166 { 0167 if (partition().roles().has(PartitionRole::Extended)) { 0168 partition().deleteFileSystem(); 0169 partition().setFileSystem(FileSystemFactory::create(FileSystem::Type::Extended, 0170 partition().firstSector(), 0171 partition().lastSector(), 0172 partition().sectorSize())); 0173 } 0174 else if (partition().roles().has(PartitionRole::Luks)) { 0175 FileSystem::Type innerFsType = partition().fileSystem().type(); 0176 partition().deleteFileSystem(); 0177 FS::luks* luksFs = dynamic_cast< FS::luks* >( 0178 FileSystemFactory::create(FileSystem::Type::Luks, 0179 partition().firstSector(), 0180 partition().lastSector(), 0181 partition().sectorSize())); 0182 luksFs->createInnerFileSystem(innerFsType); 0183 luksFs->setPassphrase(dialogWidget().editPassphrase().password()); 0184 partition().setFileSystem(luksFs); 0185 partition().fileSystem().setLabel(dialogWidget().label().text()); 0186 } 0187 0188 QDialog::accept(); 0189 } 0190 0191 void NewDialog::onRoleChanged(bool) 0192 { 0193 PartitionRole::Roles r = PartitionRole::None; 0194 0195 if (dialogWidget().radioPrimary().isChecked()) 0196 r = PartitionRole::Primary; 0197 else if (dialogWidget().radioExtended().isChecked()) 0198 r = PartitionRole::Extended; 0199 else if (dialogWidget().radioLogical().isChecked()) 0200 r = PartitionRole::Logical; 0201 0202 bool doEncrypt = dialogWidget().checkBoxEncrypt().isVisible() && 0203 dialogWidget().checkBoxEncrypt().isChecked(); 0204 if (doEncrypt) 0205 r |= PartitionRole::Luks; 0206 0207 dialogWidget().editPassphrase().setVisible(doEncrypt); 0208 0209 // Make sure an extended partition gets correctly displayed: Set its file system to extended. 0210 // Also make sure to set a primary's or logical's file system once the user goes back from 0211 // extended to any of those. 0212 if (r == PartitionRole::Extended) 0213 updateFileSystem(FileSystem::Type::Extended); 0214 else 0215 updateFileSystem(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText())); 0216 0217 dialogWidget().comboFileSystem().setEnabled(r != PartitionRole::Extended); 0218 partition().setRoles(PartitionRole(r)); 0219 0220 setupConstraints(); 0221 0222 dialogWidget().partResizerWidget().resizeLogicals(0, 0, true); 0223 dialogWidget().partResizerWidget().update(); 0224 0225 updateHideAndShow(); 0226 } 0227 0228 void NewDialog::updateFileSystem(FileSystem::Type t) 0229 { 0230 partition().deleteFileSystem(); 0231 partition().setFileSystem(FileSystemFactory::create(t, partition().firstSector(), partition().lastSector(), partition().sectorSize())); 0232 } 0233 0234 void NewDialog::onFilesystemChanged(int idx) 0235 { 0236 updateFileSystem(FileSystem::typeForName(dialogWidget().comboFileSystem().itemText(idx))); 0237 0238 setupConstraints(); 0239 updateOkButtonStatus(); 0240 0241 const FileSystem* fs = FileSystemFactory::create(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText()), -1, -1, -1, -1, QString()); 0242 dialogWidget().m_EditLabel->setMaxLength(fs->maxLabelLength()); 0243 dialogWidget().m_EditLabel->setValidator(fs->labelValidator(dialogWidget().m_EditLabel)); 0244 0245 updateSpinCapacity(partition().length()); 0246 dialogWidget().partResizerWidget().update(); 0247 0248 updateHideAndShow(); 0249 } 0250 0251 void NewDialog::onLabelChanged(const QString& newLabel) 0252 { 0253 partition().fileSystem().setLabel(newLabel); 0254 } 0255 0256 void NewDialog::slotPasswordStatusChanged() 0257 { 0258 // You may want to extend this switch with more cases, 0259 // in order to warn the user about all the possible password issues. 0260 switch (dialogWidget().editPassphrase().passwordStatus()) { 0261 case KNewPasswordWidget::WeakPassword: 0262 case KNewPasswordWidget::StrongPassword: 0263 m_IsValidPassword = true; 0264 break; 0265 default: 0266 m_IsValidPassword = false; 0267 break; 0268 } 0269 updateOkButtonStatus(); 0270 } 0271 0272 void NewDialog::updateHideAndShow() 0273 { 0274 // this is mostly copy'n'pasted from PartPropsDialog::updateHideAndShow() 0275 if (partition().roles().has(PartitionRole::Extended) || 0276 (partition().fileSystem().supportSetLabel() == FileSystem::cmdSupportNone && 0277 partition().fileSystem().supportCreateWithLabel() == FileSystem::cmdSupportNone) ) 0278 { 0279 dialogWidget().label().setReadOnly(true); 0280 dialogWidget().noSetLabel().setVisible(true); 0281 dialogWidget().noSetLabel().setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); 0282 0283 QPalette palette = dialogWidget().noSetLabel().palette(); 0284 QColor f = palette.color(QPalette::WindowText); 0285 f.setAlpha(128); 0286 palette.setColor(QPalette::WindowText, f); 0287 dialogWidget().noSetLabel().setPalette(palette); 0288 dialogWidget().checkBoxEncrypt().hide(); 0289 dialogWidget().editPassphrase().hide(); 0290 } else { 0291 dialogWidget().label().setReadOnly(false); 0292 dialogWidget().noSetLabel().setVisible(false); 0293 } 0294 if (FileSystemFactory::map()[FileSystem::Type::Luks]->supportCreate() && FS::luks::canEncryptType(FileSystem::typeForName(dialogWidget().comboFileSystem().currentText())) && !partition().roles().has(PartitionRole::Extended)) 0295 { 0296 dialogWidget().checkBoxEncrypt().show(); 0297 if (dialogWidget().checkBoxEncrypt().isChecked()) 0298 { 0299 dialogWidget().editPassphrase().show(); 0300 slotPasswordStatusChanged(); 0301 } 0302 } 0303 else 0304 { 0305 dialogWidget().checkBoxEncrypt().hide(); 0306 dialogWidget().editPassphrase().hide(); 0307 } 0308 0309 } 0310 0311 void NewDialog::updateOkButtonStatus() 0312 { 0313 okButton->setEnabled(isValidPassword() && isValidLVName()); 0314 } 0315 0316 bool NewDialog::useUnsecuredPartition() const 0317 { 0318 return !dialogWidget().isPermissionOnlyRoot(); 0319 }