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"