File indexing completed on 2025-01-19 03:53:10

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2018-05-20
0007  * Description : a tool to export images to Pinterest web service
0008  *
0009  * SPDX-FileCopyrightText: 2018      by Tarek Talaat <tarektalaat93 at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "pwindow.h"
0016 
0017 // Qt includes
0018 
0019 #include <QPointer>
0020 #include <QWindow>
0021 #include <QSpinBox>
0022 #include <QCheckBox>
0023 #include <QMessageBox>
0024 #include <QCloseEvent>
0025 
0026 // KDE includes
0027 
0028 #include <klocalizedstring.h>
0029 #include <ksharedconfig.h>
0030 #include <kconfiggroup.h>
0031 
0032 // Local includes
0033 
0034 #include "digikam_debug.h"
0035 #include "ditemslist.h"
0036 #include "digikam_version.h"
0037 #include "ptalker.h"
0038 #include "pitem.h"
0039 #include "pnewalbumdlg.h"
0040 #include "pwidget.h"
0041 
0042 namespace DigikamGenericPinterestPlugin
0043 {
0044 
0045 class Q_DECL_HIDDEN PWindow::Private
0046 {
0047 public:
0048 
0049     explicit Private()
0050       : imagesCount(0),
0051         imagesTotal(0),
0052         widget     (nullptr),
0053         albumDlg   (nullptr),
0054         talker     (nullptr)
0055     {
0056     }
0057 
0058     unsigned int  imagesCount;
0059     unsigned int  imagesTotal;
0060 
0061     PWidget*      widget;
0062     PNewAlbumDlg* albumDlg;
0063     PTalker*      talker;
0064 
0065     QString       currentAlbumName;
0066     QList<QUrl>   transferQueue;
0067 };
0068 
0069 PWindow::PWindow(DInfoInterface* const iface,
0070                  QWidget* const /*parent*/)
0071     : WSToolDialog(nullptr, QLatin1String("Pinterest Export Dialog")),
0072       d           (new Private)
0073 {
0074     d->widget = new PWidget(this, iface, QLatin1String("Pinterest"));
0075 
0076     d->widget->imagesList()->setIface(iface);
0077 
0078     setMainWidget(d->widget);
0079     setModal(false);
0080     setWindowTitle(i18nc("@title:window", "Export to Pinterest"));
0081 
0082     startButton()->setText(i18nc("@action:button", "Start Upload"));
0083     startButton()->setToolTip(i18nc("@info:tooltip, button", "Start upload to Pinterest"));
0084 
0085     d->widget->setMinimumSize(700, 500);
0086 
0087     connect(d->widget->imagesList(), SIGNAL(signalImageListChanged()),
0088             this, SLOT(slotImageListChanged()));
0089 
0090     connect(d->widget->getChangeUserBtn(), SIGNAL(clicked()),
0091             this, SLOT(slotUserChangeRequest()));
0092 
0093     connect(d->widget->getNewAlbmBtn(), SIGNAL(clicked()),
0094             this, SLOT(slotNewBoardRequest()));
0095 
0096     connect(d->widget->getReloadBtn(), SIGNAL(clicked()),
0097             this, SLOT(slotReloadBoardsRequest()));
0098 
0099     connect(startButton(), SIGNAL(clicked()),
0100             this, SLOT(slotStartTransfer()));
0101 
0102     d->albumDlg = new PNewAlbumDlg(this, QLatin1String("Pinterest"));
0103     d->talker   = new PTalker(this);
0104 
0105     connect(d->talker,SIGNAL(signalBusy(bool)),
0106             this,SLOT(slotBusy(bool)));
0107 
0108     connect(d->talker,SIGNAL(signalLinkingFailed()),
0109             this,SLOT(slotSignalLinkingFailed()));
0110 
0111     connect(d->talker,SIGNAL(signalNetworkError()),
0112             this,SLOT(slotTransferCancel()));
0113 
0114     connect(d->talker,SIGNAL(signalLinkingSucceeded()),
0115             this,SLOT(slotSignalLinkingSucceeded()));
0116 
0117     connect(d->talker,SIGNAL(signalSetUserName(QString)),
0118             this,SLOT(slotSetUserName(QString)));
0119 
0120     connect(d->talker,SIGNAL(signalListBoardsFailed(QString)),
0121             this,SLOT(slotListBoardsFailed(QString)));
0122 
0123     connect(d->talker,SIGNAL(signalListBoardsDone(QList<QPair<QString,QString> >)), // krazy:exclude=normalize
0124             this,SLOT(slotListBoardsDone(QList<QPair<QString,QString> >)));         // krazy:exclude=normalize
0125 
0126     connect(d->talker,SIGNAL(signalCreateBoardFailed(QString)),
0127             this,SLOT(slotCreateBoardFailed(QString)));
0128 
0129     connect(d->talker,SIGNAL(signalCreateBoardSucceeded()),
0130             this,SLOT(slotCreateBoardSucceeded()));
0131 
0132     connect(d->talker,SIGNAL(signalAddPinFailed(QString)),
0133             this,SLOT(slotAddPinFailed(QString)));
0134 
0135     connect(d->talker,SIGNAL(signalAddPinSucceeded()),
0136             this,SLOT(slotAddPinSucceeded()));
0137 
0138     connect(this, SIGNAL(finished(int)),
0139             this, SLOT(slotFinished()));
0140 
0141     readSettings();
0142     buttonStateChange(false);
0143 
0144     d->talker->readSettings();
0145 }
0146 
0147 PWindow::~PWindow()
0148 {
0149     delete d->widget;
0150     delete d->albumDlg;
0151     delete d->talker;
0152     delete d;
0153 }
0154 
0155 void PWindow::readSettings()
0156 {
0157     KSharedConfigPtr config = KSharedConfig::openConfig();
0158     KConfigGroup grp        = config->group(QLatin1String("Pinterest Settings"));
0159     d->currentAlbumName     = grp.readEntry("Current Album", QString());
0160 
0161     if (grp.readEntry("Resize", false))
0162     {
0163         d->widget->getResizeCheckBox()->setChecked(true);
0164         d->widget->getDimensionSpB()->setEnabled(true);
0165     }
0166     else
0167     {
0168         d->widget->getResizeCheckBox()->setChecked(false);
0169         d->widget->getDimensionSpB()->setEnabled(false);
0170     }
0171 
0172     d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width",  1600));
0173     d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90));
0174 }
0175 
0176 void PWindow::writeSettings()
0177 {
0178     KSharedConfigPtr config = KSharedConfig::openConfig();
0179     KConfigGroup grp        = config->group(QLatin1String("Pinterest Settings"));
0180 
0181     grp.writeEntry("Current Album", d->currentAlbumName);
0182     grp.writeEntry("Resize",        d->widget->getResizeCheckBox()->isChecked());
0183     grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value());
0184     grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value());
0185 }
0186 
0187 void PWindow::reactivate()
0188 {
0189     d->widget->imagesList()->loadImagesFromCurrentSelection();
0190     d->widget->progressBar()->hide();
0191 
0192     show();
0193 }
0194 
0195 void PWindow::setItemsList(const QList<QUrl>& urls)
0196 {
0197     d->widget->imagesList()->slotAddImages(urls);
0198 }
0199 
0200 void PWindow::slotBusy(bool val)
0201 {
0202     if (val)
0203     {
0204         setCursor(Qt::WaitCursor);
0205         d->widget->getChangeUserBtn()->setEnabled(false);
0206         buttonStateChange(false);
0207     }
0208     else
0209     {
0210         setCursor(Qt::ArrowCursor);
0211         d->widget->getChangeUserBtn()->setEnabled(true);
0212         buttonStateChange(true);
0213     }
0214 }
0215 
0216 void PWindow::slotSetUserName(const QString& msg)
0217 {
0218     d->widget->updateLabels(msg, QLatin1String(""));
0219 }
0220 
0221 void PWindow::slotListBoardsDone(const QList<QPair<QString,QString> >& list)
0222 {
0223     d->widget->getAlbumsCoB()->clear();
0224 
0225     for (int i = 0 ; i < list.size() ; ++i)
0226     {
0227         d->widget->getAlbumsCoB()->addItem(
0228             QIcon::fromTheme(QLatin1String("system-users")),
0229         list.value(i).second, list.value(i).first);
0230 
0231         if (d->currentAlbumName == list.value(i).second)
0232         {
0233             d->widget->getAlbumsCoB()->setCurrentIndex(i);
0234         }
0235     }
0236 
0237     buttonStateChange(true);
0238     d->talker->getUserName();
0239 }
0240 
0241 void PWindow::slotStartTransfer()
0242 {
0243     d->widget->imagesList()->clearProcessedStatus();
0244 
0245     if (d->widget->imagesList()->imageUrls().isEmpty())
0246     {
0247         QMessageBox::critical(this, i18nc("@title:window", "Error"),
0248                               i18n("No image selected. Please select which images should be uploaded."));
0249         return;
0250     }
0251 
0252     if (!(d->talker->authenticated()))
0253     {
0254         QPointer<QMessageBox> warn = new QMessageBox(QMessageBox::Warning,
0255             i18nc("@title:window", "Warning"),
0256             i18n("Authentication failed. Click \"Continue\" to authenticate."),
0257             QMessageBox::Yes | QMessageBox::No);
0258 
0259         warn->button(QMessageBox::Yes)->setText(i18nc("@action:button", "Continue"));
0260         warn->button(QMessageBox::No)->setText(i18nc("@action:button", "Cancel"));
0261 
0262         if (warn->exec() == QMessageBox::Yes)
0263         {
0264             d->talker->link();
0265             delete warn;
0266             return;
0267         }
0268         else
0269         {
0270             delete warn;
0271             return;
0272         }
0273     }
0274 
0275     d->transferQueue = d->widget->imagesList()->imageUrls();
0276 
0277     if (d->transferQueue.isEmpty())
0278     {
0279         return;
0280     }
0281 
0282     d->currentAlbumName = d->widget->getAlbumsCoB()->currentText();
0283     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "StartTransfer:" << d->currentAlbumName
0284                                      << "INDEX:" << d->widget->getAlbumsCoB()->currentIndex();
0285     d->imagesTotal      = d->transferQueue.count();
0286     d->imagesCount      = 0;
0287 
0288     d->widget->progressBar()->setFormat(i18n("%v / %m"));
0289     d->widget->progressBar()->setMaximum(d->imagesTotal);
0290     d->widget->progressBar()->setValue(0);
0291     d->widget->progressBar()->show();
0292     d->widget->progressBar()->progressScheduled(i18n("Pinterest export"), true, true);
0293     d->widget->progressBar()->progressThumbnailChanged(
0294         QIcon::fromTheme(QLatin1String("dk-pinterest")).pixmap(22, 22));
0295 
0296     uploadNextPhoto();
0297 }
0298 
0299 void PWindow::uploadNextPhoto()
0300 {
0301     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "uploadNextPhoto:" << d->transferQueue.count();
0302 
0303     if (d->transferQueue.isEmpty())
0304     {
0305         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "empty";
0306         d->widget->progressBar()->progressCompleted();
0307         return;
0308     }
0309 
0310     QString imgPath = d->transferQueue.first().toLocalFile();
0311     QString boardID = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString();
0312 
0313     bool result = d->talker->addPin(imgPath,
0314                                     boardID,
0315                                     d->widget->getResizeCheckBox()->isChecked(),
0316                                     d->widget->getDimensionSpB()->value(),
0317                                     d->widget->getImgQualitySpB()->value());
0318 
0319     if (!result)
0320     {
0321         slotAddPinFailed(QLatin1String(""));
0322         return;
0323     }
0324 }
0325 
0326 void PWindow::slotAddPinFailed(const QString& msg)
0327 {
0328     if (QMessageBox::question(this, i18nc("@title:window", "Uploading Failed"),
0329                               i18n("Failed to upload photo to Pinterest."
0330                                    "\n%1\n"
0331                                    "Do you want to continue?", msg))
0332         != QMessageBox::Yes)
0333     {
0334         d->transferQueue.clear();
0335         d->widget->progressBar()->hide();
0336         d->widget->progressBar()->progressCompleted();
0337     }
0338     else
0339     {
0340         d->transferQueue.pop_front();
0341         d->imagesTotal--;
0342         d->widget->progressBar()->setMaximum(d->imagesTotal);
0343         d->widget->progressBar()->setValue(d->imagesCount);
0344         uploadNextPhoto();
0345     }
0346 }
0347 
0348 void PWindow::slotAddPinSucceeded()
0349 {
0350     // Remove photo uploaded from the list
0351 
0352     d->widget->imagesList()->removeItemByUrl(d->transferQueue.first());
0353     d->transferQueue.pop_front();
0354     d->imagesCount++;
0355     d->widget->progressBar()->setMaximum(d->imagesTotal);
0356     d->widget->progressBar()->setValue(d->imagesCount);
0357     uploadNextPhoto();
0358 }
0359 
0360 void PWindow::slotImageListChanged()
0361 {
0362     startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty()));
0363 }
0364 
0365 void PWindow::slotNewBoardRequest()
0366 {
0367     if (d->albumDlg->exec() == QDialog::Accepted)
0368     {
0369         PFolder newFolder;
0370         d->albumDlg->getFolderTitle(newFolder);
0371         d->currentAlbumName = newFolder.title;
0372         d->talker->createBoard(d->currentAlbumName);
0373     }
0374 }
0375 
0376 void PWindow::slotReloadBoardsRequest()
0377 {
0378     d->talker->listBoards();
0379 }
0380 
0381 void PWindow::slotSignalLinkingFailed()
0382 {
0383     slotSetUserName(QLatin1String(""));
0384     d->widget->getAlbumsCoB()->clear();
0385 
0386     if (QMessageBox::question(this, i18nc("@title:window", "Login Failed"),
0387                               i18n("Authentication failed. Do you want to try again?"))
0388         == QMessageBox::Yes)
0389     {
0390         d->talker->link();
0391     }
0392 }
0393 
0394 void PWindow::slotSignalLinkingSucceeded()
0395 {
0396     d->talker->listBoards();
0397 }
0398 
0399 void PWindow::slotListBoardsFailed(const QString& msg)
0400 {
0401     QMessageBox::critical(this, QString(), i18n("Pinterest call failed:\n%1", msg));
0402 }
0403 
0404 void PWindow::slotCreateBoardFailed(const QString& msg)
0405 {
0406     QMessageBox::critical(this, QString(), i18n("Pinterest call failed:\n%1", msg));
0407 }
0408 
0409 void PWindow::slotCreateBoardSucceeded()
0410 {
0411     d->talker->listBoards();
0412 }
0413 
0414 void PWindow::slotTransferCancel()
0415 {
0416     d->talker->cancel();
0417     d->transferQueue.clear();
0418     d->widget->progressBar()->hide();
0419     d->widget->progressBar()->progressCompleted();
0420 }
0421 
0422 void PWindow::slotUserChangeRequest()
0423 {
0424     slotSetUserName(QLatin1String(""));
0425     d->widget->getAlbumsCoB()->clear();
0426     d->talker->unLink();
0427     d->talker->link();
0428 }
0429 
0430 void PWindow::buttonStateChange(bool state)
0431 {
0432     d->widget->getNewAlbmBtn()->setEnabled(state);
0433     d->widget->getReloadBtn()->setEnabled(state);
0434     startButton()->setEnabled(state);
0435 }
0436 
0437 void PWindow::slotFinished()
0438 {
0439     writeSettings();
0440     slotTransferCancel();
0441     d->widget->imagesList()->listView()->clear();
0442 }
0443 
0444 void PWindow::closeEvent(QCloseEvent* e)
0445 {
0446     if (!e)
0447     {
0448         return;
0449     }
0450 
0451     slotFinished();
0452     e->accept();
0453 }
0454 
0455 } // namespace DigikamGenericPinterestPlugin
0456 
0457 #include "moc_pwindow.cpp"