1 /* ============================================================
2  *
3  * This file is a part of KDE project
4  *
5  *
6  * Date        : 2011-02-11
7  * Description : A kipi plugin to export images to a MediaWiki wiki
8  *
9  * Copyright (C) 2011      by Alexandre Mendes <alex dot mendes1988 at gmail dot com>
10  * Copyright (C) 2011-2018 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  * Copyright (C) 2012      by Parthasarathy Gopavarapu <gparthasarathy93 at gmail dot com>
12  * Copyright (C) 2012-2016 by Peter Potrowl <peter dot potrowl at gmail dot com>
13  *
14  * This program is free software; you can redistribute it
15  * and/or modify it under the terms of the GNU General
16  * Public License as published by the Free Software Foundation;
17  * either version 2, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #include "wmwindow.h"
27 
28 // Qt includes
29 
30 #include <QWindow>
31 #include <QPointer>
32 #include <QLayout>
33 #include <QCloseEvent>
34 #include <QFileInfo>
35 #include <QFile>
36 #include <QMenu>
37 #include <QUrl>
38 #include <QComboBox>
39 #include <QPushButton>
40 #include <QMessageBox>
41 #include <QDir>
42 
43 // KDE includes
44 
45 #include <kconfig.h>
46 #include <klocalizedstring.h>
47 #include <kwindowconfig.h>
48 
49 // MediaWiki includes
50 
51 #include <MediaWiki/Login>
52 #include <MediaWiki/MediaWiki>
53 #include <mediawiki_version.h>
54 
55 // KIPI includes
56 
57 #include <KIPI/Interface>
58 #include <KIPI/ImageCollection>
59 
60 // Local includes
61 
62 #include "kipiplugins_debug.h"
63 #include "kpaboutdata.h"
64 #include "kpimageinfo.h"
65 #include "kpimageslist.h"
66 #include "kpprogresswidget.h"
67 #include "wmwidget.h"
68 #include "wmtalker.h"
69 
70 using namespace KIPI;
71 using namespace mediawiki;
72 
73 namespace KIPIWikiMediaPlugin
74 {
75 
76 class WMWindow::Private
77 {
78 public:
79 
Private()80     Private()
81     {
82         widget       = nullptr;
83         mediawiki    = nullptr;
84         uploadTalker = nullptr;
85     }
86 
87     QString    tmpDir;
88     QString    tmpPath;
89     QString    login;
90     QString    pass;
91     QString    wikiName;
92     QUrl       wikiUrl;
93 
94     WmWidget*  widget;
95     MediaWiki* mediawiki;
96 
97     WMTalker*  uploadTalker;
98 };
99 
WMWindow(const QString & tmpFolder,QWidget * const)100 WMWindow::WMWindow(const QString& tmpFolder, QWidget* const /*parent*/)
101     : KPToolDialog(nullptr),
102       d(new Private)
103 {
104     d->tmpPath.clear();
105     d->tmpDir       = tmpFolder;
106     d->widget       = new WmWidget(this);
107     d->uploadTalker = nullptr;
108     d->login        = QString();
109     d->pass         = QString();
110 
111     setMainWidget(d->widget);
112     setWindowIcon(QIcon::fromTheme(QLatin1String("kipi-wikimedia")));
113     setModal(false);
114     setWindowTitle(i18n("Export to MediaWiki"));
115 
116     startButton()->setText(i18n("Start Upload"));
117     startButton()->setToolTip(i18n("Start upload to MediaWiki"));
118 
119     startButton()->setEnabled(false);
120 
121     d->widget->setMinimumSize(700, 500);
122     d->widget->installEventFilter(this);
123 
124     KPAboutData* const about = new KPAboutData(ki18n("MediaWiki export"),
125                                                ki18n("A tool to export image collection "
126                                                      "to a MediaWiki installation.\n"
127                                                      "Using libmediawiki version %1").subs(QLatin1String(MEDIAWIKI_VERSION_STRING)),
128                                                ki18n("(c) 2011, Alexandre Mendes"));
129 
130     about->addAuthor(ki18n("Alexandre Mendes").toString(),
131                      ki18n("Author").toString(),
132                      QLatin1String("alex dot mendes1988 at gmail dot com"));
133 
134     about->addAuthor(ki18n("Guillaume Hormiere").toString(),
135                      ki18n("Developer").toString(),
136                      QLatin1String("hormiere dot guillaume at gmail dot com"));
137 
138     about->addAuthor(ki18n("Gilles Caulier").toString(),
139                      ki18n("Developer").toString(),
140                      QLatin1String("caulier dot gilles at gmail dot com"));
141 
142     about->addAuthor(ki18n("Peter Potrowl").toString(),
143                      ki18n("Developer").toString(),
144                      QLatin1String("peter dot potrowl at gmail dot com"));
145 
146     about->setHandbookEntry(QLatin1String("tool-wikimediaexport"));
147     setAboutData(about);
148 
149     connect(startButton(), SIGNAL(clicked()),
150             this, SLOT(slotStartTransfer()));
151 
152     connect(this, SIGNAL(finished(int)),
153             this, SLOT(slotFinished()));
154 
155     connect(d->widget, SIGNAL(signalChangeUserRequest()),
156             this, SLOT(slotChangeUserClicked()));
157 
158     connect(d->widget, SIGNAL(signalLoginRequest(QString, QString, QString, QUrl)),
159             this, SLOT(slotDoLogin(QString, QString, QString, QUrl)));
160 
161     connect(d->widget->progressBar(), SIGNAL(signalProgressCanceled()),
162             this, SLOT(slotProgressCanceled()));
163 
164     readSettings();
165     reactivate();
166 }
167 
~WMWindow()168 WMWindow::~WMWindow()
169 {
170     delete d;
171 }
172 
closeEvent(QCloseEvent * e)173 void WMWindow::closeEvent(QCloseEvent* e)
174 {
175     if (!e)
176     {
177         return;
178     }
179 
180     slotFinished();
181     e->accept();
182 }
183 
reactivate()184 void WMWindow::reactivate()
185 {
186     d->widget->imagesList()->listView()->clear();
187     d->widget->imagesList()->loadImagesFromCurrentSelection();
188     d->widget->loadImageInfoFirstLoad();
189     d->widget->clearEditFields();
190     qCDebug(KIPIPLUGINS_LOG) << "imagesList items count:" << d->widget->imagesList()->listView()->topLevelItemCount();
191     qCDebug(KIPIPLUGINS_LOG) << "imagesList url length:"  << d->widget->imagesList()->imageUrls(false).size();
192     qCDebug(KIPIPLUGINS_LOG) << "allImagesDesc length:"   << d->widget->allImagesDesc().size();
193     show();
194 }
195 
readSettings()196 void WMWindow::readSettings()
197 {
198     KConfig config(QLatin1String("kipirc"));
199     KConfigGroup group = config.group(QLatin1String("MediaWiki export settings"));
200 
201     d->widget->readSettings(group);
202 
203     winId();
204     KConfigGroup group2 = config.group(QLatin1String("MediaWiki export dialog"));
205     KWindowConfig::restoreWindowSize(windowHandle(), group2);
206     resize(windowHandle()->size());
207 }
208 
saveSettings()209 void WMWindow::saveSettings()
210 {
211     KConfig config(QLatin1String("kipirc"));
212     KConfigGroup group = config.group(QLatin1String("MediaWiki export settings"));
213 
214     d->widget->saveSettings(group);
215 
216     KConfigGroup group2 = config.group(QLatin1String("MediaWiki export dialog"));
217     KWindowConfig::saveWindowSize(windowHandle(), group2);
218     config.sync();
219 }
220 
slotFinished()221 void WMWindow::slotFinished()
222 {
223     d->widget->progressBar()->progressCompleted();
224     saveSettings();
225 }
226 
slotProgressCanceled()227 void WMWindow::slotProgressCanceled()
228 {
229     slotFinished();
230     reject();
231 }
232 
prepareImageForUpload(const QString & imgPath)233 bool WMWindow::prepareImageForUpload(const QString& imgPath)
234 {
235     // Create temporary directory if it does not exist
236 
237     if (!QDir(d->tmpDir).exists())
238     {
239         QDir().mkdir(d->tmpDir);
240     }
241 
242     // Get temporary file name
243 
244     d->tmpPath = d->tmpDir + QFileInfo(imgPath).baseName().trimmed() + QLatin1String(".jpg");
245 
246     QImage image;
247 
248     // Rescale image if requested: metadata is lost
249 
250     if (d->widget->resize())
251     {
252         if (iface())
253         {
254             image = iface()->preview(QUrl::fromLocalFile(imgPath));
255         }
256 
257         if (image.isNull())
258         {
259             image.load(imgPath);
260         }
261 
262         if (image.isNull())
263         {
264             return false;
265         }
266 
267         int maxDim = d->widget->dimension();
268 
269         if (d->widget->resize() && (image.width() > maxDim || image.height() > maxDim))
270         {
271             qCDebug(KIPIPLUGINS_LOG) << "Resizing to" << maxDim;
272             image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio, Qt::SmoothTransformation);
273         }
274 
275         qCDebug(KIPIPLUGINS_LOG) << "Saving to temp file:" << d->tmpPath;
276         image.save(d->tmpPath, "JPEG", d->widget->quality());
277     }
278     else
279     {
280         // file is copied with its embedded metadata
281         if (!QFile::copy(imgPath, d->tmpPath))
282         {
283             qCDebug(KIPIPLUGINS_LOG) << "File copy error from:" << imgPath << "to" << d->tmpPath;
284             return false;
285         }
286     }
287 
288     if (iface())
289     {
290         // NOTE : In case of metadata are saved to tmp file, we will override MetadataProcessor settings from KIPI host
291         // to write metadata to image file rather than sidecar file, to be effective with remote web service.
292 
293         QPointer<MetadataProcessor> meta = iface()->createMetadataProcessor();
294 
295         if (d->widget->removeMeta())
296         {
297             // save empty metadata to erase them
298             meta->save(QUrl::fromLocalFile(d->tmpPath), true);
299         }
300         else
301         {
302             // copy meta data from initial to temporary image
303 
304             if (meta->load(QUrl::fromLocalFile(imgPath)))
305             {
306                 if (d->widget->resize())
307                 {
308                     meta->setImageDimensions(image.size());
309                 }
310 
311                 if (d->widget->removeGeo())
312                 {
313                     meta->removeGPSInfo();
314                 }
315 
316                 meta->setImageOrientation(MetadataProcessor::NORMAL);
317                 meta->save(QUrl::fromLocalFile(d->tmpPath), true);
318             }
319         }
320     }
321 
322     return true;
323 }
324 
slotStartTransfer()325 void WMWindow::slotStartTransfer()
326 {
327     saveSettings();
328     QList<QUrl> urls                                    = d->widget->imagesList()->imageUrls(false);
329     QMap <QString, QMap <QString, QString> > imagesDesc = d->widget->allImagesDesc();
330 
331     for (int i = 0; i < urls.size(); ++i)
332     {
333         QString url;
334 
335         if (d->widget->resize() || d->widget->removeMeta() || d->widget->removeGeo())
336         {
337             prepareImageForUpload(urls.at(i).toLocalFile());
338             imagesDesc.insert(d->tmpPath, imagesDesc.take(urls.at(i).toLocalFile()));
339         }
340     }
341 
342     d->uploadTalker->setImageMap(imagesDesc);
343 
344     d->widget->progressBar()->setRange(0, 100);
345     d->widget->progressBar()->setValue(0);
346 
347     connect(d->uploadTalker, SIGNAL(uploadProgress(int)),
348             d->widget->progressBar(), SLOT(setValue(int)));
349 
350     connect(d->uploadTalker, SIGNAL(endUpload()),
351             this, SLOT(slotEndUpload()));
352 
353     d->widget->progressBar()->show();
354     d->widget->progressBar()->progressScheduled(i18n("MediaWiki export"), true, true);
355     d->widget->progressBar()->progressThumbnailChanged(QIcon(QLatin1String(":/icons/kipi-icon.svg")).pixmap(22, 22));
356     d->uploadTalker->begin();
357 }
358 
slotChangeUserClicked()359 void WMWindow::slotChangeUserClicked()
360 {
361     startButton()->setEnabled(false);
362     d->widget->invertAccountLoginBox();
363 }
364 
slotDoLogin(const QString & login,const QString & pass,const QString & wikiName,const QUrl & wikiUrl)365 void WMWindow::slotDoLogin(const QString& login, const QString& pass, const QString& wikiName, const QUrl& wikiUrl)
366 {
367     d->login              = login;
368     d->pass               = pass;
369     d->wikiName           = wikiName;
370     d->wikiUrl            = wikiUrl;
371     d->mediawiki          = new MediaWiki(wikiUrl);
372     Login* const loginJob = new Login(*d->mediawiki, login, pass);
373 
374     connect(loginJob, SIGNAL(result(KJob*)),
375             this, SLOT(slotLoginHandle(KJob*)));
376 
377     loginJob->start();
378 }
379 
slotLoginHandle(KJob * loginJob)380 int WMWindow::slotLoginHandle(KJob* loginJob)
381 {
382     qCDebug(KIPIPLUGINS_LOG) << loginJob->error() << loginJob->errorString() << loginJob->errorText();
383 
384     if (loginJob->error())
385     {
386         d->login.clear();
387         d->pass.clear();
388         d->uploadTalker = nullptr;
389         QMessageBox::critical(this, i18n("Login Error"), i18n("Please check your credentials and try again."));
390     }
391     else
392     {
393         d->uploadTalker = new WMTalker(iface(), d->mediawiki, this);
394         startButton()->setEnabled(true);
395         d->widget->invertAccountLoginBox();
396         d->widget->updateLabels(d->login, d->wikiName, d->wikiUrl.toString());
397     }
398 
399     return loginJob->error();
400 }
401 
slotEndUpload()402 void WMWindow::slotEndUpload()
403 {
404     disconnect(d->uploadTalker, SIGNAL(uploadProgress(int)),
405                d->widget->progressBar(),SLOT(setValue(int)));
406 
407     disconnect(d->uploadTalker, SIGNAL(endUpload()),
408                this, SLOT(slotEndUpload()));
409 
410     QMessageBox::information(this, QString(), i18n("Upload finished with no errors."));
411     d->widget->progressBar()->hide();
412     d->widget->progressBar()->progressCompleted();
413 }
414 
eventFilter(QObject *,QEvent * event)415 bool WMWindow::eventFilter(QObject* /*obj*/, QEvent* event)
416 {
417     if (event->type() == QEvent::KeyRelease)
418     {
419         QKeyEvent* const c = dynamic_cast<QKeyEvent *>(event);
420 
421         if (c && c->key() == Qt::Key_Return)
422         {
423             event->ignore();
424             qCDebug(KIPIPLUGINS_LOG) << "Key event pass";
425             return false;
426 
427         }
428     }
429 
430     return true;
431 }
432 
433 } // namespace KIPIWikiMediaPlugin
434