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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-17-06
0007  * Description : a tool to export images to Smugmug web service
0008  *
0009  * SPDX-FileCopyrightText: 2005-2008 by Vardhman Jain <vardhman at gmail dot com>
0010  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2008-2009 by Luka Renko <lure at kubuntu dot org>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "smugwindow.h"
0018 
0019 // Qt includes
0020 
0021 #include <QWindow>
0022 #include <QFileInfo>
0023 #include <QPointer>
0024 #include <QSpinBox>
0025 #include <QCheckBox>
0026 #include <QGroupBox>
0027 #include <QMenu>
0028 #include <QComboBox>
0029 #include <QPushButton>
0030 #include <QMessageBox>
0031 #include <QApplication>
0032 
0033 // KDE includes
0034 
0035 #include <klocalizedstring.h>
0036 #include <ksharedconfig.h>
0037 #include <kconfiggroup.h>
0038 
0039 // Local includes
0040 
0041 #include "digikam_debug.h"
0042 #include "ditemslist.h"
0043 #include "wstoolutils.h"
0044 #include "digikam_version.h"
0045 #include "dprogresswdg.h"
0046 #include "dmetadata.h"
0047 #include "previewloadthread.h"
0048 #include "smugtalker.h"
0049 #include "smugwidget.h"
0050 #include "smugnewalbumdlg.h"
0051 
0052 namespace DigikamGenericSmugPlugin
0053 {
0054 
0055 class Q_DECL_HIDDEN SmugWindow::Private
0056 {
0057 public:
0058 
0059     explicit Private()
0060       : import           (false),
0061         imagesCount      (0),
0062         imagesTotal      (0),
0063         anonymousImport  (false),
0064         currentAlbumID   (0),
0065         currentTmplID    (0),
0066         currentCategoryID(0),
0067         loginDlg         (nullptr),
0068         talker           (nullptr),
0069         widget           (nullptr),
0070         albumDlg         (nullptr),
0071         iface            (nullptr)
0072     {
0073     }
0074 
0075     bool             import;
0076     unsigned int     imagesCount;
0077     unsigned int     imagesTotal;
0078     QString          tmpDir;
0079     QString          tmpPath;
0080 
0081     bool             anonymousImport;
0082     QString          anonymousNick;
0083     QString          email;
0084     QString          password;
0085     qint64           currentAlbumID;
0086     QString          currentAlbumKey;
0087     qint64           currentTmplID;
0088     qint64           currentCategoryID;
0089 
0090     WSLoginDialog*   loginDlg;
0091 
0092     QList<QUrl>      transferQueue;
0093 
0094     SmugTalker*      talker;
0095     SmugWidget*      widget;
0096     SmugNewAlbumDlg* albumDlg;
0097 
0098     DInfoInterface*  iface;
0099 };
0100 
0101 SmugWindow::SmugWindow(DInfoInterface* const iface,
0102                        QWidget* const /*parent*/,
0103                        bool import,
0104                        const QString& /*nickName*/)
0105     : WSToolDialog(nullptr, QString::fromLatin1("Smug %1 Dialog").arg(import ? QLatin1String("Import")
0106                                                                              : QLatin1String("Export"))),
0107       d           (new Private)
0108 {
0109     d->tmpPath.clear();
0110     d->tmpDir        = WSToolUtils::makeTemporaryDir("smug").absolutePath() + QLatin1Char('/');;
0111     d->import        = import;
0112     d->iface         = iface;
0113     d->widget        = new SmugWidget(this, iface, import);
0114 
0115     setMainWidget(d->widget);
0116     setModal(false);
0117 
0118     if (import)
0119     {
0120         setWindowTitle(i18nc("@title:window", "Import from SmugMug Web Service"));
0121 
0122         startButton()->setText(i18nc("@action:button", "Start Download"));
0123         startButton()->setToolTip(i18nc("@info:tooltip, button", "Start download from SmugMug web service"));
0124 
0125         d->widget->setMinimumSize(300, 400);
0126     }
0127     else
0128     {
0129         setWindowTitle(i18nc("@title:window", "Export to SmugMug Web Service"));
0130 
0131         startButton()->setText(i18nc("@action:button", "Start Upload"));
0132         startButton()->setToolTip(i18nc("@info:tooltip, button", "Start upload to SmugMug web service"));
0133 
0134         d->widget->setMinimumSize(700, 500);
0135     }
0136 
0137     connect(d->widget, SIGNAL(signalUserChangeRequest(bool)),
0138             this, SLOT(slotUserChangeRequest(bool)) );
0139 
0140     connect(d->widget->m_imgList, SIGNAL(signalImageListChanged()),
0141             this, SLOT(slotImageListChanged()) );
0142 
0143     connect(d->widget->m_reloadAlbumsBtn, SIGNAL(clicked()),
0144             this, SLOT(slotReloadAlbumsRequest()) );
0145 
0146     connect(d->widget->m_newAlbumBtn, SIGNAL(clicked()),
0147             this, SLOT(slotNewAlbumRequest()) );
0148 
0149     connect(startButton(), &QPushButton::clicked,
0150             this, &SmugWindow::slotStartTransfer);
0151 
0152     connect(this, &WSToolDialog::cancelClicked,
0153             this, &SmugWindow::slotCancelClicked);
0154 
0155     connect(this, &QDialog::finished,
0156             this, &SmugWindow::slotDialogFinished);
0157 
0158     // ------------------------------------------------------------------------
0159 
0160 /*  This is deprecated because we know use O2 to login
0161 
0162     if (nickName.isEmpty())
0163     {
0164         d->loginDlg  = new WSLoginDialog(this,
0165                                          i18n("<qt>Enter the <b>email address</b> and <b>password</b> for your "
0166                                          "<a href=\"http://www.smugmug.com\">SmugMug</a> account</qt>"));       // krazy:exclude=insecurenet
0167     }
0168 */
0169 
0170     // ------------------------------------------------------------------------
0171 
0172     d->albumDlg  = new SmugNewAlbumDlg(this);
0173 
0174 /*  Categories are deprecated
0175 
0176     connect(d->albumDlg->categoryCombo(), SIGNAL(currentIndexChanged(int)),
0177             this, SLOT(slotCategorySelectionChanged(int)));
0178 
0179     connect(d->albumDlg->templateCombo(), SIGNAL(currentIndexChanged(int)),
0180             this, SLOT(slotTemplateSelectionChanged(int)));
0181 */
0182 
0183     // ------------------------------------------------------------------------
0184 
0185     d->talker = new SmugTalker(d->iface, this);
0186 
0187     connect(d->talker, SIGNAL(signalBusy(bool)),
0188             this, SLOT(slotBusy(bool)));
0189 
0190     connect(d->talker, SIGNAL(signalLoginProgress(int,int,QString)),
0191             this, SLOT(slotLoginProgress(int,int,QString)));
0192 
0193     connect(d->talker, SIGNAL(signalLoginDone(int,QString)),
0194             this, SLOT(slotLoginDone(int,QString)));
0195 
0196     connect(d->talker, SIGNAL(signalAddPhotoDone(int,QString)),
0197             this, SLOT(slotAddPhotoDone(int,QString)));
0198 
0199     connect(d->talker, SIGNAL(signalGetPhotoDone(int,QString,QByteArray)),
0200             this, SLOT(slotGetPhotoDone(int,QString,QByteArray)));
0201 
0202     connect(d->talker, SIGNAL(signalCreateAlbumDone(int,QString,qint64,QString)),
0203             this, SLOT(slotCreateAlbumDone(int,QString,qint64,QString)));
0204 
0205     connect(d->talker, SIGNAL(signalListAlbumsDone(int,QString,QList<SmugAlbum>)),
0206             this, SLOT(slotListAlbumsDone(int,QString,QList<SmugAlbum>)));
0207 
0208     connect(d->talker, SIGNAL(signalListPhotosDone(int,QString,QList<SmugPhoto>)),
0209             this, SLOT(slotListPhotosDone(int,QString,QList<SmugPhoto>)));
0210 
0211     connect(d->talker, SIGNAL(signalListAlbumTmplDone(int,QString,QList<SmugAlbumTmpl>)),
0212             this, SLOT(slotListAlbumTmplDone(int,QString,QList<SmugAlbumTmpl>)));
0213 
0214 /*  Categories deprecated in API v2
0215 
0216     connect(d->talker, SIGNAL(signalListCategoriesDone(int,QString,QList<SmugCategory>)),
0217             this, SLOT(slotListCategoriesDone(int,QString,QList<SmugCategory>)));
0218 
0219     connect(d->talker, SIGNAL(signalListSubCategoriesDone(int,QString,QList<SmugCategory>)),
0220             this, SLOT(slotListSubCategoriesDone(int,QString,QList<SmugCategory>)));
0221 */
0222 
0223     connect(d->widget->progressBar(), SIGNAL(signalProgressCanceled()),
0224             this, SLOT(slotStopAndCloseProgressBar()));
0225 
0226     // ------------------------------------------------------------------------
0227 
0228     readSettings();
0229 
0230     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling Login method";
0231     buttonStateChange(d->talker->loggedIn());
0232 
0233     authenticate();
0234 
0235 //     if (!nickName.isEmpty())
0236 //     {
0237 //         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "login with nickname";
0238 //         authenticateWithNickName(nickName);
0239 //     }
0240 //     else
0241 //     {
0242 //         if (d->import)
0243 //         {
0244 //             // if no e-mail, switch to anonymous login
0245 //             if (d->anonymousImport || d->email.isEmpty())
0246 //             {
0247 //                 d->anonymousImport = true;
0248 //                 authenticate();
0249 //             }
0250 //             else
0251 //             {
0252 //                 authenticate(d->email, d->password);
0253 //             }
0254 //
0255 //             d->widget->setAnonymous(d->anonymousImport);
0256 //         }
0257 //         else
0258 //         {
0259 //             // export cannot login anonymously: pop-up login window`
0260 //             if (d->email.isEmpty())
0261 //                 slotUserChangeRequest(false);
0262 //             else
0263 //                 authenticate(d->email, d->password);
0264 //         }
0265 //     }
0266 }
0267 
0268 SmugWindow::~SmugWindow()
0269 {
0270     WSToolUtils::removeTemporaryDir("smug");
0271 
0272     delete d->talker;
0273     delete d;
0274 }
0275 
0276 void SmugWindow::closeEvent(QCloseEvent* e)
0277 {
0278     if (!e)
0279     {
0280         return;
0281     }
0282 
0283     slotDialogFinished();
0284     e->accept();
0285 }
0286 
0287 void SmugWindow::slotDialogFinished()
0288 {
0289     slotCancelClicked();
0290 
0291 /*  We should not logout without user consent
0292 
0293     if (d->talker->loggedIn())
0294     {
0295         d->talker->logout();
0296     }
0297 */
0298 
0299     writeSettings();
0300     d->widget->imagesList()->listView()->clear();
0301 }
0302 
0303 void SmugWindow::setUiInProgressState(bool inProgress)
0304 {
0305     setRejectButtonMode(inProgress ? QDialogButtonBox::Cancel
0306                                    : QDialogButtonBox::Close);
0307 
0308     if (inProgress)
0309     {
0310         d->widget->progressBar()->show();
0311     }
0312     else
0313     {
0314         d->widget->progressBar()->hide();
0315         d->widget->progressBar()->progressCompleted();
0316     }
0317 }
0318 
0319 void SmugWindow::slotCancelClicked()
0320 {
0321     d->talker->cancel();
0322     d->transferQueue.clear();
0323     d->widget->m_imgList->cancelProcess();
0324     setUiInProgressState(false);
0325 }
0326 
0327 void SmugWindow::slotStopAndCloseProgressBar()
0328 {
0329     slotCancelClicked();
0330 
0331     writeSettings();
0332     d->widget->imagesList()->listView()->clear();
0333     reject();
0334 }
0335 
0336 void SmugWindow::reactivate()
0337 {
0338     d->widget->imagesList()->loadImagesFromCurrentSelection();
0339     show();
0340 }
0341 
0342 void SmugWindow::authenticate()
0343 {
0344     setUiInProgressState(true);
0345     d->widget->progressBar()->setFormat(QString());
0346 
0347     d->talker->login();
0348 }
0349 
0350 void SmugWindow::readSettings()
0351 {
0352     KSharedConfigPtr config = KSharedConfig::openConfig();
0353     KConfigGroup grp        = config->group(QLatin1String("Smug Settings"));
0354     d->anonymousImport      = grp.readEntry("AnonymousImport", true);
0355     d->email                = grp.readEntry("Email");
0356     d->password             = grp.readEntry("Password");
0357     d->currentAlbumID       = grp.readEntry("Current Album",   -1);
0358     d->currentAlbumKey      = grp.readEntry("Current Key");
0359 
0360     if (grp.readEntry("Resize", false))
0361     {
0362         d->widget->m_resizeChB->setChecked(true);
0363         d->widget->m_dimensionSpB->setEnabled(true);
0364         d->widget->m_imageQualitySpB->setEnabled(true);
0365     }
0366     else
0367     {
0368         d->widget->m_resizeChB->setChecked(false);
0369         d->widget->m_dimensionSpB->setEnabled(false);
0370         d->widget->m_imageQualitySpB->setEnabled(false);
0371     }
0372 
0373     d->widget->m_dimensionSpB->setValue(grp.readEntry("Maximum Width", 1600));
0374     d->widget->m_imageQualitySpB->setValue(grp.readEntry("Image Quality", 85));
0375 }
0376 
0377 void SmugWindow::writeSettings()
0378 {
0379     KSharedConfigPtr config = KSharedConfig::openConfig();
0380     KConfigGroup grp        = config->group(QLatin1String("Smug Settings"));
0381     grp.writeEntry("AnonymousImport", d->anonymousImport);
0382     grp.writeEntry("Email",           d->email);
0383     grp.writeEntry("Password",        d->password);
0384     grp.writeEntry("Current Album",   d->currentAlbumID);
0385     grp.writeEntry("Current Key",     d->currentAlbumKey);
0386     grp.writeEntry("Resize",          d->widget->m_resizeChB->isChecked());
0387     grp.writeEntry("Maximum Width",   d->widget->m_dimensionSpB->value());
0388     grp.writeEntry("Image Quality",   d->widget->m_imageQualitySpB->value());
0389 }
0390 
0391 void SmugWindow::slotLoginProgress(int step, int maxStep, const QString& label)
0392 {
0393     DProgressWdg* const progressBar = d->widget->progressBar();
0394 
0395     if (!label.isEmpty())
0396     {
0397         progressBar->setFormat(label);
0398     }
0399 
0400     if (maxStep > 0)
0401     {
0402         progressBar->setMaximum(maxStep);
0403     }
0404 
0405     progressBar->setValue(step);
0406 }
0407 
0408 void SmugWindow::slotLoginDone(int errCode, const QString& errMsg)
0409 {
0410     setUiInProgressState(false);
0411 
0412     buttonStateChange(d->talker->loggedIn());
0413     SmugUser user = d->talker->getUser();
0414     d->widget->updateLabels(user.email, user.displayName, user.nickName);
0415     d->widget->m_albumsCoB->clear();
0416 
0417     if ((errCode == 0) && d->talker->loggedIn())
0418     {
0419         if (d->import)
0420         {
0421             d->anonymousImport = d->widget->isAnonymous();
0422 
0423             // anonymous: list albums after login only if nick is not empty
0424 
0425             QString nick = d->widget->getNickName();
0426 
0427             if (!nick.isEmpty() || !d->anonymousImport)
0428             {
0429                 d->talker->listAlbums(nick);
0430             }
0431         }
0432         else
0433         {
0434             // get albums from current user
0435 
0436             d->talker->listAlbums();
0437         }
0438     }
0439     else
0440     {
0441         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("SmugMug call failed: %1\n", errMsg));
0442     }
0443 }
0444 
0445 void SmugWindow::slotListAlbumsDone(int errCode, const QString& errMsg,
0446                                     const QList <SmugAlbum>& albumsList)
0447 {
0448     if (errCode != 0)
0449     {
0450         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("SmugMug call failed: %1\n", errMsg));
0451         return;
0452     }
0453 
0454     d->widget->m_albumsCoB->clear();
0455 
0456     for (int i = 0 ; i < albumsList.size() ; ++i)
0457     {
0458         QString albumIcon;
0459 
0460         if      (!albumsList.at(i).password.isEmpty())
0461         {
0462             albumIcon = QLatin1String("folder-locked");
0463         }
0464         else if (albumsList.at(i).isPublic)
0465         {
0466             albumIcon = QLatin1String("folder-image");
0467         }
0468         else
0469         {
0470             albumIcon = QLatin1String("folder");
0471         }
0472 
0473         QString data = QString::fromLatin1("%1:%2").arg(albumsList.at(i).id).arg(albumsList.at(i).key);
0474         d->widget->m_albumsCoB->addItem(QIcon::fromTheme(albumIcon), albumsList.at(i).title, data);
0475 
0476         if (d->currentAlbumID == albumsList.at(i).id)
0477         {
0478             d->widget->m_albumsCoB->setCurrentIndex(i);
0479         }
0480     }
0481 }
0482 
0483 void SmugWindow::slotListPhotosDone(int errCode, const QString& errMsg,
0484                                     const QList <SmugPhoto>& photosList)
0485 {
0486     if (errCode != 0)
0487     {
0488         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("SmugMug call failed: %1\n", errMsg));
0489         return;
0490     }
0491 
0492     d->transferQueue.clear();
0493 
0494     for (int i = 0 ; i < photosList.size() ; ++i)
0495     {
0496         d->transferQueue.append(QUrl(photosList.at(i).originalURL));
0497     }
0498 
0499     if (d->transferQueue.isEmpty())
0500     {
0501         return;
0502     }
0503 
0504     d->imagesTotal = d->transferQueue.count();
0505     d->imagesCount = 0;
0506 
0507     d->widget->progressBar()->setMaximum(d->imagesTotal);
0508     d->widget->progressBar()->setValue(0);
0509 
0510     // start download with first photo in queue
0511 
0512     downloadNextPhoto();
0513 }
0514 
0515 void SmugWindow::slotListAlbumTmplDone(int errCode, const QString& errMsg,
0516                                        const QList <SmugAlbumTmpl>& albumTList)
0517 {
0518     // always put at least default <none> subcategory
0519 
0520     d->albumDlg->templateCombo()->clear();
0521     d->albumDlg->templateCombo()->addItem(i18n("&lt;none&gt;"), 0);
0522 
0523     if (errCode != 0)
0524     {
0525         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("SmugMug call failed: %1\n", errMsg));
0526         return;
0527     }
0528 
0529     for (int i = 0 ; i < albumTList.size() ; ++i)
0530     {
0531         QString albumIcon;
0532 
0533         if      (!albumTList.at(i).password.isEmpty())
0534         {
0535             albumIcon = QLatin1String("folder-locked");
0536         }
0537         else if (albumTList.at(i).isPublic)
0538         {
0539             albumIcon = QLatin1String("folder-image");
0540         }
0541         else
0542         {
0543             albumIcon = QLatin1String("folder");
0544         }
0545 
0546         d->albumDlg->templateCombo()->addItem(QIcon::fromTheme(albumIcon), albumTList.at(i).name, albumTList.at(i).id);
0547 
0548         if (d->currentTmplID == albumTList.at(i).id)
0549         {
0550             d->albumDlg->templateCombo()->setCurrentIndex(i+1);
0551         }
0552     }
0553 
0554     d->currentTmplID = d->albumDlg->templateCombo()->itemData(d->albumDlg->templateCombo()->currentIndex()).toLongLong();
0555 
0556 /*  Categories now are deprecated in API v2
0557     d->talker->listCategories();
0558 */
0559 }
0560 
0561 /* Categories now are deprecated in API v2
0562 
0563 void SmugWindow::slotListCategoriesDone(int errCode,
0564                                         const QString& errMsg,
0565                                         const QList <SmugCategory>& categoriesList)
0566 {
0567     if (errCode != 0)
0568     {
0569         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("SmugMug call failed: %1\n", errMsg));
0570         return;
0571     }
0572 
0573     d->albumDlg->categoryCombo()->clear();
0574 
0575     for (int i = 0; i < categoriesList.size(); ++i)
0576     {
0577         d->albumDlg->categoryCombo()->addItem(
0578             categoriesList.at(i).name,
0579             categoriesList.at(i).id);
0580 
0581         if (d->currentCategoryID == categoriesList.at(i).id)
0582             d->albumDlg->categoryCombo()->setCurrentIndex(i);
0583     }
0584 
0585     d->currentCategoryID = d->albumDlg->categoryCombo()->itemData(
0586                           d->albumDlg->categoryCombo()->currentIndex()).toLongLong();
0587     d->talker->listSubCategories(d->currentCategoryID);
0588 }
0589 
0590 void SmugWindow::slotListSubCategoriesDone(int errCode,
0591                                            const QString& errMsg,
0592                                            const QList <SmugCategory>& categoriesList)
0593 {
0594     // always put at least default <none> subcategory
0595     d->albumDlg->subCategoryCombo()->clear();
0596     d->albumDlg->subCategoryCombo()->addItem(i18n("&lt;none&gt;"), 0);
0597 
0598     if (errCode != 0)
0599     {
0600         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"),
0601                               i18n("SmugMug call failed: %1\n", errMsg));
0602         return;
0603     }
0604 
0605     for (int i = 0; i < categoriesList.size(); ++i)
0606     {
0607         d->albumDlg->subCategoryCombo()->addItem(
0608             categoriesList.at(i).name,
0609             categoriesList.at(i).id);
0610     }
0611 }
0612 */
0613 
0614 void SmugWindow::slotTemplateSelectionChanged(int index)
0615 {
0616     if (index < 0)
0617     {
0618         return;
0619     }
0620 
0621     d->currentTmplID = d->albumDlg->templateCombo()->itemData(index).toLongLong();
0622 
0623     // if template is selected, then disable Security & Privacy
0624 
0625     d->albumDlg->privateGroupBox()->setEnabled(d->currentTmplID == 0);
0626 }
0627 
0628 /* Categories now are deprecated in API v2
0629 
0630 void SmugWindow::slotCategorySelectionChanged(int index)
0631 {
0632     if (index < 0)
0633         return;
0634 
0635     // subcategories are per category -> reload
0636     d->currentCategoryID = d->albumDlg->categoryCombo()->itemData(index).toLongLong();
0637     d->talker->listSubCategories(d->currentCategoryID);
0638 }
0639 */
0640 
0641 void SmugWindow::buttonStateChange(bool state)
0642 {
0643     d->widget->m_newAlbumBtn->setEnabled(state);
0644     d->widget->m_reloadAlbumsBtn->setEnabled(state);
0645     startButton()->setEnabled(state);
0646 }
0647 
0648 void SmugWindow::slotBusy(bool val)
0649 {
0650     if (val)
0651     {
0652         setCursor(Qt::WaitCursor);
0653         d->widget->m_changeUserBtn->setEnabled(false);
0654         buttonStateChange(false);
0655     }
0656     else
0657     {
0658         setCursor(Qt::ArrowCursor);
0659         d->widget->m_changeUserBtn->setEnabled(!d->widget->isAnonymous());
0660         buttonStateChange(d->talker->loggedIn());
0661     }
0662 }
0663 
0664 void SmugWindow::slotUserChangeRequest(bool /*anonymous*/)
0665 {
0666     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot Change User Request";
0667 
0668     QPointer<QMessageBox> warn = new QMessageBox(QMessageBox::Warning,
0669                                                  i18nc("@title:window", "Warning"),
0670                                                  i18n("You will be logged out of your account, "
0671                                                  "click \"Continue\" to authenticate for another account."),
0672                                                  QMessageBox::Yes | QMessageBox::No);
0673 
0674     (warn->button(QMessageBox::Yes))->setText(i18nc("@action:button", "Continue"));
0675     (warn->button(QMessageBox::No))->setText(i18nc("@action:button", "Cancel"));
0676 
0677     if (warn->exec() == QMessageBox::Yes)
0678     {
0679         // Unlink user account and wait active until really logged out
0680 
0681         d->talker->logout();
0682 
0683         while (d->talker->loggedIn());
0684 
0685         // Re-login
0686 
0687         authenticate();
0688     }
0689 
0690     delete warn;
0691 
0692 /*
0693     if (anonymous)
0694     {
0695         authenticate();
0696     }
0697     else
0698     {
0699         // fill in current email and password
0700 
0701         d->loginDlg->setLogin(d->email);
0702         d->loginDlg->setPassword(d->password);
0703 
0704         if (d->loginDlg->exec())
0705         {
0706             d->email    = d->loginDlg->login();
0707             d->password = d->loginDlg->password();
0708             authenticate(d->email, d->password);
0709         }
0710     }
0711 */
0712 }
0713 
0714 void SmugWindow::slotReloadAlbumsRequest()
0715 {
0716     if (d->import)
0717     {
0718         d->talker->listAlbums(d->widget->getNickName());
0719     }
0720     else
0721     {
0722         // get albums for current user
0723 
0724         d->talker->listAlbums();
0725     }
0726 }
0727 
0728 void SmugWindow::slotNewAlbumRequest()
0729 {
0730     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot New Album Request";
0731 
0732     // get list of album templates from SmugMug to fill in dialog
0733 
0734     d->talker->listAlbumTmpl();
0735 
0736     if (d->albumDlg->exec() == QDialog::Accepted)
0737     {
0738         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling New Album method";
0739         d->currentTmplID = d->albumDlg->templateCombo()->itemData(
0740             d->albumDlg->templateCombo()->currentIndex()).toLongLong();
0741 
0742 /* Categories are deprecated
0743     d->currentCategoryID = d->albumDlg->categoryCombo()->itemData(
0744         d->albumDlg->categoryCombo()->currentIndex()).toLongLong();
0745 */
0746 
0747         SmugAlbum newAlbum;
0748         d->albumDlg->getAlbumProperties(newAlbum);
0749         d->talker->createAlbum(newAlbum);
0750     }
0751 }
0752 
0753 void SmugWindow::slotStartTransfer()
0754 {
0755     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotStartTransfer invoked";
0756 
0757     if (d->import)
0758     {
0759         d->widget->progressBar()->setFormat(i18n("%v / %m"));
0760         d->widget->progressBar()->setMaximum(0);
0761         d->widget->progressBar()->setValue(0);
0762         d->widget->progressBar()->progressScheduled(i18n("SmugMug Import"), true, true);
0763         d->widget->progressBar()->progressThumbnailChanged(
0764             QIcon::fromTheme(QLatin1String("dk-smugmug")).pixmap(22, 22));
0765         setUiInProgressState(true);
0766 
0767         // list photos of the album, then start download
0768 
0769         QString dataStr  = d->widget->m_albumsCoB->itemData(d->widget->m_albumsCoB->currentIndex()).toString();
0770         int colonIdx     = dataStr.indexOf(QLatin1Char(':'));
0771         qint64 albumID   = dataStr.left(colonIdx).toLongLong();
0772         QString albumKey = dataStr.right(dataStr.length() - colonIdx - 1);
0773         d->talker->listPhotos(albumID, albumKey,
0774                              d->widget->getAlbumPassword(),
0775                              d->widget->getSitePassword());
0776     }
0777     else
0778     {
0779         d->widget->m_imgList->clearProcessedStatus();
0780         d->transferQueue = d->widget->m_imgList->imageUrls();
0781 
0782         if (d->transferQueue.isEmpty())
0783         {
0784             return;
0785         }
0786 
0787         QString data       = d->widget->m_albumsCoB->itemData(d->widget->m_albumsCoB->currentIndex()).toString();
0788         int colonIdx       = data.indexOf(QLatin1Char(':'));
0789         d->currentAlbumID  = data.left(colonIdx).toLongLong();
0790         d->currentAlbumKey = data.right(data.length() - colonIdx - 1);
0791 
0792         d->imagesTotal     = d->transferQueue.count();
0793         d->imagesCount     = 0;
0794 
0795         d->widget->progressBar()->setFormat(i18n("%v / %m"));
0796         d->widget->progressBar()->setMaximum(d->imagesTotal);
0797         d->widget->progressBar()->setValue(0);
0798         d->widget->progressBar()->progressScheduled(i18n("SmugMug Export"), true, true);
0799         d->widget->progressBar()->progressThumbnailChanged(
0800             QIcon::fromTheme(QLatin1String("dk-smugmug")).pixmap(22, 22));
0801         setUiInProgressState(true);
0802 
0803         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "d->currentAlbumID" << d->currentAlbumID;
0804         uploadNextPhoto();
0805         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotStartTransfer done";
0806     }
0807 }
0808 
0809 bool SmugWindow::prepareImageForUpload(const QString& imgPath) const
0810 {
0811     QImage image = PreviewLoadThread::loadHighQualitySynchronously(imgPath).copyQImage();
0812 
0813     if (image.isNull())
0814     {
0815        image.load(imgPath);
0816     }
0817 
0818     if (image.isNull())
0819     {
0820         return false;
0821     }
0822 
0823     // get temporary file name
0824 
0825     d->tmpPath  = d->tmpDir + QFileInfo(imgPath).baseName().trimmed() + QLatin1String(".jpg");
0826 
0827     // rescale image if requested
0828 
0829     int maxDim = d->widget->m_dimensionSpB->value();
0830 
0831     if (d->widget->m_resizeChB->isChecked() &&
0832         ((image.width() > maxDim) || (image.height() > maxDim)))
0833     {
0834         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Resizing to " << maxDim;
0835         image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio,
0836                                              Qt::SmoothTransformation);
0837     }
0838 
0839     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Saving to temp file: " << d->tmpPath;
0840     image.save(d->tmpPath, "JPEG", d->widget->m_imageQualitySpB->value());
0841 
0842     // copy meta-data to temporary image
0843 
0844     QScopedPointer<DMetadata> meta(new DMetadata);
0845 
0846     if (meta->load(imgPath))
0847     {
0848         meta->setItemDimensions(image.size());
0849         meta->setItemOrientation(MetaEngine::ORIENTATION_NORMAL);
0850         meta->setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY);
0851         meta->save(d->tmpPath, true);
0852     }
0853 
0854     return true;
0855 }
0856 
0857 void SmugWindow::uploadNextPhoto()
0858 {
0859     if (d->transferQueue.isEmpty())
0860     {
0861         setUiInProgressState(false);
0862         return;
0863     }
0864 
0865     d->widget->m_imgList->processing(d->transferQueue.first());
0866 
0867     QUrl imgPath = d->transferQueue.first();
0868     DItemInfo info(d->iface->itemInfo(imgPath));
0869 
0870     d->widget->progressBar()->setMaximum(d->imagesTotal);
0871     d->widget->progressBar()->setValue(d->imagesCount);
0872 
0873     bool res;
0874 
0875     if (d->widget->m_resizeChB->isChecked())
0876     {
0877         if (!prepareImageForUpload(imgPath.toLocalFile()))
0878         {
0879             slotAddPhotoDone(666, i18n("Cannot open file"));
0880             return;
0881         }
0882 
0883         res = d->talker->addPhoto(d->tmpPath, d->currentAlbumID, d->currentAlbumKey, info.comment());
0884     }
0885     else
0886     {
0887         d->tmpPath.clear();
0888         res = d->talker->addPhoto(imgPath.toLocalFile(), d->currentAlbumID, d->currentAlbumKey, info.comment());
0889     }
0890 
0891     if (!res)
0892     {
0893         slotAddPhotoDone(666, i18n("Cannot open file"));
0894         return;
0895     }
0896 }
0897 
0898 void SmugWindow::slotAddPhotoDone(int errCode, const QString& errMsg)
0899 {
0900     // Remove temporary file if it was used
0901 
0902     if (!d->tmpPath.isEmpty())
0903     {
0904         QFile::remove(d->tmpPath);
0905         d->tmpPath.clear();
0906     }
0907 
0908     d->widget->m_imgList->processed(d->transferQueue.first(), (errCode == 0));
0909 
0910     if (errCode == 0)
0911     {
0912         d->transferQueue.removeFirst();
0913         d->imagesCount++;
0914     }
0915     else
0916     {
0917         if (QMessageBox::question(this, i18nc("@title:window", "Uploading Failed"),
0918                               i18n("Failed to upload photo to SmugMug."
0919                                    "\n%1\n"
0920                                    "Do you want to continue?", errMsg))
0921             != QMessageBox::Yes)
0922         {
0923             setUiInProgressState(false);
0924             d->transferQueue.clear();
0925             return;
0926         }
0927     }
0928 
0929     uploadNextPhoto();
0930 }
0931 
0932 void SmugWindow::downloadNextPhoto()
0933 {
0934     if (d->transferQueue.isEmpty())
0935     {
0936         setUiInProgressState(false);
0937         return;
0938     }
0939 
0940     d->widget->progressBar()->setMaximum(d->imagesTotal);
0941     d->widget->progressBar()->setValue(d->imagesCount);
0942 
0943     QString imgPath = d->transferQueue.first().url();
0944 
0945     d->talker->getPhoto(imgPath);
0946 }
0947 
0948 void SmugWindow::slotGetPhotoDone(int errCode,
0949                                   const QString& errMsg,
0950                                   const QByteArray& photoData)
0951 {
0952     QString imgPath = d->widget->getDestinationPath() + QLatin1Char('/')
0953                       + d->transferQueue.first().fileName();
0954 
0955     qCDebug(DIGIKAM_WEBSERVICES_LOG) << imgPath;
0956 
0957     if (errCode == 0)
0958     {
0959         QString errText;
0960         QFile imgFile(imgPath);
0961 
0962         if      (!imgFile.open(QIODevice::WriteOnly))
0963         {
0964             errText = imgFile.errorString();
0965         }
0966         else if (imgFile.write(photoData) != photoData.size())
0967         {
0968             errText = imgFile.errorString();
0969         }
0970         else
0971         {
0972             imgFile.close();
0973             Q_EMIT updateHostApp(QUrl::fromLocalFile(imgPath));
0974         }
0975 
0976         if (errText.isEmpty())
0977         {
0978             d->transferQueue.removeFirst();
0979             d->imagesCount++;
0980         }
0981         else
0982         {
0983             if (QMessageBox::question(this, i18nc("@title:window", "Processing Failed"),
0984                                       i18n("Failed to save photo: %1\n"
0985                                            "Do you want to continue?", errText))
0986                 != QMessageBox::Yes)
0987             {
0988                 d->transferQueue.clear();
0989                 setUiInProgressState(false);
0990                 return;
0991             }
0992         }
0993     }
0994     else
0995     {
0996         if (QMessageBox::question(this, i18nc("@title:window", "Processing Failed"),
0997                                   i18n("Failed to download photo: %1\n"
0998                                        "Do you want to continue?", errMsg))
0999                 != QMessageBox::Yes)
1000         {
1001             d->transferQueue.clear();
1002             setUiInProgressState(false);
1003             return;
1004         }
1005     }
1006 
1007     downloadNextPhoto();
1008 }
1009 
1010 void SmugWindow::slotCreateAlbumDone(int errCode,
1011                                      const QString& errMsg,
1012                                      qint64 newAlbumID,
1013                                      const QString& newAlbumKey)
1014 {
1015     if (errCode != 0)
1016     {
1017         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("SmugMug call failed: %1\n", errMsg));
1018         return;
1019     }
1020 
1021     // reload album list and automatically select new album
1022 
1023     d->currentAlbumID  = newAlbumID;
1024     d->currentAlbumKey = newAlbumKey;
1025     d->talker->listAlbums();
1026 }
1027 
1028 void SmugWindow::slotImageListChanged()
1029 {
1030     startButton()->setEnabled(!(d->widget->m_imgList->imageUrls().isEmpty()));
1031 }
1032 
1033 } // namespace DigikamGenericSmugPlugin
1034 
1035 #include "moc_smugwindow.cpp"