File indexing completed on 2024-05-19 09:43:59
0001 /* 0002 SPDX-FileCopyrightText: 2009 Harald Hvaal <haraldhv@stud.ntnu.no> 0003 0004 SPDX-License-Identifier: BSD-2-Clause 0005 */ 0006 0007 #include "extractiondialog.h" 0008 #include "ark_debug.h" 0009 #include "settings.h" 0010 0011 #include <KDirOperator> 0012 #include <KLocalizedString> 0013 #include <KMessageBox> 0014 #include <KUrlComboBox> 0015 #include <KWindowConfig> 0016 0017 #include <QDir> 0018 #include <QPushButton> 0019 0020 #include "ui_extractiondialog.h" 0021 0022 namespace Kerfuffle 0023 { 0024 class ExtractionDialogUI : public QFrame, public Ui::ExtractionDialog 0025 { 0026 Q_OBJECT 0027 0028 public: 0029 ExtractionDialogUI(QWidget *parent = nullptr) 0030 : QFrame(parent) 0031 { 0032 setupUi(this); 0033 } 0034 }; 0035 0036 ExtractionDialog::ExtractionDialog(QWidget *parent) 0037 : QDialog(parent, Qt::Dialog) 0038 0039 { 0040 setWindowTitle(i18nc("@title:window", "Extract")); 0041 0042 QHBoxLayout *hlayout = new QHBoxLayout(); 0043 setLayout(hlayout); 0044 0045 fileWidget = new KFileWidget(QUrl::fromLocalFile(QDir::homePath()), this); 0046 hlayout->addWidget(fileWidget); 0047 0048 fileWidget->setMode(KFile::Directory | KFile::LocalOnly | KFile::ExistingOnly); 0049 fileWidget->setOperationMode(KFileWidget::Saving); 0050 0051 // This signal is emitted e.g. when the user presses Return while in the location bar. 0052 connect(fileWidget, &KFileWidget::accepted, this, &ExtractionDialog::slotAccepted); 0053 0054 fileWidget->okButton()->setText(i18n("Extract")); 0055 fileWidget->okButton()->show(); 0056 connect(fileWidget->okButton(), &QPushButton::clicked, this, &ExtractionDialog::slotAccepted); 0057 0058 fileWidget->cancelButton()->show(); 0059 connect(fileWidget->cancelButton(), &QPushButton::clicked, this, &QDialog::reject); 0060 0061 m_ui = new ExtractionDialogUI(this); 0062 hlayout->addWidget(m_ui); 0063 0064 m_ui->iconLabel->setPixmap(QIcon::fromTheme(QStringLiteral("archive-extract")).pixmap(48)); 0065 0066 m_ui->filesToExtractGroupBox->hide(); 0067 m_ui->allFilesButton->setChecked(true); 0068 m_ui->extractAllLabel->show(); 0069 0070 m_ui->autoSubfolders->hide(); 0071 0072 loadSettings(); 0073 0074 connect(this, &QDialog::finished, this, &ExtractionDialog::writeSettings); 0075 } 0076 0077 void ExtractionDialog::slotAccepted() 0078 { 0079 // If an item is selected, enter it if it exists and is a dir. 0080 if (!fileWidget->dirOperator()->selectedItems().isEmpty()) { 0081 QFileInfo fi(fileWidget->dirOperator()->selectedItems().urlList().first().path()); 0082 if (fi.isDir() && fi.exists()) { 0083 fileWidget->locationEdit()->clear(); 0084 fileWidget->setUrl(QUrl::fromLocalFile(fi.absoluteFilePath())); 0085 } 0086 return; 0087 } 0088 0089 // We extract to baseUrl(). 0090 const QString destinationPath = fileWidget->baseUrl().path(); 0091 0092 // If extracting to a subfolder, we need to do some checks. 0093 if (extractToSubfolder()) { 0094 // Check if subfolder contains slashes. 0095 if (subfolder().contains(QLatin1String("/"))) { 0096 KMessageBox::error(this, i18n("The subfolder name may not contain the character '/'.")); 0097 return; 0098 } 0099 0100 // Handle existing subfolder. 0101 const QString pathWithSubfolder = destinationPath + subfolder(); 0102 while (1) { 0103 if (QDir(pathWithSubfolder).exists()) { 0104 if (QFileInfo(pathWithSubfolder).isDir()) { 0105 int overwrite = KMessageBox::questionTwoActionsCancel( 0106 this, 0107 xi18nc("@info", "The folder <filename>%1</filename> already exists. Are you sure you want to extract here?", pathWithSubfolder), 0108 i18n("Folder exists"), 0109 KGuiItem(i18n("Extract here")), 0110 KGuiItem(i18n("Retry"))); 0111 0112 if (overwrite == KMessageBox::SecondaryAction) { 0113 // The user clicked Retry. 0114 continue; 0115 } else if (overwrite == KMessageBox::Cancel) { 0116 return; 0117 } 0118 } else { 0119 KMessageBox::detailedError(this, 0120 xi18nc("@info", "The folder <filename>%1</filename> could not be created.", subfolder()), 0121 xi18nc("@info", "<filename>%1</filename> already exists, but is not a folder.", subfolder())); 0122 return; 0123 } 0124 } else if (!QDir().mkdir(pathWithSubfolder)) { 0125 KMessageBox::detailedError(this, 0126 xi18nc("@info", "The folder <filename>%1</filename> could not be created.", subfolder()), 0127 i18n("Please check your permissions to create it.")); 0128 return; 0129 } 0130 break; 0131 } 0132 } 0133 0134 // Add new destination value to arkrc for quickExtractMenu. 0135 KConfigGroup conf(KSharedConfig::openConfig(), QStringLiteral("ExtractDialog")); 0136 QStringList destHistory = conf.readPathEntry("DirHistory", QStringList()); 0137 destHistory.prepend(destinationPath); 0138 destHistory.removeDuplicates(); 0139 if (destHistory.size() > 10) { 0140 destHistory.removeLast(); 0141 } 0142 conf.writePathEntry("DirHistory", destHistory); 0143 0144 fileWidget->accept(); 0145 accept(); 0146 } 0147 0148 void ExtractionDialog::loadSettings() 0149 { 0150 setOpenDestinationFolderAfterExtraction(ArkSettings::openDestinationFolderAfterExtraction()); 0151 setCloseAfterExtraction(ArkSettings::closeAfterExtraction()); 0152 setPreservePaths(ArkSettings::preservePaths()); 0153 } 0154 0155 void ExtractionDialog::setExtractToSubfolder(bool extractToSubfolder) 0156 { 0157 m_ui->singleFolderGroup->setChecked(extractToSubfolder && ArkSettings::extractToSubfolder()); 0158 } 0159 0160 void ExtractionDialog::batchModeOption() 0161 { 0162 m_ui->autoSubfolders->show(); 0163 m_ui->autoSubfolders->setEnabled(true); 0164 m_ui->singleFolderGroup->hide(); 0165 m_ui->extractAllLabel->setText(i18n("Extract multiple archives")); 0166 } 0167 0168 void ExtractionDialog::setSubfolder(const QString &subfolder) 0169 { 0170 m_ui->subfolder->setText(subfolder); 0171 } 0172 0173 QString ExtractionDialog::subfolder() const 0174 { 0175 return m_ui->subfolder->text(); 0176 } 0177 0178 void ExtractionDialog::setBusyGui() 0179 { 0180 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0181 fileWidget->setEnabled(false); 0182 m_ui->setEnabled(false); 0183 // TODO: tell the user why the dialog is busy (e.g. "archive is being loaded"). 0184 } 0185 0186 void ExtractionDialog::setReadyGui() 0187 { 0188 QApplication::restoreOverrideCursor(); 0189 fileWidget->setEnabled(true); 0190 m_ui->setEnabled(true); 0191 } 0192 0193 ExtractionDialog::~ExtractionDialog() 0194 { 0195 delete m_ui; 0196 m_ui = nullptr; 0197 } 0198 0199 void ExtractionDialog::setShowSelectedFiles(bool value) 0200 { 0201 if (value) { 0202 m_ui->filesToExtractGroupBox->show(); 0203 m_ui->gridLayout->removeItem(m_ui->gridLayoutVerticalSpacer); 0204 delete m_ui->gridLayoutVerticalSpacer; 0205 m_ui->selectedFilesButton->setChecked(true); 0206 m_ui->extractAllLabel->hide(); 0207 } else { 0208 m_ui->filesToExtractGroupBox->hide(); 0209 m_ui->gridLayout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding), 6, 0); 0210 m_ui->selectedFilesButton->setChecked(false); 0211 m_ui->extractAllLabel->show(); 0212 } 0213 } 0214 0215 bool ExtractionDialog::extractAllFiles() const 0216 { 0217 return m_ui->allFilesButton->isChecked(); 0218 } 0219 0220 void ExtractionDialog::setAutoSubfolder(bool value) 0221 { 0222 m_ui->autoSubfolders->setChecked(value); 0223 } 0224 0225 bool ExtractionDialog::autoSubfolders() const 0226 { 0227 return m_ui->autoSubfolders->isChecked(); 0228 } 0229 0230 bool ExtractionDialog::extractToSubfolder() const 0231 { 0232 return m_ui->singleFolderGroup->isChecked(); 0233 } 0234 0235 void ExtractionDialog::setOpenDestinationFolderAfterExtraction(bool value) 0236 { 0237 m_ui->openFolderCheckBox->setChecked(value); 0238 } 0239 0240 void ExtractionDialog::setCloseAfterExtraction(bool value) 0241 { 0242 m_ui->closeAfterExtraction->setChecked(value); 0243 } 0244 0245 void ExtractionDialog::setPreservePaths(bool value) 0246 { 0247 m_ui->preservePaths->setChecked(value); 0248 } 0249 0250 bool ExtractionDialog::preservePaths() const 0251 { 0252 return m_ui->preservePaths->isChecked(); 0253 } 0254 0255 bool ExtractionDialog::openDestinationAfterExtraction() const 0256 { 0257 return m_ui->openFolderCheckBox->isChecked(); 0258 } 0259 0260 bool ExtractionDialog::closeAfterExtraction() const 0261 { 0262 return m_ui->closeAfterExtraction->isChecked(); 0263 } 0264 0265 QUrl ExtractionDialog::destinationDirectory() const 0266 { 0267 if (extractToSubfolder()) { 0268 QUrl subUrl = fileWidget->baseUrl(); 0269 if (subUrl.path().endsWith(QDir::separator())) { 0270 subUrl.setPath(subUrl.path() + subfolder()); 0271 } else { 0272 subUrl.setPath(subUrl.path() + QDir::separator() + subfolder()); 0273 } 0274 0275 return subUrl; 0276 } else { 0277 return fileWidget->baseUrl(); 0278 } 0279 } 0280 0281 void ExtractionDialog::writeSettings() 0282 { 0283 ArkSettings::setOpenDestinationFolderAfterExtraction(openDestinationAfterExtraction()); 0284 ArkSettings::setCloseAfterExtraction(closeAfterExtraction()); 0285 ArkSettings::setPreservePaths(preservePaths()); 0286 ArkSettings::self()->save(); 0287 0288 // Save dialog window size 0289 KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("ExtractDialog")); 0290 KWindowConfig::saveWindowSize(windowHandle(), group, KConfigBase::Persistent); 0291 } 0292 0293 void ExtractionDialog::setCurrentUrl(const QUrl &url) 0294 { 0295 fileWidget->setUrl(url); 0296 } 0297 0298 void ExtractionDialog::restoreWindowSize() 0299 { 0300 // Restore window size from config file, needs a windowHandle so must be called after show() 0301 KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("ExtractDialog")); 0302 KWindowConfig::restoreWindowSize(windowHandle(), group); 0303 } 0304 0305 } 0306 0307 #include "extractiondialog.moc" 0308 #include "moc_extractiondialog.cpp"