File indexing completed on 2024-06-23 05:14:18

0001 /*  utils/overwritedialog.cpp
0002 
0003     This file is part of Kleopatra, the KDE keymanager
0004     SPDX-FileCopyrightText: 2023 g10 Code GmbH
0005     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-kleopatra.h>
0011 
0012 #include "overwritedialog.h"
0013 
0014 #include <QFileInfo>
0015 #include <QHBoxLayout>
0016 #include <QLabel>
0017 #include <QLineEdit>
0018 #include <QMimeDatabase>
0019 #include <QPushButton>
0020 #include <QVBoxLayout>
0021 
0022 #include <KFileUtils>
0023 #include <KGuiItem>
0024 #include <KLocalizedString>
0025 #include <KMessageBox>
0026 #include <KSeparator>
0027 #include <KStandardGuiItem>
0028 
0029 using namespace Kleo;
0030 
0031 class OverwriteDialog::Private
0032 {
0033     Kleo::OverwriteDialog *q;
0034 
0035 public:
0036     Private(const QString &filePath, Kleo::OverwriteDialog *qq)
0037         : q{qq}
0038         , fileInfo{filePath}
0039     {
0040     }
0041 
0042     void setRenameBoxText(const QString &fileName);
0043     void enableRenameButton(const QString &newName);
0044     void suggestNewNamePressed();
0045     QString newFileName() const;
0046 
0047     void renamePressed();
0048     void renameAllPressed();
0049     void skipPressed();
0050     void skipAllPressed();
0051     void overwritePressed();
0052     void overwriteAllPressed();
0053     void cancelPressed();
0054 
0055     void done(Result result)
0056     {
0057         q->done(static_cast<int>(result));
0058     }
0059 
0060     QLineEdit *newNameEdit = nullptr;
0061     QPushButton *suggestNewNameBtn = nullptr;
0062     QPushButton *renameBtn = nullptr;
0063     QPushButton *renameAllBtn = nullptr;
0064     QPushButton *skipBtn = nullptr;
0065     QPushButton *skipAllBtn = nullptr;
0066     QPushButton *overwriteBtn = nullptr;
0067     QPushButton *overwriteAllBtn = nullptr;
0068     QPushButton *cancelBtn = nullptr;
0069     QFileInfo fileInfo;
0070 };
0071 
0072 void OverwriteDialog::Private::setRenameBoxText(const QString &fileName)
0073 {
0074     // sets the text in file name line edit box, selecting the filename (but not the extension if there is one).
0075     QMimeDatabase db;
0076     const auto extension = db.suffixForFileName(fileName);
0077     newNameEdit->setText(fileName);
0078 
0079     if (!extension.isEmpty()) {
0080         const int selectionLength = fileName.length() - extension.length() - 1;
0081         newNameEdit->setSelection(0, selectionLength);
0082     } else {
0083         newNameEdit->selectAll();
0084     }
0085 }
0086 
0087 void OverwriteDialog::Private::enableRenameButton(const QString &newName)
0088 {
0089     if (!newName.isEmpty() && (newName != fileInfo.fileName())) {
0090         renameBtn->setEnabled(true);
0091         renameBtn->setDefault(true);
0092 
0093         if (renameAllBtn) {
0094             renameAllBtn->setEnabled(false);
0095         }
0096         if (overwriteBtn) {
0097             overwriteBtn->setEnabled(false);
0098         }
0099         if (overwriteAllBtn) {
0100             overwriteAllBtn->setEnabled(false);
0101         }
0102     } else {
0103         renameBtn->setEnabled(false);
0104 
0105         if (renameAllBtn) {
0106             renameAllBtn->setEnabled(true);
0107         }
0108         if (overwriteBtn) {
0109             overwriteBtn->setEnabled(true);
0110         }
0111         if (overwriteAllBtn) {
0112             overwriteAllBtn->setEnabled(true);
0113         }
0114     }
0115 }
0116 
0117 void OverwriteDialog::Private::suggestNewNamePressed()
0118 {
0119     if (!newNameEdit->text().isEmpty()) {
0120         setRenameBoxText(KFileUtils::suggestName(QUrl::fromLocalFile(fileInfo.absolutePath()), newNameEdit->text()));
0121     } else {
0122         setRenameBoxText(KFileUtils::suggestName(QUrl::fromLocalFile(fileInfo.absolutePath()), fileInfo.fileName()));
0123     }
0124 }
0125 
0126 QString OverwriteDialog::Private::newFileName() const
0127 {
0128     return fileInfo.path() + QLatin1Char{'/'} + newNameEdit->text();
0129 }
0130 
0131 void OverwriteDialog::Private::renamePressed()
0132 {
0133     if (newNameEdit->text().isEmpty()) {
0134         return;
0135     }
0136     const auto fileName = newFileName();
0137     if (QFileInfo::exists(fileName)) {
0138         KMessageBox::error(q, xi18nc("@info", "The file <filename>%1</filename> already exists. Please enter a different file name.", fileName));
0139         return;
0140     }
0141     done(Result::Rename);
0142 }
0143 
0144 void OverwriteDialog::Private::renameAllPressed()
0145 {
0146     done(Result::AutoRename);
0147 }
0148 
0149 void OverwriteDialog::Private::skipPressed()
0150 {
0151     done(Result::Skip);
0152 }
0153 
0154 void OverwriteDialog::Private::skipAllPressed()
0155 {
0156     done(Result::AutoSkip);
0157 }
0158 
0159 void OverwriteDialog::Private::overwritePressed()
0160 {
0161     done(Result::Overwrite);
0162 }
0163 
0164 void OverwriteDialog::Private::overwriteAllPressed()
0165 {
0166     done(Result::OverwriteAll);
0167 }
0168 
0169 void OverwriteDialog::Private::cancelPressed()
0170 {
0171     done(Result::Cancel);
0172 }
0173 
0174 OverwriteDialog::OverwriteDialog(QWidget *parent, const QString &title, const QString &fileName, Options options)
0175     : QDialog{parent}
0176     , d{new Private{fileName, this}}
0177 {
0178     setObjectName(QLatin1StringView("Kleo::OverwriteDialog"));
0179 
0180     setWindowTitle(title);
0181 
0182     auto mainLayout = new QVBoxLayout{this};
0183     mainLayout->addStrut(400); // makes dlg at least that wide
0184 
0185     mainLayout->addWidget(new QLabel{xi18nc("@info", "The file <filename>%1</filename> already exists.", fileName), this});
0186 
0187     if (options & AllowRename) {
0188         mainLayout->addSpacing(15);
0189 
0190         auto label = new QLabel{i18nc("@label", "Rename:"), this};
0191         mainLayout->addWidget(label);
0192 
0193         auto hbox = new QHBoxLayout;
0194 
0195         d->newNameEdit = new QLineEdit{this};
0196         label->setBuddy(d->newNameEdit);
0197         hbox->addWidget(d->newNameEdit);
0198 
0199         d->suggestNewNameBtn = new QPushButton{i18nc("@action:button", "Suggest New Name"), this};
0200         d->suggestNewNameBtn->setToolTip(i18nc("@info:tooltip", "Suggest a file name that does not already exist."));
0201         hbox->addWidget(d->suggestNewNameBtn);
0202 
0203         mainLayout->addLayout(hbox);
0204     }
0205 
0206     mainLayout->addWidget(new KSeparator{this});
0207 
0208     auto buttonLayout = new QHBoxLayout;
0209 
0210     if (options & AllowRename) {
0211         d->renameBtn = new QPushButton{i18nc("@action:button", "Rename"), this};
0212         d->renameBtn->setToolTip(i18nc("@info:tooltip", "Save the file with the given name."));
0213         d->renameBtn->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename")));
0214         d->renameBtn->setEnabled(false);
0215         buttonLayout->addWidget(d->renameBtn);
0216 
0217         if (options & MultipleItems) {
0218             d->renameAllBtn = new QPushButton{i18nc("@action:button", "Rename All"), this};
0219             d->renameAllBtn->setIcon(d->renameBtn->icon());
0220             d->renameAllBtn->setToolTip(
0221                 i18nc("@info:tooltip", "Automatically save all files that would overwrite an already existing file with a different name."));
0222             buttonLayout->addWidget(d->renameAllBtn);
0223         }
0224     }
0225 
0226     if ((options & AllowSkip) && (options & MultipleItems)) {
0227         d->skipBtn = new QPushButton{i18nc("@action:button", "Skip"), this};
0228         d->skipBtn->setIcon(QIcon::fromTheme(QStringLiteral("go-next-skip")));
0229         d->skipBtn->setToolTip(i18nc("@info:tooltip", "Do not write this file, skip to the next one instead."));
0230         buttonLayout->addWidget(d->skipBtn);
0231 
0232         d->skipAllBtn = new QPushButton{i18nc("@action:button", "Skip All"), this};
0233         d->skipAllBtn->setIcon(d->skipBtn->icon());
0234         d->skipAllBtn->setToolTip(i18nc("@info:tooltip", "Do not write this file and any other files that would overwrite an already existing file."));
0235         buttonLayout->addWidget(d->skipAllBtn);
0236     }
0237 
0238     d->overwriteBtn = new QPushButton{i18nc("@action:button", "Overwrite"), this};
0239     d->overwriteBtn->setIcon(KStandardGuiItem::overwrite().icon());
0240     d->overwriteBtn->setToolTip(i18nc("@info:tooltip", "Overwrite the existing file."));
0241     buttonLayout->addWidget(d->overwriteBtn);
0242 
0243     if (options & MultipleItems) {
0244         d->overwriteAllBtn = new QPushButton{i18nc("@action:button", "Overwrite All"), this};
0245         d->overwriteAllBtn->setIcon(d->overwriteBtn->icon());
0246         d->overwriteAllBtn->setToolTip(i18nc("@info:tooltip", "Overwrite the existing file and any other files that already exist."));
0247         buttonLayout->addWidget(d->overwriteAllBtn);
0248     }
0249 
0250     d->cancelBtn = new QPushButton{this};
0251     KGuiItem::assign(d->cancelBtn, KStandardGuiItem::cancel());
0252     d->cancelBtn->setDefault(true);
0253     buttonLayout->addWidget(d->cancelBtn);
0254 
0255     mainLayout->addLayout(buttonLayout);
0256 
0257     if (d->newNameEdit) {
0258         d->setRenameBoxText(d->fileInfo.fileName());
0259         connect(d->newNameEdit, &QLineEdit::textChanged, this, [this](const QString &text) {
0260             d->enableRenameButton(text);
0261         });
0262         connect(d->suggestNewNameBtn, &QAbstractButton::clicked, this, [this]() {
0263             d->suggestNewNamePressed();
0264         });
0265     }
0266     if (d->renameBtn) {
0267         connect(d->renameBtn, &QAbstractButton::clicked, this, [this]() {
0268             d->renamePressed();
0269         });
0270     }
0271     if (d->renameAllBtn) {
0272         connect(d->renameAllBtn, &QAbstractButton::clicked, this, [this]() {
0273             d->renameAllPressed();
0274         });
0275     }
0276     if (d->skipBtn) {
0277         connect(d->skipBtn, &QAbstractButton::clicked, this, [this]() {
0278             d->skipPressed();
0279         });
0280         connect(d->skipAllBtn, &QAbstractButton::clicked, this, [this]() {
0281             d->skipAllPressed();
0282         });
0283     }
0284     connect(d->overwriteBtn, &QAbstractButton::clicked, this, [this]() {
0285         d->overwritePressed();
0286     });
0287     if (d->overwriteAllBtn) {
0288         connect(d->overwriteAllBtn, &QAbstractButton::clicked, this, [this]() {
0289             d->overwriteAllPressed();
0290         });
0291     }
0292     connect(d->cancelBtn, &QAbstractButton::clicked, this, [this]() {
0293         d->cancelPressed();
0294     });
0295 
0296     if (d->newNameEdit) {
0297         d->newNameEdit->setFocus();
0298     }
0299 
0300     resize(sizeHint());
0301 }
0302 
0303 OverwriteDialog::~OverwriteDialog() = default;
0304 
0305 QString OverwriteDialog::newFileName() const
0306 {
0307     if (result() == Result::Rename) {
0308         return d->newFileName();
0309     }
0310     return {};
0311 }
0312 
0313 #include "moc_overwritedialog.cpp"