1 /* ============================================================
2  *
3  * This file is a part of KDE project
4  *
5  *
6  * Date        : 2010-11-15
7  * Description : a kipi plugin to export images to Yandex.Fotki web service
8  *
9  * Copyright (C) 2010 by Roman Tsisyk <roman at tsisyk dot com>
10  *
11  * GUI based on PicasaWeb KIPI Plugin
12  * Copyright (C) 2005-2008 by Vardhman Jain <vardhman at gmail dot com>
13  * Copyright (C) 2008-2018 by Gilles Caulier <caulier dot gilles at gmail dot com>
14  * Copyright (C) 2009      by Luka Renko <lure at kubuntu dot org>
15  *
16  * This program is free software; you can redistribute it
17  * and/or modify it under the terms of the GNU General
18  * Public License as published by the Free Software Foundation;
19  * either version 2, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  * GNU General Public License for more details.
25  *
26  * ============================================================ */
27 
28 #include "yfwindow.h"
29 
30 // Qt includes
31 
32 #include <QButtonGroup>
33 #include <QCheckBox>
34 #include <QCloseEvent>
35 #include <QFileInfo>
36 #include <QGridLayout>
37 #include <QGroupBox>
38 #include <QHBoxLayout>
39 #include <QLabel>
40 #include <QProgressBar>
41 #include <QRadioButton>
42 #include <QSpinBox>
43 #include <QVBoxLayout>
44 #include <QMenu>
45 #include <QComboBox>
46 #include <QApplication>
47 #include <QMessageBox>
48 
49 // KDE includes
50 
51 #include <kconfig.h>
52 #include <kconfiggroup.h>
53 #include <klocalizedstring.h>
54 
55 // Libkipi includes
56 
57 #include <KIPI/Interface>
58 #include <KIPI/UploadWidget>
59 #include <KIPI/ImageCollection>
60 
61 // Local includes
62 
63 #include "kpaboutdata.h"
64 #include "kpimageinfo.h"
65 #include "kpversion.h"
66 #include "kpimageslist.h"
67 #include "yftalker.h"
68 #include "yfalbumdialog.h"
69 #include "kipiplugins_debug.h"
70 #include "kputil.h"
71 #include "kplogindialog.h"
72 #include "yfwidget.h"
73 
74 using namespace KIPI;
75 
76 namespace KIPIYandexFotkiPlugin
77 {
78 
79 /*
80  * This tag added to our images after uploading to Fotki web service
81  */
82 const char* YandexFotkiWindow::XMP_SERVICE_ID = "Xmp.kipi.yandexGPhotoId";
83 
YandexFotkiWindow(bool import,QWidget * const parent)84 YandexFotkiWindow::YandexFotkiWindow(bool import, QWidget* const parent)
85     : KPToolDialog(parent)
86 {
87     m_import = import;
88     m_tmpDir = makeTemporaryDir("yandexfotki").absolutePath() + QLatin1Char('/');
89     m_widget = new YandexFotkiWidget(this, iface(), QString::fromLatin1("Yandex.Fotki"));
90 
91     m_loginLabel           = m_widget->getUserNameLabel();
92     m_headerLabel          = m_widget->getHeaderLbl();
93     m_changeUserButton     = m_widget->getChangeUserBtn();
94     m_newAlbumButton       = m_widget->getNewAlbmBtn();
95     m_reloadAlbumsButton   = m_widget->getReloadBtn();
96     m_albumsCombo          = m_widget->getAlbumsCoB();
97     m_resizeCheck          = m_widget->getResizeCheckBox();
98     m_dimensionSpin        = m_widget->getDimensionSpB();
99     m_imageQualitySpin     = m_widget->getImgQualitySpB();
100     m_imgList              = m_widget->imagesList();
101     m_progressBar          = m_widget->progressBar();
102     m_accessCombo          = m_widget->m_accessCombo;
103     m_hideOriginalCheck    = m_widget->m_hideOriginalCheck;
104     m_disableCommentsCheck = m_widget->m_disableCommentsCheck;
105     m_adultCheck           = m_widget->m_adultCheck;
106     m_policyGroup          = m_widget->m_policyGroup;
107     m_albumsBox            = m_widget->getAlbumBox();
108     m_meta                 = nullptr;
109 
110     if (iface())
111     {
112         m_meta = iface()->createMetadataProcessor();
113     }
114 
115     connect(m_changeUserButton, SIGNAL(clicked()),
116             this, SLOT(slotChangeUserClicked()));
117 
118     connect(m_newAlbumButton, SIGNAL(clicked()),
119             this, SLOT(slotNewAlbumRequest()) );
120 
121 
122     connect(m_reloadAlbumsButton, SIGNAL(clicked()),
123             this, SLOT(slotReloadAlbumsRequest()) );
124 
125     setMainWidget(m_widget);
126     m_widget->setMinimumSize(800, 600);
127 
128     KPAboutData* const about = new KPAboutData(ki18n("Yandex.Fotki Plugin"),
129                                                ki18n("A tool to export image collections to "
130                                                      "Yandex.Fotki web service."),
131                                                ki18n("(c) 2007-2009, Vardhman Jain\n"
132                                                      "(c) 2008-2015, Gilles Caulier\n"
133                                                      "(c) 2009, Luka Renko\n"
134                                                      "(c) 2010, Roman Tsisyk"));
135 
136     about->addAuthor(ki18n( "Roman Tsisyk" ).toString(),
137                      ki18n("Author").toString(),
138                      QString::fromLatin1("roman at tsisyk dot com"));
139 
140     about->setHandbookEntry(QString::fromLatin1("tool-yandexfotkiexport"));
141     setAboutData(about);
142 
143     // -- UI slots -----------------------------------------------------------------------
144 
145     connect(startButton(), &QPushButton::clicked,
146             this, &YandexFotkiWindow::slotStartTransfer);
147 
148     connect(this, &KPToolDialog::cancelClicked,
149             this, &YandexFotkiWindow::slotCancelClicked);
150 
151     connect(this, &QDialog::finished,
152             this, &YandexFotkiWindow::slotFinished);
153 
154     // -- Talker slots -------------------------------------------------------------------
155 
156     connect(&m_talker, SIGNAL(signalError()),
157             this, SLOT(slotError()));
158 
159     connect(&m_talker, SIGNAL(signalGetSessionDone()),
160             this, SLOT(slotGetSessionDone()));
161 
162     connect(&m_talker, SIGNAL(signalGetTokenDone()),
163             this, SLOT(slotGetTokenDone()));
164 
165     connect(&m_talker, SIGNAL(signalGetServiceDone()),
166             this, SLOT(slotGetServiceDone()));
167 
168     connect(&m_talker, SIGNAL(signalListAlbumsDone(QList<YandexFotkiAlbum>)),
169             this, SLOT(slotListAlbumsDone(QList<YandexFotkiAlbum>)));
170 
171     connect(&m_talker, SIGNAL(signalListPhotosDone(QList<YandexFotkiPhoto>)),
172             this, SLOT(slotListPhotosDone(QList<YandexFotkiPhoto>)));
173 
174     connect(&m_talker, SIGNAL(signalUpdatePhotoDone(YandexFotkiPhoto&)),
175             this, SLOT(slotUpdatePhotoDone(YandexFotkiPhoto&)));
176 
177     connect(&m_talker, SIGNAL(signalUpdateAlbumDone()),
178             this, SLOT(slotUpdateAlbumDone()));
179 
180     // read settings from file
181     readSettings();
182 }
183 
~YandexFotkiWindow()184 YandexFotkiWindow::~YandexFotkiWindow()
185 {
186     reset();
187 }
188 
reactivate()189 void YandexFotkiWindow::reactivate()
190 {
191     m_imgList->loadImagesFromCurrentSelection();
192 
193     reset();
194     authenticate(false);
195     show();
196 }
197 
reset()198 void YandexFotkiWindow::reset()
199 {
200     m_talker.reset();
201     updateControls(true);
202     updateLabels();
203 }
204 
updateControls(bool val)205 void YandexFotkiWindow::updateControls(bool val)
206 {
207     if (val)
208     {
209         if (m_talker.isAuthenticated())
210         {
211             m_albumsBox->setEnabled(true);
212             startButton()->setEnabled(true);
213         }
214         else
215         {
216             m_albumsBox->setEnabled(false);
217             startButton()->setEnabled(false);
218         }
219 
220         m_changeUserButton->setEnabled(true);
221         setCursor(Qt::ArrowCursor);
222 
223         setRejectButtonMode(QDialogButtonBox::Close);
224     }
225     else
226     {
227         setCursor(Qt::WaitCursor);
228         m_albumsBox->setEnabled(false);
229         m_changeUserButton->setEnabled(false);
230         startButton()->setEnabled(false);
231 
232         setRejectButtonMode(QDialogButtonBox::Cancel);
233     }
234 }
235 
updateLabels()236 void YandexFotkiWindow::updateLabels()
237 {
238     QString urltext;
239     QString logintext;
240 
241     if (m_talker.isAuthenticated())
242     {
243         logintext = m_talker.login();
244         urltext = YandexFotkiTalker::USERPAGE_URL.arg(m_talker.login());
245         m_albumsBox->setEnabled(true);
246     }
247     else
248     {
249         logintext = i18n("Unauthorized");
250         urltext = YandexFotkiTalker::USERPAGE_DEFAULT_URL;
251         m_albumsCombo->clear();
252     }
253 
254     m_loginLabel->setText(QString::fromLatin1("<b>%1</b>").arg(logintext));
255     m_headerLabel->setText(QString::fromLatin1(
256         "<b><h2><a href=\"%1\">"
257         "<font color=\"#ff000a\">%2</font>"
258         "<font color=\"black\">%3</font>"
259         "<font color=\"#009d00\">%4</font>"
260         "</a></h2></b>")
261         .arg(urltext)
262         .arg(i18nc("Yandex.Fotki", "Y"))
263         .arg(i18nc("Yandex.Fotki", "andex."))
264         .arg(i18nc("Yandex.Fotki", "Fotki")));
265 }
266 
readSettings()267 void YandexFotkiWindow::readSettings()
268 {
269     KConfig config(QString::fromLatin1("kipirc"));
270     KConfigGroup grp = config.group("YandexFotki Settings");
271 
272     m_talker.setLogin(grp.readEntry("login", ""));
273     // don't store tokens in plaintext
274     //m_talker.setToken(grp.readEntry("token", ""));
275 
276     if (grp.readEntry("Resize", false))
277     {
278         m_resizeCheck->setChecked(true);
279         m_dimensionSpin->setEnabled(true);
280         m_imageQualitySpin->setEnabled(true);
281     }
282     else
283     {
284         m_resizeCheck->setChecked(false);
285         m_dimensionSpin->setEnabled(false);
286         m_imageQualitySpin->setEnabled(false);
287     }
288 
289     m_dimensionSpin->setValue(grp.readEntry("Maximum Width", 1600));
290     m_imageQualitySpin->setValue(grp.readEntry("Image Quality", 85));
291     m_policyGroup->button(grp.readEntry("Sync policy", 0))->setChecked(true);
292 }
293 
writeSettings()294 void YandexFotkiWindow::writeSettings()
295 {
296     KConfig config(QString::fromLatin1("kipirc"));
297     KConfigGroup grp = config.group("YandexFotki Settings");
298 
299     grp.writeEntry("token", m_talker.token());
300     // don't store tokens in plaintext
301     //grp.writeEntry("login", m_talker.login());
302 
303     grp.writeEntry("Resize", m_resizeCheck->isChecked());
304     grp.writeEntry("Maximum Width", m_dimensionSpin->value());
305     grp.writeEntry("Image Quality", m_imageQualitySpin->value());
306     grp.writeEntry("Sync policy", m_policyGroup->checkedId());
307 }
308 
slotChangeUserClicked()309 void YandexFotkiWindow::slotChangeUserClicked()
310 {
311     // force authenticate window
312     authenticate(true);
313 }
314 
closeEvent(QCloseEvent * e)315 void YandexFotkiWindow::closeEvent(QCloseEvent* e)
316 {
317     if (!e)
318     {
319         return;
320     }
321 
322     slotFinished();
323     e->accept();
324 }
325 
slotFinished()326 void YandexFotkiWindow::slotFinished()
327 {
328     writeSettings();
329     reset();
330 }
331 
slotCancelClicked()332 void YandexFotkiWindow::slotCancelClicked()
333 {
334     m_talker.cancel();
335     updateControls(true);
336 }
337 
338 /*
339 void YandexFotkiWindow::cancelProcessing()
340 {
341     m_talker.cancel();
342     m_transferQueue.clear();
343     m_imgList->processed(false);
344     progressBar()->hide();
345 }
346 */
347 
authenticate(bool forceAuthWindow)348 void YandexFotkiWindow::authenticate(bool forceAuthWindow)
349 {
350     // update credentials
351     if (forceAuthWindow || m_talker.login().isNull() || m_talker.password().isNull())
352     {
353         KPLoginDialog* const dlg = new KPLoginDialog(this, QString::fromLatin1("Yandex.Fotki"), m_talker.login(), QString());
354 
355         if (dlg->exec() == QDialog::Accepted)
356         {
357             m_talker.setLogin(dlg->login());
358             m_talker.setPassword(dlg->password());
359         }
360         else
361         {
362             // don't change anything
363             return;
364         }
365 
366         delete dlg;
367     }
368 
369     /*else
370     {
371         qCDebug(KIPIPLUGINS_LOG) << "Checking old token...";
372         m_talker.checkToken();
373         return;
374     }
375     */
376 
377     // if new credentials non-empty, authenticate
378     if (!m_talker.login().isEmpty() && !m_talker.password().isEmpty())
379     {
380         // cancel all tasks first
381         reset();
382 
383         // start authentication chain
384         updateControls(false);
385         m_talker.getService();
386     }
387     else
388     {
389         // we don't have valid credentials, so cancel all transfers and reset
390         reset();
391     }
392 
393 /*
394         progressBar()->show();
395         progressBar()->setFormat("");
396 */
397 }
398 
slotListPhotosDone(const QList<YandexFotkiPhoto> & photosList)399 void YandexFotkiWindow::slotListPhotosDone(const QList <YandexFotkiPhoto>& photosList)
400 {
401     if (m_import)
402     {
403         slotListPhotosDoneForDownload(photosList);
404     }
405     else
406     {
407         slotListPhotosDoneForUpload(photosList);
408     }
409 }
410 
slotListPhotosDoneForDownload(const QList<YandexFotkiPhoto> & photosList)411 void YandexFotkiWindow::slotListPhotosDoneForDownload(const QList <YandexFotkiPhoto>& photosList)
412 {
413     Q_UNUSED(photosList);
414     updateControls(true);
415 }
416 
slotListPhotosDoneForUpload(const QList<YandexFotkiPhoto> & photosList)417 void YandexFotkiWindow::slotListPhotosDoneForUpload(const QList <YandexFotkiPhoto>& photosList)
418 {
419     updateControls(true);
420 
421     QMap<QString, int> dups;
422     int i = 0;
423 
424     foreach(const YandexFotkiPhoto& photo, photosList)
425     {
426         dups.insert(photo.urn(), i);
427         i++;
428     }
429 
430     YandexFotkiWidget::UpdatePolicy policy = static_cast<YandexFotkiWidget::UpdatePolicy>(m_policyGroup->checkedId());
431     const YandexFotkiPhoto::Access access = static_cast<YandexFotkiPhoto::Access>(
432                                             m_accessCombo->itemData(m_accessCombo->currentIndex()).toInt());
433 
434     qCDebug(KIPIPLUGINS_LOG) << "";
435     qCDebug(KIPIPLUGINS_LOG) << "----";
436     m_transferQueue.clear();
437 
438     foreach(const QUrl& url, m_imgList->imageUrls(true))
439     {
440         KPImageInfo info(url);
441 
442         // check if photo alredy uploaded
443 
444         int oldPhotoId = -1;
445 
446         if (m_meta && m_meta->load(url))
447         {
448             QString localId = m_meta->getXmpTagString(QLatin1String(XMP_SERVICE_ID));
449             oldPhotoId      = dups.value(localId, -1);
450         }
451 
452         // get tags
453         QStringList tags = info.tagsPath();
454         bool updateFile  = true;
455 
456         QSet<QString> oldtags;
457 
458         if (oldPhotoId != -1)
459         {
460             if (policy == YandexFotkiWidget::UpdatePolicy::POLICY_SKIP)
461             {
462                 qCDebug(KIPIPLUGINS_LOG) << "SKIP: " << url;
463                 continue;
464             }
465 
466             // old photo copy
467             m_transferQueue.push(photosList[oldPhotoId]);
468 
469             if (policy == YandexFotkiWidget::UpdatePolicy::POLICY_UPDATE_MERGE)
470             {
471                 foreach(const QString& t, m_transferQueue.top().tags)
472                 {
473                     oldtags.insert(t);
474                 }
475             }
476 
477             if (policy != YandexFotkiWidget::UpdatePolicy::POLICY_ADDNEW)
478             {
479                 updateFile = false;
480             }
481         }
482         else
483         {
484             // empty photo
485             m_transferQueue.push(YandexFotkiPhoto());
486         }
487 
488         YandexFotkiPhoto& photo = m_transferQueue.top();
489         // TODO: updateFile is not used
490         photo.setOriginalUrl(url.toLocalFile());
491         photo.setTitle(info.name());
492         photo.setSummary(info.description());
493         photo.setAccess(access);
494         photo.setHideOriginal(m_hideOriginalCheck->isChecked());
495         photo.setDisableComments(m_disableCommentsCheck->isChecked());
496 
497         // adult flag can't be removed, API restrictions
498         if (!photo.isAdult())
499             photo.setAdult(m_adultCheck->isChecked());
500 
501         foreach(const QString& t, tags)
502         {
503             if (!oldtags.contains(t))
504             {
505                 photo.tags.append(t);
506             }
507         }
508 
509         if (updateFile)
510         {
511             qCDebug(KIPIPLUGINS_LOG) << "METADATA + IMAGE: " << url;
512         }
513         else
514         {
515             qCDebug(KIPIPLUGINS_LOG) << "METADATA: " << url;
516         }
517     }
518 
519     if (m_transferQueue.isEmpty())
520     {
521         return;    // nothing to do
522     }
523 
524     qCDebug(KIPIPLUGINS_LOG) << "----";
525     qCDebug(KIPIPLUGINS_LOG) << "";
526 
527     updateControls(false);
528     updateNextPhoto();
529 }
530 
updateNextPhoto()531 void YandexFotkiWindow::updateNextPhoto()
532 {
533     // select only one image from stack
534     while (!m_transferQueue.isEmpty())
535     {
536         YandexFotkiPhoto& photo = m_transferQueue.top();
537 
538         if (!photo.originalUrl().isNull())
539         {
540             QImage image;
541 
542             if (iface())
543             {
544                 image = iface()->preview(QUrl::fromLocalFile(photo.originalUrl()));
545             }
546 
547             if (image.isNull())
548             {
549                 image.load(photo.originalUrl());
550             }
551 
552             photo.setLocalUrl(m_tmpDir + QFileInfo(photo.originalUrl())
553                               .baseName()
554                               .trimmed() + QString::fromLatin1(".jpg"));
555 
556             bool prepared = false;
557 
558             if (!image.isNull())
559             {
560                 // get temporary file name
561 
562                 // rescale image if requested
563                 int maxDim = m_dimensionSpin->value();
564 
565                 if (m_resizeCheck->isChecked() && (image.width() > maxDim || image.height() > maxDim))
566                 {
567                     qCDebug(KIPIPLUGINS_LOG) << "Resizing to " << maxDim;
568                     image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio,
569                                          Qt::SmoothTransformation);
570                 }
571 
572                 // copy meta data to temporary image
573 
574                 if (image.save(photo.localUrl(), "JPEG", m_imageQualitySpin->value()))
575                 {
576                     if (m_meta && m_meta->load(QUrl::fromLocalFile(photo.originalUrl())))
577                     {
578                         m_meta->setImageDimensions(image.size());
579                         m_meta->setImageOrientation(MetadataProcessor::NORMAL);
580                         m_meta->setImageProgramId(QString::fromLatin1("Kipi-plugins"), kipipluginsVersion());
581                         m_meta->save(QUrl::fromLocalFile(photo.localUrl()), true);
582                         prepared = true;
583                     }
584                 }
585             }
586 
587             if (!prepared)
588             {
589                 if (QMessageBox::question(this, i18n("Processing Failed"),
590                                   i18n("Failed to prepare image %1\n"
591                                        "Do you want to continue?", photo.originalUrl()))
592                     != QMessageBox::Yes)
593                 {
594                     // stop uploading
595                     m_transferQueue.clear();
596                     continue;
597                 }
598                 else
599                 {
600                     m_transferQueue.pop();
601                     continue;
602                 }
603             }
604         }
605 
606         const YandexFotkiAlbum& album = m_talker.albums().at(m_albumsCombo->currentIndex());
607 
608         qCDebug(KIPIPLUGINS_LOG) << photo.originalUrl();
609 
610         m_talker.updatePhoto(photo, album);
611 
612         return;
613     }
614 
615     updateControls(true);
616 
617     QMessageBox::information(this, QString(), i18n("Images have been uploaded"));
618     return;
619 }
620 
slotNewAlbumRequest()621 void YandexFotkiWindow::slotNewAlbumRequest()
622 {
623     YandexFotkiAlbum album;
624     QPointer<YandexFotkiAlbumDialog> dlg = new YandexFotkiAlbumDialog(this, album);
625 
626     if (dlg->exec() == QDialog::Accepted)
627     {
628         updateControls(false);
629         m_talker.updateAlbum(album);
630     }
631 
632     delete dlg;
633 }
634 
slotReloadAlbumsRequest()635 void YandexFotkiWindow::slotReloadAlbumsRequest()
636 {
637     updateControls(false);
638     m_talker.listAlbums();
639 }
640 
slotStartTransfer()641 void YandexFotkiWindow::slotStartTransfer()
642 {
643     qCDebug(KIPIPLUGINS_LOG) << "slotStartTransfer invoked";
644 
645     if (m_albumsCombo->currentIndex() == -1 || m_albumsCombo->count() == 0)
646     {
647         QMessageBox::information(this, QString(), i18n("Please select album first"));
648         return;
649     }
650 
651     // TODO: import support
652     if (!m_import)
653     {
654         // list photos of the album, then start upload
655         const YandexFotkiAlbum& album = m_talker.albums().at(m_albumsCombo->currentIndex());
656 
657         qCDebug(KIPIPLUGINS_LOG) << "Album selected" << album;
658 
659         updateControls(false);
660         m_talker.listPhotos(album);
661     }
662 }
663 
slotError()664 void YandexFotkiWindow::slotError()
665 {
666     switch (m_talker.state())
667     {
668         case YandexFotkiTalker::STATE_GETSESSION_ERROR:
669             QMessageBox::critical(this, QString(), i18n("Session error"));
670             break;
671         case YandexFotkiTalker::STATE_GETTOKEN_ERROR:
672             QMessageBox::critical(this, QString(), i18n("Token error"));
673             break;
674         case YandexFotkiTalker::STATE_INVALID_CREDENTIALS:
675             QMessageBox::critical(this, QString(), i18n("Invalid credentials"));
676 //            authenticate(true);
677             break;
678         case YandexFotkiTalker::STATE_GETSERVICE_ERROR:
679             QMessageBox::critical(this, QString(), i18n("Cannot get service document"));
680             break;
681 /*
682         case YandexFotkiTalker::STATE_CHECKTOKEN_INVALID:
683             // remove old expired token
684             qCDebug(KIPIPLUGINS_LOG) << "CheckToken invalid";
685             m_talker.setToken(QString());
686             // don't say anything, simple show new auth window
687             authenticate(true);
688             break;
689 */
690         case YandexFotkiTalker::STATE_LISTALBUMS_ERROR:
691             m_albumsCombo->clear();
692             QMessageBox::critical(this, QString(), i18n("Cannot list albums"));
693             break;
694         case YandexFotkiTalker::STATE_LISTPHOTOS_ERROR:
695             QMessageBox::critical(this, QString(), i18n("Cannot list photos"));
696             break;
697         case YandexFotkiTalker::STATE_UPDATEALBUM_ERROR:
698             QMessageBox::critical(this, QString(), i18n("Cannot update album info"));
699             break;
700         case YandexFotkiTalker::STATE_UPDATEPHOTO_FILE_ERROR:
701         case YandexFotkiTalker::STATE_UPDATEPHOTO_INFO_ERROR:
702             qCDebug(KIPIPLUGINS_LOG) << "UpdatePhotoError";
703 
704             if (QMessageBox::question(this, i18n("Uploading Failed"),
705                                       i18n("Failed to upload image %1\n"
706                                            "Do you want to continue?",
707                                       m_transferQueue.top().originalUrl()))
708                 != QMessageBox::Yes)
709             {
710                 // clear upload stack
711                 m_transferQueue.clear();
712             }
713             else
714             {
715                 // cancel current operation
716                 m_talker.cancel();
717                 // remove only bad image
718                 m_transferQueue.pop();
719                 // and try next
720                 updateNextPhoto();
721                 return;
722             }
723             break;
724         default:
725             qCDebug(KIPIPLUGINS_LOG) << "Unhandled error" << m_talker.state();
726             QMessageBox::critical(this, QString(), i18n("Unknown error"));
727     }
728 
729     // cancel current operation
730     m_talker.cancel();
731     updateControls(true);
732 }
733 
slotGetServiceDone()734 void YandexFotkiWindow::slotGetServiceDone()
735 {
736     qCDebug(KIPIPLUGINS_LOG) << "GetService Done";
737     m_talker.getSession();
738 }
739 
slotGetSessionDone()740 void YandexFotkiWindow::slotGetSessionDone()
741 {
742     qCDebug(KIPIPLUGINS_LOG) << "GetSession Done";
743     m_talker.getToken();
744 }
745 
slotGetTokenDone()746 void YandexFotkiWindow::slotGetTokenDone()
747 {
748     updateLabels();
749     slotReloadAlbumsRequest();
750 }
751 
slotListAlbumsDone(const QList<YandexFotkiAlbum> & albumsList)752 void YandexFotkiWindow::slotListAlbumsDone(const QList<YandexFotkiAlbum>& albumsList)
753 {
754     m_albumsCombo->clear();
755 
756     foreach(const YandexFotkiAlbum& album, albumsList)
757     {
758         QString albumIcon;
759 
760         if (album.isProtected())
761         {
762             albumIcon = QString::fromLatin1("folder-locked");
763         }
764         else
765         {
766             albumIcon = QString::fromLatin1("folder-image");
767         }
768 
769         m_albumsCombo->addItem(QIcon::fromTheme(albumIcon), album.toString());
770     }
771 
772     m_albumsCombo->setEnabled(true);
773     updateControls(true);
774 }
775 
slotUpdatePhotoDone(YandexFotkiPhoto & photo)776 void YandexFotkiWindow::slotUpdatePhotoDone(YandexFotkiPhoto& photo)
777 {
778     qCDebug(KIPIPLUGINS_LOG) << "photoUploaded" << photo;
779 
780     if (m_meta && m_meta->supportXmp() && m_meta->canWriteXmp(QUrl::fromLocalFile(photo.originalUrl())) &&
781         m_meta->load(QUrl::fromLocalFile(photo.originalUrl())))
782     {
783         // ignore errors here
784         if (m_meta->setXmpTagString(QLatin1String(XMP_SERVICE_ID), photo.urn()) &&
785             m_meta->save(QUrl::fromLocalFile(photo.originalUrl())))
786         {
787             qCDebug(KIPIPLUGINS_LOG) << "MARK: " << photo.originalUrl();
788         }
789     }
790 
791     m_transferQueue.pop();
792     updateNextPhoto();
793 }
794 
slotUpdateAlbumDone()795 void YandexFotkiWindow::slotUpdateAlbumDone()
796 {
797     qCDebug(KIPIPLUGINS_LOG) << "Album created";
798     m_albumsCombo->clear();
799     m_talker.listAlbums();
800 }
801 
802 } // namespace KIPIYandexFotkiPlugin
803