File indexing completed on 2024-04-21 04:18:47

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2009 Aurélien Gâteau <agateau@kde.org>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
0019 
0020 */
0021 // Self
0022 #include "importdialog.h"
0023 
0024 // Qt
0025 #include <QApplication>
0026 #include <QDate>
0027 #include <QStackedWidget>
0028 #include <QStandardPaths>
0029 
0030 // KF
0031 #include <KIO/ApplicationLauncherJob>
0032 #include <KIO/DeleteJob>
0033 #include <KIO/JobUiDelegate>
0034 #include <KIO/JobUiDelegateFactory>
0035 #include <KLocalizedString>
0036 #include <KMessageBox>
0037 #include <KProtocolInfo>
0038 #include <KService>
0039 #include <KStandardGuiItem>
0040 #include <Solid/Device>
0041 #include <kwidgetsaddons_version.h>
0042 
0043 // Local
0044 #include "dialogpage.h"
0045 #include "gwenview_importer_debug.h"
0046 #include "importer.h"
0047 #include "importerconfig.h"
0048 #include "progresspage.h"
0049 #include "thumbnailpage.h"
0050 
0051 namespace Gwenview
0052 {
0053 class ImportDialogPrivate
0054 {
0055 public:
0056     ImportDialog *q = nullptr;
0057     QStackedWidget *mCentralWidget = nullptr;
0058     ThumbnailPage *mThumbnailPage = nullptr;
0059     ProgressPage *mProgressPage = nullptr;
0060     DialogPage *mDialogPage = nullptr;
0061     Importer *mImporter = nullptr;
0062 
0063     void checkForFailedUrls()
0064     {
0065         // First check for errors on file imports or subfolder creation
0066         const QList<QUrl> failedUrls = mImporter->failedUrlList();
0067         const QList<QUrl> failedSubFolders = mImporter->failedSubFolderList();
0068         const int failedUrlCount = failedUrls.count();
0069         const int failedSubFolderCount = failedSubFolders.count();
0070         if (failedUrlCount + failedSubFolderCount > 0) {
0071             QStringList files, dirs;
0072             for (int i = 0; i < failedUrlCount; i++) {
0073                 files << failedUrls[i].toString(QUrl::PreferLocalFile);
0074             }
0075             for (int i = 0; i < failedSubFolderCount; i++) {
0076                 dirs << failedSubFolders[i].toString(QUrl::PreferLocalFile);
0077             }
0078             Q_EMIT q->showErrors(files, dirs);
0079         }
0080     }
0081 
0082     void deleteImportedUrls()
0083     {
0084         const QList<QUrl> importedUrls = mImporter->importedUrlList();
0085         const QList<QUrl> skippedUrls = mImporter->skippedUrlList();
0086         const int importedCount = importedUrls.count();
0087         const int skippedCount = skippedUrls.count();
0088 
0089         if (importedCount == 0 && skippedCount == 0) {
0090             return;
0091         }
0092 
0093         QStringList message;
0094         message << i18np("One document has been imported.", "%1 documents have been imported.", importedCount);
0095         if (skippedCount > 0) {
0096             message << i18np("One document has been skipped because it had already been imported.",
0097                              "%1 documents have been skipped because they had already been imported.",
0098                              skippedCount);
0099         }
0100 
0101         if (mImporter->renamedCount() > 0) {
0102             message[0].append(QStringLiteral("*"));
0103             message << QStringLiteral("<small>* ")
0104                     + i18np("One of them has been renamed because another document with the same name had already been imported.",
0105                             "%1 of them have been renamed because other documents with the same name had already been imported.",
0106                             mImporter->renamedCount())
0107                     + "</small>";
0108         }
0109 
0110         message << QString();
0111         if (skippedCount == 0) {
0112             message << i18np("Delete the imported document from the device?", "Delete the %1 imported documents from the device?", importedCount);
0113         } else if (importedCount == 0) {
0114             message << i18np("Delete the skipped document from the device?", "Delete the %1 skipped documents from the device?", skippedCount);
0115         } else {
0116             message << i18ncp("Singular sentence is actually never used.",
0117                               "Delete the imported or skipped document from the device?",
0118                               "Delete the %1 imported and skipped documents from the device?",
0119                               importedCount + skippedCount);
0120         }
0121 
0122         int answer = KMessageBox::questionTwoActions(mCentralWidget,
0123                                                      QStringLiteral("<qt>") + message.join(QStringLiteral("<br/>")) + QStringLiteral("</qt>"),
0124                                                      i18nc("@title:window", "Import Finished"),
0125                                                      KGuiItem(i18n("Keep")),
0126                                                      KStandardGuiItem::del());
0127         if (answer == KMessageBox::PrimaryAction) {
0128             return;
0129         }
0130         QList<QUrl> urls = importedUrls + skippedUrls;
0131         while (true) {
0132             KIO::Job *job = KIO::del(urls);
0133             if (job->exec()) {
0134                 break;
0135             }
0136             // Deleting failed
0137             int answer =
0138                 KMessageBox::warningTwoActions(mCentralWidget,
0139                                                i18np("Failed to delete the document:\n%2", "Failed to delete documents:\n%2", urls.count(), job->errorString()),
0140                                                QString(),
0141                                                KGuiItem(i18n("Retry")),
0142                                                KGuiItem(i18n("Ignore")));
0143             if (answer != KMessageBox::PrimaryAction) {
0144                 // Ignore
0145                 break;
0146             }
0147         }
0148     }
0149 
0150     void startGwenview()
0151     {
0152         KService::Ptr service = KService::serviceByDesktopName(QStringLiteral("org.kde.gwenview"));
0153         if (!service) {
0154             qCCritical(GWENVIEW_IMPORTER_LOG) << "Could not find gwenview";
0155         } else {
0156             auto job = new KIO::ApplicationLauncherJob(service);
0157             job->setUrls({mThumbnailPage->destinationUrl()});
0158             job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0159             job->start();
0160         }
0161     }
0162 
0163     void showWhatNext()
0164     {
0165         mCentralWidget->setCurrentWidget(mDialogPage);
0166         mDialogPage->setText(i18n("What do you want to do now?"));
0167         mDialogPage->removeButtons();
0168         int gwenview = mDialogPage->addButton(KGuiItem(i18n("View Imported Documents with Gwenview"), QStringLiteral("gwenview")));
0169         int importMore = mDialogPage->addButton(KGuiItem(i18n("Import more Documents")));
0170         mDialogPage->addButton(KGuiItem(i18n("Quit"), QStringLiteral("dialog-cancel")));
0171 
0172         int answer = mDialogPage->exec();
0173         if (answer == gwenview) {
0174             startGwenview();
0175             qApp->quit();
0176         } else if (answer == importMore) {
0177             mCentralWidget->setCurrentWidget(mThumbnailPage);
0178         } else { /* quit */
0179             qApp->quit();
0180         }
0181     }
0182 };
0183 
0184 ImportDialog::ImportDialog()
0185     : d(new ImportDialogPrivate)
0186 {
0187     d->q = this;
0188     d->mImporter = new Importer(this);
0189     connect(d->mImporter, &Importer::error, this, &ImportDialog::showImportError);
0190     d->mThumbnailPage = new ThumbnailPage;
0191 
0192     QUrl url = ImporterConfig::destinationUrl();
0193     if (!url.isValid()) {
0194         url = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
0195         const int year = QDate::currentDate().year();
0196         url.setPath(url.path() + '/' + QString::number(year));
0197     }
0198     d->mThumbnailPage->setDestinationUrl(url);
0199 
0200     d->mProgressPage = new ProgressPage(d->mImporter);
0201 
0202     d->mDialogPage = new DialogPage;
0203 
0204     d->mCentralWidget = new QStackedWidget;
0205     setCentralWidget(d->mCentralWidget);
0206     d->mCentralWidget->addWidget(d->mThumbnailPage);
0207     d->mCentralWidget->addWidget(d->mProgressPage);
0208     d->mCentralWidget->addWidget(d->mDialogPage);
0209 
0210     connect(d->mThumbnailPage, &ThumbnailPage::importRequested, this, &ImportDialog::startImport);
0211     connect(d->mThumbnailPage, &ThumbnailPage::rejected, this, &QWidget::close);
0212     connect(d->mImporter, &Importer::importFinished, this, &ImportDialog::slotImportFinished);
0213     connect(this, &ImportDialog::showErrors, d->mDialogPage, &DialogPage::slotShowErrors);
0214 
0215     d->mCentralWidget->setCurrentWidget(d->mThumbnailPage);
0216 
0217     setWindowIcon(QIcon::fromTheme(QStringLiteral("gwenview")));
0218     setAutoSaveSettings();
0219 }
0220 
0221 ImportDialog::~ImportDialog()
0222 {
0223     delete d;
0224 }
0225 
0226 QSize ImportDialog::sizeHint() const
0227 {
0228     return QSize(700, 500);
0229 }
0230 
0231 void ImportDialog::setSourceUrl(const QUrl &url, const QString &deviceUdi)
0232 {
0233     QString name, iconName;
0234     if (deviceUdi.isEmpty()) {
0235         name = url.url(QUrl::PreferLocalFile);
0236         iconName = KProtocolInfo::icon(url.scheme());
0237         if (iconName.isEmpty()) {
0238             iconName = QStringLiteral("folder");
0239         }
0240     } else {
0241         Solid::Device device(deviceUdi);
0242         name = device.vendor() + QLatin1Char(' ') + device.product();
0243         iconName = device.icon();
0244     }
0245     d->mThumbnailPage->setSourceUrl(url, iconName, name);
0246 }
0247 
0248 void ImportDialog::startImport()
0249 {
0250     const QUrl url = d->mThumbnailPage->destinationUrl();
0251     ImporterConfig::setDestinationUrl(url);
0252     ImporterConfig::self()->save();
0253 
0254     d->mCentralWidget->setCurrentWidget(d->mProgressPage);
0255     d->mImporter->setAutoRenameFormat(ImporterConfig::autoRename() ? ImporterConfig::autoRenameFormat() : QString());
0256     d->mImporter->start(d->mThumbnailPage->urlList(), url);
0257 }
0258 
0259 void ImportDialog::slotImportFinished()
0260 {
0261     d->checkForFailedUrls();
0262     d->deleteImportedUrls();
0263     d->showWhatNext();
0264 }
0265 
0266 void ImportDialog::showImportError(const QString &message)
0267 {
0268     KMessageBox::error(this, message);
0269     d->mCentralWidget->setCurrentWidget(d->mThumbnailPage);
0270 }
0271 
0272 } // namespace
0273 
0274 #include "moc_importdialog.cpp"