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"