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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-04-12
0007  * Description : A tool to export items to Rajce web service
0008  *
0009  * SPDX-FileCopyrightText: 2011      by Lukas Krejci <krejci.l at centrum dot cz>
0010  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "rajcewidget.h"
0017 
0018 // Qt includes
0019 
0020 #include <QLabel>
0021 #include <QSpinBox>
0022 #include <QCheckBox>
0023 #include <QGroupBox>
0024 #include <QButtonGroup>
0025 #include <QRadioButton>
0026 #include <QGridLayout>
0027 #include <QHBoxLayout>
0028 #include <QVBoxLayout>
0029 #include <QDialog>
0030 #include <QComboBox>
0031 #include <QApplication>
0032 #include <QStyle>
0033 
0034 // KDE includes
0035 
0036 #include <klocalizedstring.h>
0037 #include <ksharedconfig.h>
0038 #include <kconfiggroup.h>
0039 
0040 // Local includes
0041 
0042 #include "rajcetalker.h"
0043 #include "rajcenewalbumdlg.h"
0044 #include "rajcesession.h"
0045 #include "ditemslist.h"
0046 #include "wslogindialog.h"
0047 #include "dprogresswdg.h"
0048 
0049 namespace DigikamGenericRajcePlugin
0050 {
0051 
0052 class Q_DECL_HIDDEN RajceWidget::Private
0053 {
0054 public:
0055 
0056     explicit Private()
0057     {
0058         headerLbl         = nullptr;
0059         userNameLbl       = nullptr;
0060         userName          = nullptr;
0061         dimensionSpB      = nullptr;
0062         imageQualitySpB   = nullptr;
0063         albumsCoB         = nullptr;
0064         newAlbumBtn       = nullptr;
0065         reloadAlbumsBtn   = nullptr;
0066         changeUserBtn     = nullptr;
0067         iface             = nullptr;
0068         imgList           = nullptr;
0069         progressBar       = nullptr;
0070         talker            = nullptr;
0071         uploadingPhotos   = false;
0072         lastLoggedInState = false;
0073     }
0074 
0075     QLabel*                  headerLbl;
0076     QLabel*                  userNameLbl;
0077     QLabel*                  userName;
0078 
0079     QSpinBox*                dimensionSpB;
0080     QSpinBox*                imageQualitySpB;
0081 
0082     QComboBox*               albumsCoB;
0083 
0084     QPushButton*             newAlbumBtn;
0085     QPushButton*             reloadAlbumsBtn;
0086     QPushButton*             changeUserBtn;
0087 
0088     DInfoInterface*          iface;
0089     DItemsList*             imgList;
0090     DProgressWdg*            progressBar;
0091 
0092     RajceTalker*             talker;
0093 
0094     QList<QString>           uploadQueue;
0095     QList<QString>::Iterator currentUploadImage;
0096 
0097     bool                     uploadingPhotos;
0098     bool                     lastLoggedInState;
0099     QString                  currentAlbumName;
0100 };
0101 
0102 RajceWidget::RajceWidget(DInfoInterface* const iface, QWidget* const parent)
0103     : WSSettingsWidget(parent, iface, QLatin1String("Rajce.net")),
0104       d               (new Private)
0105 {
0106     d->iface             = iface;
0107     d->talker            = new RajceTalker(this);
0108     d->albumsCoB         = getAlbumsCoB();
0109     d->dimensionSpB      = getDimensionSpB();
0110     d->imageQualitySpB   = getImgQualitySpB();
0111     d->newAlbumBtn       = getNewAlbmBtn();
0112     d->reloadAlbumsBtn   = getReloadBtn();
0113     d->progressBar       = progressBar();
0114     d->imgList           = imagesList();
0115     d->changeUserBtn     = getChangeUserBtn();
0116 
0117     getUploadBox()->hide();
0118     getSizeBox()->hide();
0119 
0120     this->updateLabels();
0121 
0122     // ------------------------------------------------------------------------
0123 
0124     connect(d->talker, SIGNAL(signalBusyStarted(uint)),
0125             this, SLOT(slotProgressStarted(uint)));
0126 
0127     connect(d->talker, SIGNAL(signalBusyFinished(uint)),
0128             this, SLOT(slotProgressFinished(uint)));
0129 
0130     connect(d->talker, SIGNAL(signalBusyProgress(uint,uint)),
0131             this, SLOT(slotProgressChanged(uint,uint)));
0132 
0133     connect(d->changeUserBtn, SIGNAL(clicked()),
0134             this, SLOT(slotChangeUserClicked()));
0135 
0136     connect(d->newAlbumBtn, SIGNAL(clicked()),
0137             this, SLOT(slotCreateAlbum()));
0138 
0139     connect(d->reloadAlbumsBtn, SIGNAL(clicked()),
0140             this, SLOT(slotLoadAlbums()));
0141 
0142     connect(d->albumsCoB, SIGNAL(currentTextChanged(QString)),
0143             this, SLOT(slotSelectedAlbumChanged(QString)));
0144 }
0145 
0146 RajceWidget::~RajceWidget()
0147 {
0148     delete d;
0149 }
0150 
0151 void RajceWidget::updateLabels(const QString&, const QString&)
0152 {
0153     bool loggedIn = !d->talker->session().sessionToken().isEmpty();
0154 
0155     if (loggedIn != d->lastLoggedInState)
0156     {
0157         d->lastLoggedInState = loggedIn;
0158         Q_EMIT signalLoginStatusChanged(loggedIn);
0159     }
0160 
0161     QString username = loggedIn ? d->talker->session().username() : QLatin1String("");
0162     QString nickname = loggedIn ? d->talker->session().nickname() : i18n("Not logged in");
0163 
0164     getUserNameLabel()->setText(QString::fromLatin1("<b>%2</b> <small>%1</small>").arg(username, nickname));
0165 
0166     QString link = loggedIn
0167         ? QString::fromLatin1("<b><h2><a href='http://") + d->talker->session().nickname() +
0168           QString::fromLatin1(".rajce.net'>"
0169                               "<font color=\"#9ACD32\">Rajce.net</font>"
0170                               "</a></h2></b>")
0171         : QString::fromLatin1("<b><h2><a href='https://www.rajce.net'>"
0172                               "<font color=\"#9ACD32\">Rajce.net</font>"
0173                               "</a></h2></b>");
0174 
0175     getHeaderLbl()->setText(link);
0176 
0177     disconnect(d->albumsCoB, SIGNAL(currentTextChanged(QString)),
0178                this, SLOT(slotSelectedAlbumChanged(QString)));
0179 
0180     d->albumsCoB->clear();
0181     RajceAlbum album;
0182     int   selIdx = 0;
0183     int   i      = 0;
0184 
0185     Q_FOREACH (album, d->talker->session().albums())
0186     {
0187         d->albumsCoB->addItem(album.name, QVariant::fromValue(album));
0188 
0189         if (d->currentAlbumName == album.name)
0190         {
0191             selIdx = i;
0192         }
0193 
0194         ++i;
0195     }
0196 
0197     if (!d->currentAlbumName.isEmpty())
0198     {
0199         d->albumsCoB->setCurrentIndex(selIdx);
0200     }
0201 
0202     connect(d->albumsCoB, SIGNAL(currentTextChanged(QString)),
0203             this, SLOT(slotSelectedAlbumChanged(QString)));
0204 
0205     unsigned max = d->talker->session().maxHeight();
0206     max          = max > d->talker->session().maxWidth() ? max
0207                                                         : d->talker->session().maxWidth();
0208     d->dimensionSpB->setMaximum(max);
0209 
0210     if (d->dimensionSpB->value() == 0)
0211     {
0212         d->dimensionSpB->setValue(max);
0213     }
0214 
0215     d->newAlbumBtn->setEnabled(loggedIn);
0216     d->albumsCoB->setEnabled(loggedIn);
0217     d->reloadAlbumsBtn->setEnabled(loggedIn);
0218     d->dimensionSpB->setEnabled(loggedIn);
0219     d->imageQualitySpB->setEnabled(loggedIn);
0220 
0221     if (d->talker->session().lastErrorCode() != 0)
0222     {
0223         d->progressBar->setVisible(true);
0224 
0225         switch (d->talker->session().lastErrorCode())
0226         {
0227             case UnknownError:                   d->progressBar->setFormat(i18n("Unknown error"));                  break;
0228             case InvalidCommand:                 d->progressBar->setFormat(i18n("Invalid command"));                break;
0229             case InvalidCredentials:             d->progressBar->setFormat(i18n("Invalid login name or password")); break;
0230             case InvalidSessionToken:            d->progressBar->setFormat(i18n("Session expired"));                break;
0231             case InvalidOrRepeatedColumnName:                                                                       break;
0232             case InvalidAlbumId:                 d->progressBar->setFormat(i18n("Unknown album"));                  break;
0233             case AlbumDoesntExistOrNoPrivileges: d->progressBar->setFormat(i18n("Unknown album"));                  break;
0234             case InvalidAlbumToken:              d->progressBar->setFormat(i18n("Failed to open album"));           break;
0235             case AlbumNameEmpty:                 d->progressBar->setFormat(i18n("The album name cannot be empty")); break;
0236             case FailedToCreateAlbum:            d->progressBar->setFormat(i18n("Failed to create album"));         break;
0237             case AlbumDoesntExist:               d->progressBar->setFormat(i18n("Album does not exist"));           break;
0238             case UnknownApplication:                                                                                break;
0239             case InvalidApplicationKey:                                                                             break;
0240             case FileNotAttached:                d->progressBar->setFormat(i18n("File upload failed"));             break;
0241             case NewerVersionExists:                                                                                break;
0242             case SavingFileFailed:               d->progressBar->setFormat(i18n("File upload failed"));             break;
0243             case UnsupportedFileExtension:       d->progressBar->setFormat(i18n("Unsupported file extension"));     break;
0244             case UnknownClientVersion:                                                                              break;
0245             case NonexistentTarget:                                                                                 break;
0246             default:                                                                                                break;
0247         }
0248 
0249         QPalette palette = d->progressBar->palette();
0250         palette.setColor(QPalette::Active, QPalette::Window, Qt::darkRed);
0251         d->progressBar->setPalette(palette);
0252     }
0253 }
0254 
0255 void RajceWidget::reactivate()
0256 {
0257     d->imgList->listView()->clear();
0258     d->imgList->loadImagesFromCurrentSelection();
0259     d->talker->clearLastError();
0260     updateLabels();
0261 }
0262 
0263 void RajceWidget::slotProgressChanged(unsigned /*commandType*/, unsigned int percent)
0264 {
0265     if (d->uploadingPhotos)
0266     {
0267         unsigned idx  = d->currentUploadImage - d->uploadQueue.begin() - 1;
0268         float perc    = (float)idx / d->uploadQueue.size();
0269         perc         += (float)percent / 100 / d->uploadQueue.size();
0270         percent       = perc * 100;
0271     }
0272 
0273     d->progressBar->setValue(percent);
0274 }
0275 
0276 void RajceWidget::slotProgressFinished(unsigned)
0277 {
0278     if (d->uploadingPhotos)
0279     {
0280         unsigned idx = d->currentUploadImage - d->uploadQueue.begin();
0281         float perc   = (float)idx / d->uploadQueue.size();
0282 
0283         d->progressBar->setValue(perc * 100);
0284     }
0285     else
0286     {
0287         d->progressBar->setVisible(false);
0288         setEnabledWidgets(true);
0289         updateLabels();
0290     }
0291 }
0292 
0293 void RajceWidget::slotProgressStarted(unsigned commandType)
0294 {
0295     QString text;
0296 
0297     switch (commandType)
0298     {
0299         case Login:       text = i18n("Logging in %v%");     break;
0300         case Logout:      text = i18n("Logging out %v%");    break;
0301         case ListAlbums:  text = i18n("Loading albums %v%"); break;
0302         case CreateAlbum: text = i18n("Creating album %v%"); break;
0303         case OpenAlbum:   text = i18n("Opening album %v%");  break;
0304         case CloseAlbum:  text = i18n("Closing album %v%");  break;
0305         case AddPhoto:    text = i18n("Adding photos %v%");  break;
0306     }
0307 
0308     if (!d->uploadingPhotos)
0309     {
0310         d->progressBar->setValue(0);
0311     }
0312 
0313     d->progressBar->setFormat(text);
0314     d->progressBar->setVisible(true);
0315     setEnabledWidgets(false);
0316 }
0317 
0318 void RajceWidget::slotChangeUserClicked()
0319 {
0320     WSLoginDialog* const dlg = new WSLoginDialog(this, QLatin1String("Rajce.net"));
0321 
0322     if (dlg->exec() == QDialog::Accepted)
0323     {
0324         d->talker->clearLastError();
0325 
0326         connect(d->talker, SIGNAL(signalBusyFinished(uint)),
0327                 this, SLOT(slotLoadAlbums()));
0328 
0329         d->talker->login(dlg->login(), dlg->password());
0330     }
0331 
0332     delete dlg;
0333 }
0334 
0335 void RajceWidget::slotLoadAlbums()
0336 {
0337     disconnect(d->talker, SIGNAL(signalBusyFinished(uint)),
0338                this, SLOT(slotLoadAlbums()));
0339 
0340     d->talker->loadAlbums();
0341 }
0342 
0343 void RajceWidget::slotCreateAlbum()
0344 {
0345     RajceNewAlbumDlg* const dlg = new RajceNewAlbumDlg(this);
0346 
0347     if (dlg->exec() == QDialog::Accepted)
0348     {
0349         d->talker->clearLastError();
0350 
0351         connect(d->talker, SIGNAL(signalBusyFinished(uint)),
0352                 this, SLOT(slotLoadAlbums()));
0353 
0354         d->talker->createAlbum(dlg->albumName(), dlg->albumDescription(), dlg->albumVisible());
0355     }
0356 
0357     delete dlg;
0358 }
0359 
0360 void RajceWidget::slotStartUpload()
0361 {
0362     d->talker->clearLastError();
0363     setEnabledWidgets(false);
0364 
0365     d->uploadQueue.clear();
0366 
0367     Q_FOREACH (const QUrl& image, d->imgList->imageUrls(true))
0368     {
0369         QString imagePath = image.toLocalFile();
0370         d->uploadQueue.append(imagePath);
0371     }
0372 
0373     if (d->uploadQueue.isEmpty())
0374     {
0375         setEnabledWidgets(true);
0376         return;
0377     }
0378 
0379     connect(d->talker, SIGNAL(signalBusyFinished(uint)),
0380             this, SLOT(slotStartUploadAfterAlbumOpened()));
0381 
0382     QString albumName = d->albumsCoB->currentText();
0383     RajceAlbum album;
0384 
0385     Q_FOREACH (RajceAlbum a, d->talker->session().albums())
0386     {
0387         if (a.name == albumName)
0388         { // cppcheck-suppress useStlAlgorithm
0389             album = a;
0390             break;
0391         }
0392     }
0393 
0394     if (album.name == albumName)
0395     {
0396         d->talker->openAlbum(album);
0397     }
0398 }
0399 
0400 void RajceWidget::slotStartUploadAfterAlbumOpened()
0401 {
0402     disconnect(d->talker, SIGNAL(signalBusyFinished(uint)),
0403                this, SLOT(slotStartUploadAfterAlbumOpened()));
0404 
0405     connect(d->talker, SIGNAL(signalBusyFinished(uint)),
0406             this, SLOT(slotUploadNext()));
0407 
0408     d->uploadingPhotos    = true;
0409     d->progressBar->setValue(0);
0410     slotProgressStarted(AddPhoto);
0411     d->currentUploadImage = d->uploadQueue.begin();
0412     slotUploadNext();
0413 }
0414 
0415 void RajceWidget::slotCloseAlbum()
0416 {
0417     setEnabledWidgets(true);
0418 
0419     disconnect(d->talker, SIGNAL(signalBusyFinished(uint)),
0420                this, SLOT(slotCloseAlbum()));
0421 
0422     d->uploadQueue.clear();
0423     d->progressBar->setVisible(false);
0424 
0425     d->uploadingPhotos = false;
0426 }
0427 
0428 void RajceWidget::slotUploadNext()
0429 {
0430     QList<QString>::Iterator tmp = d->currentUploadImage;
0431 
0432     if (d->currentUploadImage == d->uploadQueue.end())
0433     {
0434         d->imgList->processed(QUrl::fromLocalFile(*(--tmp)), (d->talker->session().lastErrorCode() == 0));
0435         cancelUpload();
0436         return;
0437     }
0438 
0439     if (d->currentUploadImage != d->uploadQueue.begin())
0440     {
0441         d->imgList->processed(QUrl::fromLocalFile(*(--tmp)), (d->talker->session().lastErrorCode() == 0));
0442     }
0443 
0444     d->imgList->processing(QUrl::fromLocalFile(*d->currentUploadImage));
0445 
0446     QString currentPhoto = *d->currentUploadImage;
0447     ++d->currentUploadImage;
0448 
0449     unsigned dimension   = d->dimensionSpB->value();
0450     int jpgQuality       = d->imageQualitySpB->value();
0451 
0452     d->talker->uploadPhoto(currentPhoto, dimension, jpgQuality);
0453 }
0454 
0455 void RajceWidget::cancelUpload()
0456 {
0457     if (d->uploadingPhotos && d->currentUploadImage != d->uploadQueue.begin() &&
0458         d->currentUploadImage != d->uploadQueue.end())
0459     {
0460         d->imgList->processed(QUrl::fromLocalFile(*d->currentUploadImage), false);
0461     }
0462 
0463     disconnect(d->talker, SIGNAL(signalBusyFinished(uint)),
0464                this, SLOT(slotUploadNext()));
0465 
0466     connect(d->talker, SIGNAL(signalBusyFinished(uint)),
0467             this, SLOT(slotCloseAlbum()));
0468 
0469     d->talker->cancelCurrentCommand();
0470     d->talker->closeAlbum();
0471     d->uploadQueue.clear();
0472 }
0473 
0474 void RajceWidget::slotSelectedAlbumChanged(const QString& newName)
0475 {
0476     d->currentAlbumName = newName;
0477 }
0478 
0479 void RajceWidget::setEnabledWidgets(bool enabled)
0480 {
0481     d->changeUserBtn->setEnabled(enabled);
0482     d->newAlbumBtn->setEnabled(enabled);
0483     d->albumsCoB->setEnabled(enabled);
0484     d->reloadAlbumsBtn->setEnabled(enabled);
0485     d->dimensionSpB->setEnabled(enabled);
0486     d->imageQualitySpB->setEnabled(enabled);
0487 
0488     Q_EMIT signalLoginStatusChanged(enabled);
0489 }
0490 
0491 void RajceWidget::readSettings()
0492 {
0493     KSharedConfigPtr config = KSharedConfig::openConfig();
0494     KConfigGroup grp        = config->group(QLatin1String("RajceExport Settings"));
0495 
0496     RajceSession session;
0497 
0498     session.sessionToken() = grp.readEntry("token");
0499     session.username()     = grp.readEntry("username");
0500     session.nickname()     = grp.readEntry("nickname");
0501     d->currentAlbumName    = grp.readEntry("album");
0502     session.maxHeight()    = grp.readEntry("maxHeight",    1200);
0503     session.maxWidth()     = grp.readEntry("maxWidth",     1200);
0504     session.imageQuality() = grp.readEntry("imageQuality", 85);
0505 
0506     d->talker->init(session);
0507 
0508     if (!d->talker->session().sessionToken().isEmpty())
0509     {
0510         d->talker->loadAlbums();
0511     }
0512 }
0513 
0514 void RajceWidget::writeSettings()
0515 {
0516     KSharedConfigPtr config     = KSharedConfig::openConfig();
0517     KConfigGroup grp            = config->group(QLatin1String("RajceExport Settings"));
0518     const RajceSession& session = d->talker->session();
0519 
0520     grp.writeEntry("token",        session.sessionToken());
0521     grp.writeEntry("username",     session.username());
0522     grp.writeEntry("nickname",     session.nickname());
0523     grp.writeEntry("album",        d->currentAlbumName);
0524     grp.writeEntry("maxWidth",     session.maxWidth());
0525     grp.writeEntry("maxHeight",    session.maxHeight());
0526     grp.writeEntry("imageQuality", session.imageQuality());
0527 }
0528 
0529 } // namespace DigikamGenericRajcePlugin
0530 
0531 #include "moc_rajcewidget.cpp"