File indexing completed on 2024-12-22 05:01:03
0001 /* 0002 SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB 0003 SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "archivefolderdialog.h" 0009 0010 #include "kmmainwidget.h" 0011 #include <MailCommon/BackupJob> 0012 #include <MailCommon/FolderRequester> 0013 #include <MessageViewer/MessageViewerUtil> 0014 0015 #include <Akonadi/Collection> 0016 0017 #include <KLocalizedString> 0018 #include <KMessageBox> 0019 #include <KSeparator> 0020 #include <KUrlRequester> 0021 #include <QComboBox> 0022 0023 #include <QCheckBox> 0024 #include <QDialogButtonBox> 0025 #include <QGridLayout> 0026 #include <QLabel> 0027 #include <QMimeDatabase> 0028 #include <QPushButton> 0029 #include <QStandardPaths> 0030 #include <QVBoxLayout> 0031 0032 using namespace KMail; 0033 using namespace MailCommon; 0034 0035 QString ArchiveFolderDialog::standardArchivePath(const QString &folderName) 0036 { 0037 QString currentPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); 0038 const QDir dir(currentPath); 0039 if (!dir.exists()) { 0040 currentPath = QDir::homePath(); 0041 } 0042 return currentPath + QLatin1Char('/') + i18nc("Start of the filename for a mail archive file", "Archive") + QLatin1Char('_') + folderName + QLatin1Char('_') 0043 + QDate::currentDate().toString(Qt::ISODate) + QLatin1StringView(".tar.bz2"); 0044 } 0045 0046 ArchiveFolderDialog::ArchiveFolderDialog(QWidget *parent) 0047 : QDialog(parent) 0048 , mParentWidget(parent) 0049 { 0050 setObjectName(QLatin1StringView("archive_folder_dialog")); 0051 setWindowTitle(i18nc("@title:window for archiving a folder", "Archive Folder")); 0052 auto topLayout = new QVBoxLayout(this); 0053 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); 0054 mOkButton = buttonBox->button(QDialogButtonBox::Ok); 0055 mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0056 connect(buttonBox, &QDialogButtonBox::accepted, this, &ArchiveFolderDialog::slotAccepted); 0057 connect(buttonBox, &QDialogButtonBox::rejected, this, &ArchiveFolderDialog::reject); 0058 mOkButton->setDefault(true); 0059 mOkButton->setText(i18nc("@action", "Archive")); 0060 setModal(true); 0061 auto mainWidget = new QWidget(this); 0062 topLayout->addWidget(mainWidget); 0063 topLayout->addWidget(buttonBox); 0064 auto mainLayout = new QGridLayout(mainWidget); 0065 mainLayout->setContentsMargins({}); 0066 0067 int row = 0; 0068 0069 // TODO: Explanation label 0070 0071 auto folderLabel = new QLabel(i18n("&Folder:"), mainWidget); 0072 mainLayout->addWidget(folderLabel, row, 0); 0073 mFolderRequester = new FolderRequester(mainWidget); 0074 mFolderRequester->setMustBeReadWrite(false); 0075 mFolderRequester->setNotAllowToCreateNewFolder(true); 0076 connect(mFolderRequester, &FolderRequester::folderChanged, this, &ArchiveFolderDialog::slotFolderChanged); 0077 folderLabel->setBuddy(mFolderRequester); 0078 mainLayout->addWidget(mFolderRequester, row, 1); 0079 row++; 0080 0081 auto formatLabel = new QLabel(i18n("F&ormat:"), mainWidget); 0082 mainLayout->addWidget(formatLabel, row, 0); 0083 mFormatComboBox = new QComboBox(mainWidget); 0084 formatLabel->setBuddy(mFormatComboBox); 0085 0086 // These combobox values have to stay in sync with the ArchiveType enum from BackupJob! 0087 mFormatComboBox->addItem(i18n("Compressed Zip Archive (.zip)")); 0088 mFormatComboBox->addItem(i18n("Uncompressed Archive (.tar)")); 0089 mFormatComboBox->addItem(i18n("BZ2-Compressed Tar Archive (.tar.bz2)")); 0090 mFormatComboBox->addItem(i18n("GZ-Compressed Tar Archive (.tar.gz)")); 0091 mFormatComboBox->setCurrentIndex(2); 0092 connect(mFormatComboBox, &QComboBox::activated, this, &ArchiveFolderDialog::slotFixFileExtension); 0093 mainLayout->addWidget(mFormatComboBox, row, 1); 0094 row++; 0095 0096 auto fileNameLabel = new QLabel(i18n("&Archive File:"), mainWidget); 0097 mainLayout->addWidget(fileNameLabel, row, 0); 0098 mUrlRequester = new KUrlRequester(mainWidget); 0099 mUrlRequester->setMode(KFile::LocalOnly | KFile::File); 0100 mUrlRequester->setNameFilter(i18n("Archive file (*.tar *.zip *.tar.gz *.tar.bz2)")); 0101 fileNameLabel->setBuddy(mUrlRequester); 0102 connect(mUrlRequester, &KUrlRequester::urlSelected, this, &ArchiveFolderDialog::slotFixFileExtension); 0103 connect(mUrlRequester, &KUrlRequester::textChanged, this, &ArchiveFolderDialog::slotUrlChanged); 0104 mainLayout->addWidget(mUrlRequester, row, 1); 0105 row++; 0106 0107 // TODO: Make this appear more dangerous! 0108 mDeleteCheckBox = new QCheckBox(i18n("&Delete folder and subfolders after completion"), mainWidget); 0109 mainLayout->addWidget(mDeleteCheckBox, row, 0, 1, 2, Qt::AlignLeft); 0110 row++; 0111 0112 mRecursiveCheckBox = new QCheckBox(i18n("Archive all subfolders"), mainWidget); 0113 connect(mRecursiveCheckBox, &QCheckBox::clicked, this, &ArchiveFolderDialog::slotRecursiveCheckboxClicked); 0114 mainLayout->addWidget(mRecursiveCheckBox, row, 0, 1, 2, Qt::AlignLeft); 0115 mRecursiveCheckBox->setChecked(true); 0116 row++; 0117 0118 // TODO: what's this, tooltips 0119 0120 // TODO: Warn that user should do mail check for online IMAP and possibly cached IMAP as well 0121 0122 mainLayout->addWidget(new KSeparator(), row, 0, 1, 2); 0123 row++; 0124 mainLayout->setColumnStretch(1, 1); 0125 mainLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding), row, 0); 0126 0127 // Make it a bit bigger, else the folder requester cuts off the text too early 0128 resize(500, minimumSize().height()); 0129 } 0130 0131 bool canRemoveFolder(const Akonadi::Collection &col) 0132 { 0133 const QSharedPointer<FolderSettings> folder = FolderSettings::forCollection(col, false); 0134 return !folder.isNull() && col.isValid() && !col.isVirtual() && (col.rights() & Akonadi::Collection::CanDeleteCollection) && !folder->isStructural() 0135 && !folder->isSystemFolder(); 0136 } 0137 0138 void ArchiveFolderDialog::slotRecursiveCheckboxClicked() 0139 { 0140 slotFolderChanged(mFolderRequester->collection()); 0141 } 0142 0143 void ArchiveFolderDialog::slotFolderChanged(const Akonadi::Collection &folder) 0144 { 0145 mDeleteCheckBox->setEnabled(allowToDeleteFolders(folder)); 0146 } 0147 0148 bool ArchiveFolderDialog::allowToDeleteFolders(const Akonadi::Collection &folder) const 0149 { 0150 return canRemoveFolder(folder) && mRecursiveCheckBox->isChecked(); 0151 } 0152 0153 void ArchiveFolderDialog::setFolder(const Akonadi::Collection &defaultCollection) 0154 { 0155 mFolderRequester->setCollection(defaultCollection); 0156 // TODO: what if the file already exists? 0157 mUrlRequester->setUrl(QUrl::fromLocalFile(standardArchivePath(defaultCollection.name()))); 0158 const QSharedPointer<FolderSettings> folder = FolderSettings::forCollection(defaultCollection, false); 0159 mDeleteCheckBox->setEnabled(allowToDeleteFolders(defaultCollection)); 0160 mOkButton->setEnabled(defaultCollection.isValid() && folder && !folder->isStructural()); 0161 } 0162 0163 void ArchiveFolderDialog::slotAccepted() 0164 { 0165 if (!MessageViewer::Util::checkOverwrite(mUrlRequester->url(), this)) { 0166 return; 0167 } 0168 0169 if (!mFolderRequester->hasCollection()) { 0170 KMessageBox::information(this, i18n("Please select the folder that should be archived."), i18nc("@title:window", "No folder selected")); 0171 return; 0172 } 0173 0174 auto backupJob = new MailCommon::BackupJob(mParentWidget); 0175 backupJob->setRootFolder(mFolderRequester->collection()); 0176 backupJob->setSaveLocation(mUrlRequester->url()); 0177 backupJob->setArchiveType(static_cast<BackupJob::ArchiveType>(mFormatComboBox->currentIndex())); 0178 backupJob->setDeleteFoldersAfterCompletion(mDeleteCheckBox->isEnabled() && mDeleteCheckBox->isChecked()); 0179 backupJob->setRecursive(mRecursiveCheckBox->isChecked()); 0180 backupJob->start(); 0181 accept(); 0182 } 0183 0184 void ArchiveFolderDialog::slotFixFileExtension() 0185 { 0186 const int numExtensions = 4; 0187 // The extensions here are also sorted, like the enum order of BackupJob::ArchiveType 0188 const char *extensions[numExtensions] = {".zip", ".tar", ".tar.bz2", ".tar.gz"}; 0189 0190 QString fileName = mUrlRequester->url().path(); 0191 if (fileName.isEmpty()) { 0192 fileName = standardArchivePath(mFolderRequester->hasCollection() ? mFolderRequester->collection().name() : QString()); 0193 } 0194 0195 QMimeDatabase db; 0196 const QString extension = db.suffixForFileName(fileName); 0197 if (!extension.isEmpty()) { 0198 fileName.truncate(fileName.length() - extension.length() - 1); 0199 } 0200 0201 // Now, we've got a filename without an extension, simply append the correct one 0202 fileName += QLatin1StringView(extensions[mFormatComboBox->currentIndex()]); 0203 mUrlRequester->setUrl(QUrl::fromLocalFile(fileName)); 0204 } 0205 0206 void ArchiveFolderDialog::slotUrlChanged(const QString &url) 0207 { 0208 mOkButton->setEnabled(!url.isEmpty()); 0209 } 0210 0211 #include "moc_archivefolderdialog.cpp"