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

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 Box 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 "boxwindow.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 "boxtalker.h"
0038 #include "boxitem.h"
0039 #include "boxnewalbumdlg.h"
0040 #include "boxwidget.h"
0041 
0042 namespace DigikamGenericBoxPlugin
0043 {
0044 
0045 class Q_DECL_HIDDEN BOXWindow::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     BOXWidget*      widget;
0062     BOXNewAlbumDlg* albumDlg;
0063     BOXTalker*      talker;
0064 
0065     QString         currentAlbumName;
0066     QList<QUrl>     transferQueue;
0067 };
0068 
0069 BOXWindow::BOXWindow(DInfoInterface* const iface,
0070                      QWidget* const /*parent*/)
0071     : WSToolDialog(nullptr, QLatin1String("Box Export Dialog")),
0072       d           (new Private)
0073 {
0074     d->widget = new BOXWidget(this, iface, QLatin1String("Box"));
0075 
0076     d->widget->imagesList()->setIface(iface);
0077 
0078     setMainWidget(d->widget);
0079     setModal(false);
0080     setWindowTitle(i18nc("@title:window", "Export to Box"));
0081 
0082     startButton()->setText(i18nc("@action:button", "Start Upload"));
0083     startButton()->setToolTip(i18nc("@info:tooltip, button", "Start upload to Box"));
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(slotNewAlbumRequest()));
0095 
0096     connect(d->widget->getReloadBtn(), SIGNAL(clicked()),
0097             this, SLOT(slotReloadAlbumsRequest()));
0098 
0099     connect(startButton(), SIGNAL(clicked()),
0100             this, SLOT(slotStartTransfer()));
0101 
0102     d->albumDlg = new BOXNewAlbumDlg(this, QLatin1String("Box"));
0103     d->talker   = new BOXTalker(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(signalLinkingSucceeded()),
0112             this, SLOT(slotSignalLinkingSucceeded()));
0113 
0114     connect(d->talker, SIGNAL(signalSetUserName(QString)),
0115             this, SLOT(slotSetUserName(QString)));
0116 
0117     connect(d->talker, SIGNAL(signalListAlbumsFailed(QString)),
0118             this, SLOT(slotListAlbumsFailed(QString)));
0119 
0120     connect(d->talker, SIGNAL(signalListAlbumsDone(QList<QPair<QString,QString> >)), // krazy:exclude=normalize
0121             this, SLOT(slotListAlbumsDone(QList<QPair<QString,QString> >)));         // krazy:exclude=normalize
0122 
0123     connect(d->talker, SIGNAL(signalCreateFolderFailed(QString)),
0124             this, SLOT(slotCreateFolderFailed(QString)));
0125 
0126     connect(d->talker, SIGNAL(signalCreateFolderSucceeded()),
0127             this, SLOT(slotCreateFolderSucceeded()));
0128 
0129     connect(d->talker, SIGNAL(signalAddPhotoFailed(QString)),
0130             this, SLOT(slotAddPhotoFailed(QString)));
0131 
0132     connect(d->talker, SIGNAL(signalAddPhotoSucceeded()),
0133             this, SLOT(slotAddPhotoSucceeded()));
0134 
0135     connect(this, SIGNAL(finished(int)),
0136             this, SLOT(slotFinished()));
0137 
0138     readSettings();
0139     buttonStateChange(false);
0140 
0141     d->talker->link();
0142 }
0143 
0144 BOXWindow::~BOXWindow()
0145 {
0146     delete d->widget;
0147     delete d->albumDlg;
0148     delete d->talker;
0149     delete d;
0150 }
0151 
0152 void BOXWindow::readSettings()
0153 {
0154     KSharedConfigPtr config = KSharedConfig::openConfig();
0155     KConfigGroup grp        = config->group(QLatin1String("Box Settings"));
0156     d->currentAlbumName     = grp.readEntry("Current Album", QString());
0157 
0158     if (grp.readEntry("Resize", false))
0159     {
0160         d->widget->getResizeCheckBox()->setChecked(true);
0161         d->widget->getDimensionSpB()->setEnabled(true);
0162     }
0163     else
0164     {
0165         d->widget->getResizeCheckBox()->setChecked(false);
0166         d->widget->getDimensionSpB()->setEnabled(false);
0167     }
0168 
0169     d->widget->getDimensionSpB()->setValue(grp.readEntry("Maximum Width",  1600));
0170     d->widget->getImgQualitySpB()->setValue(grp.readEntry("Image Quality", 90));
0171 }
0172 
0173 void BOXWindow::writeSettings()
0174 {
0175     KSharedConfigPtr config = KSharedConfig::openConfig();
0176     KConfigGroup grp        = config->group(QLatin1String("Box Settings"));
0177 
0178     grp.writeEntry("Current Album", d->currentAlbumName);
0179     grp.writeEntry("Resize",        d->widget->getResizeCheckBox()->isChecked());
0180     grp.writeEntry("Maximum Width", d->widget->getDimensionSpB()->value());
0181     grp.writeEntry("Image Quality", d->widget->getImgQualitySpB()->value());
0182 }
0183 
0184 void BOXWindow::reactivate()
0185 {
0186     d->widget->imagesList()->loadImagesFromCurrentSelection();
0187     d->widget->progressBar()->hide();
0188 
0189     show();
0190 }
0191 
0192 void BOXWindow::setItemsList(const QList<QUrl>& urls)
0193 {
0194     d->widget->imagesList()->slotAddImages(urls);
0195 }
0196 
0197 void BOXWindow::slotBusy(bool val)
0198 {
0199     if (val)
0200     {
0201         setCursor(Qt::WaitCursor);
0202         d->widget->getChangeUserBtn()->setEnabled(false);
0203         buttonStateChange(false);
0204     }
0205     else
0206     {
0207         setCursor(Qt::ArrowCursor);
0208         d->widget->getChangeUserBtn()->setEnabled(true);
0209         buttonStateChange(true);
0210     }
0211 }
0212 
0213 void BOXWindow::slotSetUserName(const QString& msg)
0214 {
0215     d->widget->updateLabels(msg, QLatin1String(""));
0216 }
0217 
0218 void BOXWindow::slotListAlbumsDone(const QList<QPair<QString,QString> >& list)
0219 {
0220     d->widget->getAlbumsCoB()->clear();
0221 
0222     for (int i = 0 ; i < list.size() ; ++i)
0223     {
0224         d->widget->getAlbumsCoB()->addItem(
0225             QIcon::fromTheme(QLatin1String("system-users")),
0226             list.value(i).second, list.value(i).second);
0227 
0228         if (d->currentAlbumName == QString(list.value(i).second))
0229         {
0230             d->widget->getAlbumsCoB()->setCurrentIndex(i);
0231         }
0232     }
0233 
0234     buttonStateChange(true);
0235     d->talker->getUserName();
0236 }
0237 
0238 void BOXWindow::slotStartTransfer()
0239 {
0240     d->widget->imagesList()->clearProcessedStatus();
0241 
0242     if (d->widget->imagesList()->imageUrls().isEmpty())
0243     {
0244         QMessageBox::critical(this, i18nc("@title:window", "Error"),
0245                               i18nc("@info", "No image selected. Please select which images should be uploaded."));
0246         return;
0247     }
0248 
0249     if (!(d->talker->authenticated()))
0250     {
0251         QPointer<QMessageBox> warn = new QMessageBox(QMessageBox::Warning,
0252                 i18nc("@title:window", "Warning"),
0253                 i18nc("@info", "Authentication failed. Click \"Continue\" to authenticate."),
0254                 QMessageBox::Yes | QMessageBox::No);
0255 
0256         (warn->button(QMessageBox::Yes))->setText(i18nc("@action:button", "Continue"));
0257         (warn->button(QMessageBox::No))->setText(i18nc("@action:button", "Cancel"));
0258 
0259         if (warn->exec() == QMessageBox::Yes)
0260         {
0261             d->talker->link();
0262             delete warn;
0263             return;
0264         }
0265         else
0266         {
0267             delete warn;
0268             return;
0269         }
0270     }
0271 
0272     d->transferQueue = d->widget->imagesList()->imageUrls();
0273 
0274     if (d->transferQueue.isEmpty())
0275     {
0276         return;
0277     }
0278 
0279     d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString();
0280     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "StartTransfer:" << d->currentAlbumName
0281                                      << "INDEX: " << d->widget->getAlbumsCoB()->currentIndex();
0282     d->imagesTotal = d->transferQueue.count();
0283     d->imagesCount = 0;
0284 
0285     d->widget->progressBar()->setFormat(i18nc("@info: progress bar", "%v / %m"));
0286     d->widget->progressBar()->setMaximum(d->imagesTotal);
0287     d->widget->progressBar()->setValue(0);
0288     d->widget->progressBar()->show();
0289     d->widget->progressBar()->progressScheduled(i18nc("@info", "Box export"), true, true);
0290     d->widget->progressBar()->progressThumbnailChanged(
0291         QIcon::fromTheme(QLatin1String("dk-box")).pixmap(22, 22));
0292 
0293     uploadNextPhoto();
0294 }
0295 
0296 void BOXWindow::uploadNextPhoto()
0297 {
0298     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "uploadNextPhoto:" << d->transferQueue.count();
0299 
0300     if (d->transferQueue.isEmpty())
0301     {
0302         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "empty";
0303         d->widget->progressBar()->progressCompleted();
0304         return;
0305     }
0306 
0307     QString imgPath = d->transferQueue.first().toLocalFile();
0308     QString temp    = d->currentAlbumName;
0309 
0310     bool result = d->talker->addPhoto(imgPath,
0311                                       temp,
0312                                       d->widget->getResizeCheckBox()->isChecked(),
0313                                       d->widget->getDimensionSpB()->value(),
0314                                       d->widget->getImgQualitySpB()->value());
0315 
0316     if (!result)
0317     {
0318         slotAddPhotoFailed(QLatin1String(""));
0319         return;
0320     }
0321 }
0322 
0323 void BOXWindow::slotAddPhotoFailed(const QString& msg)
0324 {
0325     if (QMessageBox::question(this, i18nc("@title:window", "Uploading Failed"),
0326                               i18nc("@info", "Failed to upload photo to Box."
0327                                     "\n%1\n"
0328                                     "Do you want to continue?", msg))
0329         != QMessageBox::Yes)
0330     {
0331         d->transferQueue.clear();
0332         d->widget->progressBar()->hide();
0333     }
0334     else
0335     {
0336         d->transferQueue.pop_front();
0337         d->imagesTotal--;
0338         d->widget->progressBar()->setMaximum(d->imagesTotal);
0339         d->widget->progressBar()->setValue(d->imagesCount);
0340         uploadNextPhoto();
0341     }
0342 }
0343 
0344 void BOXWindow::slotAddPhotoSucceeded()
0345 {
0346     // Remove photo uploaded from the list
0347 
0348     d->widget->imagesList()->removeItemByUrl(d->transferQueue.first());
0349     d->transferQueue.pop_front();
0350     d->imagesCount++;
0351     d->widget->progressBar()->setMaximum(d->imagesTotal);
0352     d->widget->progressBar()->setValue(d->imagesCount);
0353     uploadNextPhoto();
0354 }
0355 
0356 void BOXWindow::slotImageListChanged()
0357 {
0358     startButton()->setEnabled(!(d->widget->imagesList()->imageUrls().isEmpty()));
0359 }
0360 
0361 void BOXWindow::slotNewAlbumRequest()
0362 {
0363     if (d->albumDlg->exec() == QDialog::Accepted)
0364     {
0365         BOXFolder newFolder;
0366         d->albumDlg->getFolderTitle(newFolder);
0367         qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotNewAlbumRequest:" << newFolder.title;
0368         d->currentAlbumName = d->widget->getAlbumsCoB()->itemData(d->widget->getAlbumsCoB()->currentIndex()).toString();
0369         d->currentAlbumName = d->currentAlbumName + newFolder.title;
0370         d->talker->createFolder(d->currentAlbumName);
0371     }
0372 }
0373 
0374 void BOXWindow::slotReloadAlbumsRequest()
0375 {
0376     d->talker->listFolders();
0377 }
0378 
0379 void BOXWindow::slotSignalLinkingFailed()
0380 {
0381     slotSetUserName(QLatin1String(""));
0382     d->widget->getAlbumsCoB()->clear();
0383 
0384     if (QMessageBox::question(this, i18nc("@title:window", "Login Failed"),
0385                               i18nc("@info", "Authentication failed. Do you want to try again?"))
0386         == QMessageBox::Yes)
0387     {
0388         d->talker->link();
0389     }
0390 }
0391 
0392 void BOXWindow::slotSignalLinkingSucceeded()
0393 {
0394     slotBusy(false);
0395     d->talker->listFolders();
0396 }
0397 
0398 void BOXWindow::slotListAlbumsFailed(const QString& msg)
0399 {
0400     QMessageBox::critical(this, QString(), i18nc("@info", "Box call failed:\n%1", msg));
0401 }
0402 
0403 void BOXWindow::slotCreateFolderFailed(const QString& msg)
0404 {
0405     QMessageBox::critical(this, QString(), i18nc("@info", "Box call failed:\n%1", msg));
0406 }
0407 
0408 void BOXWindow::slotCreateFolderSucceeded()
0409 {
0410     d->talker->listFolders();
0411 }
0412 
0413 void BOXWindow::slotTransferCancel()
0414 {
0415     d->transferQueue.clear();
0416     d->widget->progressBar()->hide();
0417     d->talker->cancel();
0418 }
0419 
0420 void BOXWindow::slotUserChangeRequest()
0421 {
0422     slotSetUserName(QLatin1String(""));
0423     d->widget->getAlbumsCoB()->clear();
0424     d->talker->unLink();
0425     d->talker->link();
0426 }
0427 
0428 void BOXWindow::buttonStateChange(bool state)
0429 {
0430     d->widget->getNewAlbmBtn()->setEnabled(state);
0431     d->widget->getReloadBtn()->setEnabled(state);
0432     startButton()->setEnabled(state);
0433 }
0434 
0435 void BOXWindow::slotFinished()
0436 {
0437     writeSettings();
0438     d->widget->imagesList()->listView()->clear();
0439 }
0440 
0441 void BOXWindow::closeEvent(QCloseEvent* e)
0442 {
0443     if (!e)
0444     {
0445         return;
0446     }
0447 
0448     slotFinished();
0449     e->accept();
0450 }
0451 
0452 } // namespace DigikamGenericBoxPlugin
0453 
0454 #include "moc_boxwindow.cpp"