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