File indexing completed on 2025-01-05 03:53:38

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-02-11
0007  * Description : a tool to export images to WikiMedia web service
0008  *
0009  * SPDX-FileCopyrightText: 2011      by Alexandre Mendes <alex dot mendes1988 at gmail dot com>
0010  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2012      by Parthasarathy Gopavarapu <gparthasarathy93 at gmail dot com>
0012  * SPDX-FileCopyrightText: 2012-2016 by Peter Potrowl <peter dot potrowl at gmail dot com>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "mediawikiwindow.h"
0019 
0020 // Qt includes
0021 
0022 #include <QWindow>
0023 #include <QPointer>
0024 #include <QLayout>
0025 #include <QCloseEvent>
0026 #include <QFileInfo>
0027 #include <QFile>
0028 #include <QMenu>
0029 #include <QUrl>
0030 #include <QComboBox>
0031 #include <QPushButton>
0032 #include <QMessageBox>
0033 #include <QDir>
0034 
0035 // KDE includes
0036 
0037 #include <klocalizedstring.h>
0038 #include <ksharedconfig.h>
0039 #include <kconfiggroup.h>
0040 
0041 // MediaWiki includes
0042 
0043 #include "mediawiki_login.h"
0044 #include "mediawiki_iface.h"
0045 
0046 // Local includes
0047 
0048 #include "digikam_debug.h"
0049 #include "dmetadata.h"
0050 #include "wstoolutils.h"
0051 #include "ditemslist.h"
0052 #include "previewloadthread.h"
0053 #include "mediawikiwidget.h"
0054 #include "mediawikitalker.h"
0055 #include "dfileoperations.h"
0056 
0057 using namespace MediaWiki;
0058 
0059 namespace DigikamGenericMediaWikiPlugin
0060 {
0061 
0062 class Q_DECL_HIDDEN MediaWikiWindow::Private
0063 {
0064 public:
0065 
0066     explicit Private()
0067     {
0068         widget       = nullptr;
0069         MediaWiki    = nullptr;
0070         iface        = nullptr;
0071         uploadTalker = nullptr;
0072     }
0073 
0074     QString          tmpDir;
0075     QString          tmpPath;
0076     QString          login;
0077     QString          pass;
0078     QString          wikiName;
0079     QUrl             wikiUrl;
0080 
0081     MediaWikiWidget* widget;
0082     Iface*           MediaWiki;
0083     DInfoInterface*  iface;
0084     MediaWikiTalker* uploadTalker;
0085 };
0086 
0087 MediaWikiWindow::MediaWikiWindow(DInfoInterface* const iface, QWidget* const /*parent*/)
0088     : WSToolDialog(nullptr, QLatin1String("MediaWiki export dialog")),
0089       d           (new Private)
0090 {
0091     d->tmpPath.clear();
0092     d->tmpDir       = WSToolUtils::makeTemporaryDir("MediaWiki").absolutePath() + QLatin1Char('/');
0093     d->widget       = new MediaWikiWidget(iface, this);
0094     d->uploadTalker = nullptr;
0095     d->login        = QString();
0096     d->pass         = QString();
0097     d->iface        = iface;
0098 
0099     setMainWidget(d->widget);
0100     setModal(false);
0101     setWindowTitle(i18nc("@title:window", "Export to MediaWiki"));
0102 
0103     startButton()->setText(i18nc("@action:button", "Start Upload"));
0104     startButton()->setToolTip(i18nc("@info:tooltip, button", "Start upload to MediaWiki"));
0105 
0106     startButton()->setEnabled(false);
0107 
0108     d->widget->setMinimumSize(700, 500);
0109     d->widget->installEventFilter(this);
0110 
0111     connect(startButton(), SIGNAL(clicked()),
0112             this, SLOT(slotStartTransfer()));
0113 
0114     connect(this, SIGNAL(finished(int)),
0115             this, SLOT(slotFinished()));
0116 
0117     connect(d->widget, SIGNAL(signalChangeUserRequest()),
0118             this, SLOT(slotChangeUserClicked()));
0119 
0120     connect(d->widget, SIGNAL(signalLoginRequest(QString,QString,QString,QUrl)),
0121             this, SLOT(slotDoLogin(QString,QString,QString,QUrl)));
0122 
0123     connect(d->widget->progressBar(), SIGNAL(signalProgressCanceled()),
0124             this, SLOT(slotProgressCanceled()));
0125 
0126     readSettings();
0127     reactivate();
0128 }
0129 
0130 MediaWikiWindow::~MediaWikiWindow()
0131 {
0132     delete d;
0133 }
0134 
0135 void MediaWikiWindow::closeEvent(QCloseEvent* e)
0136 {
0137     if (!e)
0138     {
0139         return;
0140     }
0141 
0142     slotFinished();
0143     e->accept();
0144 }
0145 
0146 void MediaWikiWindow::reactivate()
0147 {
0148     d->widget->imagesList()->listView()->clear();
0149     d->widget->imagesList()->loadImagesFromCurrentSelection();
0150     d->widget->loadItemInfoFirstLoad();
0151     d->widget->clearEditFields();
0152     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "imagesList items count:" << d->widget->imagesList()->listView()->topLevelItemCount();
0153     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "imagesList url length:"  << d->widget->imagesList()->imageUrls(false).size();
0154     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "allImagesDesc length:"   << d->widget->allImagesDesc().size();
0155     show();
0156 }
0157 
0158 void MediaWikiWindow::readSettings()
0159 {
0160     KSharedConfigPtr config = KSharedConfig::openConfig();
0161     KConfigGroup group      = config->group(QLatin1String("MediaWiki export settings"));
0162 
0163     d->widget->readSettings(group);
0164 }
0165 
0166 void MediaWikiWindow::saveSettings()
0167 {
0168     KSharedConfigPtr config = KSharedConfig::openConfig();
0169     KConfigGroup group      = config->group(QLatin1String("MediaWiki export settings"));
0170 
0171     d->widget->saveSettings(group);
0172 }
0173 
0174 void MediaWikiWindow::slotFinished()
0175 {
0176     d->widget->progressBar()->progressCompleted();
0177     saveSettings();
0178 }
0179 
0180 void MediaWikiWindow::slotProgressCanceled()
0181 {
0182     slotFinished();
0183     reject();
0184 }
0185 
0186 bool MediaWikiWindow::prepareImageForUpload(const QString& imgPath)
0187 {
0188     // Create temporary directory if it does not exist
0189 
0190     if (!QDir(d->tmpDir).exists())
0191     {
0192         QDir().mkpath(d->tmpDir);
0193     }
0194 
0195     // Get temporary file name
0196 
0197     d->tmpPath = d->tmpDir + QFileInfo(imgPath).baseName().trimmed() + QLatin1String(".jpg");
0198 
0199     QImage image;
0200 
0201     // Rescale image if requested: metadata is lost
0202 
0203     if (d->widget->resize())
0204     {
0205         image = PreviewLoadThread::loadHighQualitySynchronously(imgPath).copyQImage();
0206 
0207         if (image.isNull())
0208         {
0209             image.load(imgPath);
0210         }
0211 
0212         if (image.isNull())
0213         {
0214             return false;
0215         }
0216 
0217         int maxDim = d->widget->dimension();
0218 
0219         if (d->widget->resize() && (image.width() > maxDim || image.height() > maxDim))
0220         {
0221             qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Resizing to" << maxDim;
0222             image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio, Qt::SmoothTransformation);
0223         }
0224 
0225         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Saving to temp file:" << d->tmpPath;
0226         image.save(d->tmpPath, "JPEG", d->widget->quality());
0227     }
0228     else
0229     {
0230         // file is copied with its embedded metadata
0231         if (!DFileOperations::copyFile(imgPath, d->tmpPath))
0232         {
0233             qCDebug(DIGIKAM_WEBSERVICES_LOG) << "File copy error from:" << imgPath << "to" << d->tmpPath;
0234             return false;
0235         }
0236     }
0237 
0238     // NOTE : In case of metadata are saved to tmp file, we will override metadata processor settings from host
0239     // to write metadata to image file rather than sidecar file, to be effective with remote web service.
0240 
0241     QScopedPointer<DMetadata> meta(new DMetadata);
0242     meta->setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY);
0243 
0244     if (d->widget->removeMeta())
0245     {
0246         // save empty metadata to erase them
0247         meta->save(d->tmpPath);
0248     }
0249     else
0250     {
0251         // copy meta data from initial to temporary image
0252 
0253         if (meta->load(imgPath))
0254         {
0255             if (d->widget->resize())
0256             {
0257                 meta->setItemDimensions(image.size());
0258             }
0259 
0260             if (d->widget->removeGeo())
0261             {
0262                 meta->removeGPSInfo();
0263             }
0264 
0265             meta->setItemOrientation(MetaEngine::ORIENTATION_NORMAL);
0266             meta->save(d->tmpPath, true);
0267         }
0268     }
0269 
0270     return true;
0271 }
0272 
0273 void MediaWikiWindow::slotStartTransfer()
0274 {
0275     saveSettings();
0276     QList<QUrl> urls                                    = d->widget->imagesList()->imageUrls(false);
0277     QMap <QString, QMap <QString, QString> > imagesDesc = d->widget->allImagesDesc();
0278 
0279     for (int i = 0 ; i < urls.size() ; ++i)
0280     {
0281         QString url;
0282 
0283         if (d->widget->resize() || d->widget->removeMeta() || d->widget->removeGeo())
0284         {
0285             prepareImageForUpload(urls.at(i).toLocalFile());
0286             imagesDesc.insert(d->tmpPath, imagesDesc.take(urls.at(i).toLocalFile()));
0287         }
0288     }
0289 
0290     d->uploadTalker->setImageMap(imagesDesc);
0291 
0292     d->widget->progressBar()->setRange(0, 100);
0293     d->widget->progressBar()->setValue(0);
0294 
0295     connect(d->uploadTalker, SIGNAL(signalUploadProgress(int)),
0296             d->widget->progressBar(), SLOT(setValue(int)));
0297 
0298     connect(d->uploadTalker, SIGNAL(signalEndUpload()),
0299             this, SLOT(slotEndUpload()));
0300 
0301     d->widget->progressBar()->show();
0302     d->widget->progressBar()->progressScheduled(i18n("MediaWiki export"), true, true);
0303     d->widget->progressBar()->progressThumbnailChanged(
0304         QIcon::fromTheme(QLatin1String("dk-mediawiki")).pixmap(22, 22));
0305     d->uploadTalker->slotBegin();
0306 }
0307 
0308 void MediaWikiWindow::slotChangeUserClicked()
0309 {
0310     startButton()->setEnabled(false);
0311     d->widget->invertAccountLoginBox();
0312 }
0313 
0314 void MediaWikiWindow::slotDoLogin(const QString& login, const QString& pass, const QString& wikiName, const QUrl& wikiUrl)
0315 {
0316     d->login              = login;
0317     d->pass               = pass;
0318     d->wikiName           = wikiName;
0319     d->wikiUrl            = wikiUrl;
0320     d->MediaWiki          = new Iface(wikiUrl);
0321     Login* const loginJob = new Login(*d->MediaWiki, login, pass);
0322 
0323     connect(loginJob, SIGNAL(result(KJob*)),
0324             this, SLOT(slotLoginHandle(KJob*)));
0325 
0326     loginJob->start();
0327 }
0328 
0329 int MediaWikiWindow::slotLoginHandle(KJob* loginJob)
0330 {
0331     qCDebug(DIGIKAM_WEBSERVICES_LOG) << loginJob->error() << loginJob->errorString() << loginJob->errorText();
0332 
0333     if (loginJob->error())
0334     {
0335         d->login.clear();
0336         d->pass.clear();
0337         d->uploadTalker = nullptr;
0338         QMessageBox::critical(this, i18nc("@title:window", "Login Error"), i18n("Please check your credentials and try again."));
0339     }
0340     else
0341     {
0342         d->uploadTalker = new MediaWikiTalker(d->iface, d->MediaWiki, this);
0343         startButton()->setEnabled(true);
0344         d->widget->invertAccountLoginBox();
0345         d->widget->updateLabels(d->login, d->wikiName, d->wikiUrl.toString());
0346     }
0347 
0348     return loginJob->error();
0349 }
0350 
0351 void MediaWikiWindow::slotEndUpload()
0352 {
0353     disconnect(d->uploadTalker, SIGNAL(signalUploadProgress(int)),
0354                d->widget->progressBar(),SLOT(setValue(int)));
0355 
0356     disconnect(d->uploadTalker, SIGNAL(signalEndUpload()),
0357                this, SLOT(slotEndUpload()));
0358 
0359     QMessageBox::information(this, QString(), i18n("Upload finished with no errors."));
0360     d->widget->progressBar()->hide();
0361     d->widget->progressBar()->progressCompleted();
0362 }
0363 
0364 bool MediaWikiWindow::eventFilter(QObject* /*obj*/, QEvent* event)
0365 {
0366     if (event->type() == QEvent::KeyRelease)
0367     {
0368         QKeyEvent* const c = dynamic_cast<QKeyEvent *>(event);
0369 
0370         if (c && c->key() == Qt::Key_Return)
0371         {
0372             event->ignore();
0373             qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Key event pass";
0374             return false;
0375 
0376         }
0377     }
0378 
0379     return true;
0380 }
0381 
0382 } // namespace DigikamGenericMediaWikiPlugin
0383 
0384 #include "moc_mediawikiwindow.cpp"