diff --git a/core/dplugins/generic/webservices/piwigo/piwigoitem.h b/core/dplugins/generic/webservices/piwigo/piwigoitem.h index b1f39ed2e2..d9c2a9bbd8 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigoitem.h +++ b/core/dplugins/generic/webservices/piwigo/piwigoitem.h @@ -1,67 +1,67 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2014-09-30 * Description : a tool to export items to Piwigo web service * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006 by Colin Guthrie * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2008 by Andrea Diamantini * Copyright (C) 2010-2014 by Frederic Coiffier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_PIWIGO_ITEM_H #define DIGIKAM_PIWIGO_ITEM_H // Qt includes #include namespace DigikamGenericPiwigoPlugin { class PiwigoAlbum { public: explicit PiwigoAlbum() + : m_refNum(-1), + m_parentRefNum(-1) { - m_refNum = -1; - m_parentRefNum = -1; } bool operator<(const PiwigoAlbum& rhs) const { if (m_parentRefNum == rhs.m_parentRefNum) { - return m_refNum < rhs.m_refNum; + return (m_refNum < rhs.m_refNum); } - return m_parentRefNum < rhs.m_parentRefNum; + return (m_parentRefNum < rhs.m_parentRefNum); } public: - int m_refNum; // album reference number - int m_parentRefNum; // parent's album reference number + int m_refNum; ///< album reference number + int m_parentRefNum; ///< parent's album reference number - QString m_name; // Album name + QString m_name; ///< Album name }; } // namespace DigikamGenericPiwigoPlugin #endif // DIGIKAM_PIWIGO_ITEM_H diff --git a/core/dplugins/generic/webservices/piwigo/piwigologindlg.cpp b/core/dplugins/generic/webservices/piwigo/piwigologindlg.cpp index 88d3550bbc..dacfaa47f5 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigologindlg.cpp +++ b/core/dplugins/generic/webservices/piwigo/piwigologindlg.cpp @@ -1,154 +1,160 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2014-09-30 * Description : a tool to export items to Piwigo web service * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006 by Colin Guthrie * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2008 by Andrea Diamantini * Copyright (C) 2010-2014 by Frederic Coiffier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the id->plied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "piwigologindlg.h" // Qt includes #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_version.h" #include "digikam_debug.h" #include "piwigosession.h" namespace DigikamGenericPiwigoPlugin { class Q_DECL_HIDDEN PiwigoLoginDlg::Private { public: explicit Private() + : pUrlEdit(nullptr), + pUsernameEdit(nullptr), + pPasswordEdit(nullptr), + pPiwigo(nullptr) { - pUrlEdit = nullptr; - pUsernameEdit = nullptr; - pPasswordEdit = nullptr; - pPiwigo = nullptr; } QLineEdit* pUrlEdit; QLineEdit* pUsernameEdit; QLineEdit* pPasswordEdit; PiwigoSession* pPiwigo; }; PiwigoLoginDlg::PiwigoLoginDlg(QWidget* const pParent, PiwigoSession* const pPiwigo, const QString& title) : QDialog(pParent, Qt::Dialog), d(new Private) { d->pPiwigo = pPiwigo; setWindowTitle(title); QFrame* const page = new QFrame(this); QGridLayout* const centerLayout = new QGridLayout(); page->setMinimumSize(500, 128); d->pUrlEdit = new QLineEdit(this); centerLayout->addWidget(d->pUrlEdit, 1, 1); d->pUsernameEdit = new QLineEdit(this); centerLayout->addWidget(d->pUsernameEdit, 2, 1); d->pPasswordEdit = new QLineEdit(this); d->pPasswordEdit->setEchoMode(QLineEdit::Password); centerLayout->addWidget(d->pPasswordEdit, 3, 1); QLabel* const urlLabel = new QLabel(this); urlLabel->setText(i18nc("piwigo login settings", "URL:")); centerLayout->addWidget(urlLabel, 1, 0); QLabel* const usernameLabel = new QLabel(this); usernameLabel->setText(i18nc("piwigo login settings", "Username:")); centerLayout->addWidget(usernameLabel, 2, 0); QLabel* const passwdLabel = new QLabel(this); passwdLabel->setText(i18nc("piwigo login settings", "Password:")); centerLayout->addWidget(passwdLabel, 3, 0); //--------------------------------------------- page->setLayout(centerLayout); resize(QSize(300, 150).expandedTo(minimumSizeHint())); // setting initial data d->pUrlEdit->setText(pPiwigo->url()); d->pUsernameEdit->setText(pPiwigo->username()); d->pPasswordEdit->setText(pPiwigo->password()); //--------------------------------------------- QDialogButtonBox* const buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); QVBoxLayout* const dialogLayout = new QVBoxLayout(this); dialogLayout->addWidget(page); dialogLayout->addWidget(buttonBox); connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOk())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } PiwigoLoginDlg::~PiwigoLoginDlg() { delete d; } void PiwigoLoginDlg::slotOk() { if (d->pUrlEdit->isModified()) + { d->pPiwigo->setUrl(d->pUrlEdit->text()); + } if (d->pUsernameEdit->isModified()) + { d->pPiwigo->setUsername(d->pUsernameEdit->text()); + } if (d->pPasswordEdit->isModified()) + { d->pPiwigo->setPassword(d->pPasswordEdit->text()); + } d->pPiwigo->save(); accept(); } } // namespace DigikamGenericPiwigoPlugin diff --git a/core/dplugins/generic/webservices/piwigo/piwigoplugin.h b/core/dplugins/generic/webservices/piwigo/piwigoplugin.h index b26c031398..48446ca234 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigoplugin.h +++ b/core/dplugins/generic/webservices/piwigo/piwigoplugin.h @@ -1,71 +1,71 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2018-07-30 * Description : a plugin to export to Piwigo web-service. * * Copyright (C) 2018-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_PIWIGO_PLUGIN_H #define DIGIKAM_PIWIGO_PLUGIN_H // Local includes #include "dplugingeneric.h" #define DPLUGIN_IID "org.kde.digikam.plugin.generic.Piwigo" using namespace Digikam; namespace DigikamGenericPiwigoPlugin { class PiwigoWindow; class PiwigoPlugin : public DPluginGeneric { Q_OBJECT Q_PLUGIN_METADATA(IID DPLUGIN_IID) Q_INTERFACES(Digikam::DPluginGeneric) public: explicit PiwigoPlugin(QObject* const parent = nullptr); ~PiwigoPlugin(); QString name() const override; QString iid() const override; QIcon icon() const override; QString details() const override; QString description() const override; QList authors() const override; - void setup(QObject* const) override; - void cleanUp() override; + void setup(QObject* const) override; + void cleanUp() override; private Q_SLOTS: void slotPiwigo(); private: QPointer m_toolDlg; }; } // namespace DigikamGenericPiwigoPlugin #endif // DIGIKAM_PIWIGO_PLUGIN_H diff --git a/core/dplugins/generic/webservices/piwigo/piwigosession.cpp b/core/dplugins/generic/webservices/piwigo/piwigosession.cpp index b8ce1cdf6d..67724bfbc6 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigosession.cpp +++ b/core/dplugins/generic/webservices/piwigo/piwigosession.cpp @@ -1,122 +1,122 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2014-09-30 * Description : a tool to export items to Piwigo web service * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006 by Colin Guthrie * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2008 by Andrea Diamantini * Copyright (C) 2010-2014 by Frederic Coiffier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "piwigosession.h" // Qt includes #include #include // KDE includes #include #include // Local includes #include "digikam_debug.h" namespace DigikamGenericPiwigoPlugin { class Q_DECL_HIDDEN PiwigoSession::Private { public: explicit Private() { } QString url; QString username; QString password; }; PiwigoSession::PiwigoSession() : d(new Private) { load(); } PiwigoSession::~PiwigoSession() { delete d; } QString PiwigoSession::url() const { return d->url; } QString PiwigoSession::username() const { return d->username; } QString PiwigoSession::password() const { return d->password; } void PiwigoSession::setUrl(const QString& url) { d->url = url; } void PiwigoSession::setUsername(const QString& username) { d->username = username; } void PiwigoSession::setPassword(const QString& password) { d->password = password; } void PiwigoSession::load() { KConfig config; KConfigGroup group = config.group("Piwigo Settings"); - d->url = group.readEntry("URL", QString()); - d->username = group.readEntry("Username", QString()); - d->password = group.readEntry("Password", QString()); + d->url = group.readEntry("URL", QString()); + d->username = group.readEntry("Username", QString()); + d->password = group.readEntry("Password", QString()); } void PiwigoSession::save() { KConfig config; KConfigGroup group = config.group("Piwigo Settings"); group.writeEntry(QString::fromUtf8("URL"), url()); group.writeEntry(QString::fromUtf8("Username"), username()); group.writeEntry(QString::fromUtf8("Password"), password()); config.sync(); } } // namespace DigikamGenericPiwigoPlugin diff --git a/core/dplugins/generic/webservices/piwigo/piwigotalker.cpp b/core/dplugins/generic/webservices/piwigo/piwigotalker.cpp index 65655568fe..c08ebe31f8 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigotalker.cpp +++ b/core/dplugins/generic/webservices/piwigo/piwigotalker.cpp @@ -1,996 +1,1047 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2014-09-30 * Description : a tool to export items to Piwigo web service * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006 by Colin Guthrie * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2008 by Andrea Diamantini * Copyright (C) 2010-2019 by Frederic Coiffier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "piwigotalker.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dmetadata.h" #include "digikam_debug.h" #include "piwigoitem.h" #include "digikam_version.h" #include "wstoolutils.h" #include "previewloadthread.h" namespace DigikamGenericPiwigoPlugin { class Q_DECL_HIDDEN PiwigoTalker::Private { public: explicit Private() + : parent(nullptr), + state(GE_LOGOUT), + netMngr(nullptr), + reply(nullptr), + loggedIn(false), + chunkId(0), + nbOfChunks(0), + version(-1), + albumId(0), + photoId(0), + iface(nullptr) { - parent = nullptr; - state = GE_LOGOUT; - netMngr = nullptr; - reply = nullptr; - loggedIn = false; - chunkId = 0; - nbOfChunks = 0; - version = -1; - albumId = 0; - photoId = 0; - iface = nullptr; } QWidget* parent; State state; QString cookie; QUrl url; QNetworkAccessManager* netMngr; QNetworkReply* reply; bool loggedIn; QByteArray talker_buffer; uint chunkId; uint nbOfChunks; int version; QByteArray md5sum; QString path; - QString tmpPath; // If set, contains a temporary file which must be deleted + QString tmpPath; ///< If set, contains a temporary file which must be deleted int albumId; - int photoId; // Filled when the photo already exist - QString comment; // Synchronized with Piwigo comment - QString title; // Synchronized with Piwigo name - QString author; // Synchronized with Piwigo author - QDateTime date; // Synchronized with Piwigo date + int photoId; ///< Filled when the photo already exist + QString comment; ///< Synchronized with Piwigo comment + QString title; ///< Synchronized with Piwigo name + QString author; ///< Synchronized with Piwigo author + QDateTime date; ///< Synchronized with Piwigo date DInfoInterface* iface; }; QString PiwigoTalker::s_authToken = QLatin1String(""); PiwigoTalker::PiwigoTalker(DInfoInterface* const iface, QWidget* const parent) : d(new Private) { d->parent = parent; d->iface = iface; d->netMngr = new QNetworkAccessManager(this); connect(d->netMngr, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotFinished(QNetworkReply*))); } PiwigoTalker::~PiwigoTalker() { cancel(); WSToolUtils::removeTemporaryDir("piwigo"); delete d; } void PiwigoTalker::cancel() { deleteTemporaryFile(); if (d->reply) { d->reply->abort(); d->reply = nullptr; } } QString PiwigoTalker::getAuthToken() { return s_authToken; } QByteArray PiwigoTalker::computeMD5Sum(const QString& filepath) { QFile file(filepath); if (!file.open(QIODevice::ReadOnly)) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "File open error:" << filepath; return QByteArray(); } QByteArray md5sum = QCryptographicHash::hash(file.readAll(), QCryptographicHash::Md5); file.close(); return md5sum; } bool PiwigoTalker::loggedIn() const { return d->loggedIn; } void PiwigoTalker::login(const QUrl& url, const QString& name, const QString& passwd) { d->url = url; d->state = GE_LOGIN; d->talker_buffer.resize(0); // Add the page to the URL + if (!d->url.url().endsWith(QLatin1String(".php"))) { d->url.setPath(d->url.path() + QLatin1Char('/') + QLatin1String("ws.php")); } s_authToken = QLatin1String(QUuid::createUuid().toByteArray().toBase64()); QStringList qsl; qsl.append(QLatin1String("password=") + QString::fromUtf8(passwd.toUtf8().toPercentEncoding())); qsl.append(QLatin1String("method=pwg.session.login")); qsl.append(QLatin1String("username=") + QString::fromUtf8(name.toUtf8().toPercentEncoding())); QString dataParameters = qsl.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); emit signalBusy(true); } void PiwigoTalker::listAlbums() { d->state = GE_LISTALBUMS; d->talker_buffer.resize(0); QStringList qsl; qsl.append(QLatin1String("method=pwg.categories.getList")); qsl.append(QLatin1String("recursive=true")); QString dataParameters = qsl.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); emit signalBusy(true); } bool PiwigoTalker::addPhoto(int albumId, const QString& mediaPath, bool rescale, int maxWidth, int maxHeight, int quality) { d->state = GE_CHECKPHOTOEXIST; d->talker_buffer.resize(0); d->path = mediaPath; // By default, d->path contains the original file - d->tmpPath = QLatin1String(""); // By default, no temporary file (except with rescaling) + d->tmpPath = QLatin1String(""); // By default, no temporary file (except with rescaling) d->albumId = albumId; d->md5sum = computeMD5Sum(mediaPath); qCDebug(DIGIKAM_WEBSERVICES_LOG) << mediaPath << " " << d->md5sum.toHex(); if (mediaPath.endsWith(QLatin1String(".mp4")) || mediaPath.endsWith(QLatin1String(".MP4")) || mediaPath.endsWith(QLatin1String(".ogg")) || mediaPath.endsWith(QLatin1String(".OGG")) || mediaPath.endsWith(QLatin1String(".webm")) || mediaPath.endsWith(QLatin1String(".WEBM"))) { // Video management // Nothing to do } else { // Image management QImage image = PreviewLoadThread::loadHighQualitySynchronously(mediaPath).copyQImage(); if (image.isNull()) { image.load(mediaPath); } if (image.isNull()) { // Invalid image return false; } if (!rescale) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Upload the original version: " << d->path; } else { // Rescale the image - if (image.width() > maxWidth || image.height() > maxHeight) + + if ((image.width() > maxWidth) || (image.height() > maxHeight)) { image = image.scaled(maxWidth, maxHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); } d->path = WSToolUtils::makeTemporaryDir("piwigo") .filePath(QUrl::fromLocalFile(mediaPath).fileName()); d->tmpPath = d->path; image.save(d->path, "JPEG", quality); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Upload a resized version: " << d->path ; // Restore all metadata with EXIF // in the resized version DMetadata meta; if (meta.load(mediaPath)) { meta.setItemDimensions(image.size()); meta.setItemOrientation(MetaEngine::ORIENTATION_NORMAL); meta.setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY); meta.save(d->path, true); } else { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Image " << mediaPath << " has no exif data"; } } } // Metadata management // Complete name and comment for summary sending + QFileInfo fi(mediaPath); d->title = fi.completeBaseName(); d->comment = QString(); d->author = QString(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + d->date = fi.birthTime(); + #else + d->date = fi.created(); + #endif // Look in the host database DItemInfo info(d->iface->itemInfo(QUrl::fromLocalFile(mediaPath))); if (!info.title().isEmpty()) + { d->title = info.title(); + } if (!info.comment().isEmpty()) + { d->comment = info.comment(); + } if (!info.creators().isEmpty()) + { d->author = info.creators().join(QLatin1String(" / ")); + } if (!info.dateTime().isNull()) + { d->date = info.dateTime(); + } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Title: " << d->title; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Comment: " << d->comment; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Author: " << d->author; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Date: " << d->date; QStringList qsl; qsl.append(QLatin1String("method=pwg.images.exist")); qsl.append(QLatin1String("md5sud->list=") + QLatin1String(d->md5sum.toHex())); QString dataParameters = qsl.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); emit signalProgressInfo(i18n("Check if %1 already exists", QUrl(mediaPath).fileName())); emit signalBusy(true); return true; } void PiwigoTalker::slotFinished(QNetworkReply* reply) { if (reply != d->reply) { return; } d->reply = nullptr; State state = d->state; // Can change in the treatment itself, so we cache it if (reply->error() != QNetworkReply::NoError) { - if (state == GE_LOGIN) + if (state == GE_LOGIN) { emit signalLoginFailed(reply->errorString()); qCDebug(DIGIKAM_WEBSERVICES_LOG) << reply->errorString(); } else if (state == GE_GETVERSION) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << reply->errorString(); + // Version isn't mandatory and errors can be ignored // As login succeeded, albums can be listed + listAlbums(); } - else if (state == GE_CHECKPHOTOEXIST || state == GE_GETINFO || - state == GE_SETINFO || state == GE_ADDPHOTOCHUNK || - state == GE_ADDPHOTOSUMMARY) + else if ((state == GE_CHECKPHOTOEXIST) || (state == GE_GETINFO) || + (state == GE_SETINFO) || (state == GE_ADDPHOTOCHUNK) || + (state == GE_ADDPHOTOSUMMARY)) { deleteTemporaryFile(); emit signalAddPhotoFailed(reply->errorString()); } else { QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), reply->errorString()); } emit signalBusy(false); reply->deleteLater(); return; } d->talker_buffer.append(reply->readAll()); switch (state) { case (GE_LOGIN): parseResponseLogin(d->talker_buffer); break; + case (GE_GETVERSION): parseResponseGetVersion(d->talker_buffer); break; + case (GE_LISTALBUMS): parseResponseListAlbums(d->talker_buffer); break; + case (GE_CHECKPHOTOEXIST): parseResponseDoesPhotoExist(d->talker_buffer); break; + case (GE_GETINFO): parseResponseGetInfo(d->talker_buffer); break; + case (GE_SETINFO): parseResponseSetInfo(d->talker_buffer); break; + case (GE_ADDPHOTOCHUNK): // Support for Web API >= 2.4 parseResponseAddPhotoChunk(d->talker_buffer); break; + case (GE_ADDPHOTOSUMMARY): parseResponseAddPhotoSummary(d->talker_buffer); break; + default: // GE_LOGOUT break; } - if (state == GE_GETVERSION && d->loggedIn) + if ((state == GE_GETVERSION) && d->loggedIn) { listAlbums(); } emit signalBusy(false); reply->deleteLater(); } void PiwigoTalker::parseResponseLogin(const QByteArray& data) { QXmlStreamReader ts(data); QString line; bool foundResponse = false; - d->loggedIn = false; + d->loggedIn = false; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseLogin: " << QString::fromUtf8(data); while (!ts.atEnd()) { ts.readNext(); if (ts.isStartElement()) { foundResponse = true; - if (ts.name() == QLatin1String("rsp") && - ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + if ((ts.name() == QLatin1String("rsp")) && + (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok"))) { d->loggedIn = true; /** Request Version */ - d->state = GE_GETVERSION; + + d->state = GE_GETVERSION; d->talker_buffer.resize(0); - d->version = -1; + d->version = -1; QByteArray buffer = "method=pwg.getVersion"; QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); emit signalBusy(true); return; } } } if (!foundResponse) { emit signalLoginFailed(i18n("Piwigo URL probably incorrect")); return; } if (!d->loggedIn) { emit signalLoginFailed(i18n("Incorrect username or password specified")); } } void PiwigoTalker::parseResponseGetVersion(const QByteArray& data) { QXmlStreamReader ts(data); QString line; QRegExp verrx(QLatin1String(".?(\\d+)\\.(\\d+).*")); bool foundResponse = false; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseGetVersion: " << QString::fromUtf8(data); while (!ts.atEnd()) { ts.readNext(); if (ts.isStartElement()) { foundResponse = true; - if (ts.name() == QLatin1String("rsp") && - ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + if ((ts.name() == QLatin1String("rsp")) && + (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok"))) { QString v = ts.readElementText(); if (verrx.exactMatch(v)) { QStringList qsl = verrx.capturedTexts(); d->version = qsl[1].toInt() * 100 + qsl[2].toInt(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Version: " << d->version; break; } } } } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "foundResponse : " << foundResponse; if (d->version < PIWIGO_VER_2_4) { d->loggedIn = false; emit signalLoginFailed(i18n("Upload to Piwigo version < 2.4 is no longer supported")); return; } } void PiwigoTalker::parseResponseListAlbums(const QByteArray& data) { QString str = QString::fromUtf8(data); QXmlStreamReader ts(data); QString line; bool foundResponse = false; bool success = false; typedef QList PiwigoAlbumList; PiwigoAlbumList albumList; PiwigoAlbumList::iterator iter = albumList.begin(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseListAlbums"; while (!ts.atEnd()) { ts.readNext(); - if (ts.isEndElement() && ts.name() == QLatin1String("categories")) + if (ts.isEndElement() && (ts.name() == QLatin1String("categories"))) + { break; + } if (ts.isStartElement()) { - if (ts.name() == QLatin1String("rsp") && - ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + if ((ts.name() == QLatin1String("rsp")) && + (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok"))) { foundResponse = true; } if (ts.name() == QLatin1String("categories")) { success = true; } if (ts.name() == QLatin1String("category")) { PiwigoAlbum album; album.m_refNum = ts.attributes().value(QLatin1String("id")).toString().toInt(); album.m_parentRefNum = -1; qCDebug(DIGIKAM_WEBSERVICES_LOG) << album.m_refNum << "\n"; iter = albumList.insert(iter, album); } if (ts.name() == QLatin1String("name")) { (*iter).m_name = ts.readElementText(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << (*iter).m_name << "\n"; } if (ts.name() == QLatin1String("uppercats")) { QString uppercats = ts.readElementText(); QStringList catlist = uppercats.split(QLatin1Char(',')); - if (catlist.size() > 1 && catlist.at((uint)catlist.size() - 2).toInt() != (*iter).m_refNum) + if ((catlist.size() > 1) && (catlist.at((uint)catlist.size() - 2).toInt() != (*iter).m_refNum)) { (*iter).m_parentRefNum = catlist.at((uint)catlist.size() - 2).toInt(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << (*iter).m_parentRefNum << "\n"; } } } } if (!foundResponse) { emit signalError(i18n("Invalid response received from remote Piwigo")); return; } if (!success) { emit signalError(i18n("Failed to list albums")); return; } // We need parent albums to come first for rest of the code to work + std::sort(albumList.begin(), albumList.end()); emit signalAlbums(albumList); } void PiwigoTalker::parseResponseDoesPhotoExist(const QByteArray& data) { QString str = QString::fromUtf8(data); QXmlStreamReader ts(data); QString line; bool foundResponse = false; bool success = false; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseDoesPhotoExist: " << QString::fromUtf8(data); while (!ts.atEnd()) { ts.readNext(); if (ts.name() == QLatin1String("rsp")) { foundResponse = true; if (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + { success = true; + } // Originally, first versions of Piwigo 2.4.x returned an invalid XML as the element started with a digit // New versions are corrected (starting with _) : This code works with both versions + QRegExp md5rx(QLatin1String("_?([a-f0-9]+)>([0-9]+)md5sum.toHex())) + if (qsl1[1] == QLatin1String(d->md5sum.toHex())) { - d->photoId = qsl[2].toInt(); + d->photoId = qsl1[2].toInt(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "d->photoId: " << d->photoId; emit signalProgressInfo(i18n("Photo '%1' already exists.", d->title)); d->state = GE_GETINFO; d->talker_buffer.resize(0); - QStringList qsl; - qsl.append(QLatin1String("method=pwg.images.getInfo")); - qsl.append(QLatin1String("image_id=") + QString::number(d->photoId)); - QString dataParameters = qsl.join(QLatin1Char('&')); + QStringList qsl2; + qsl2.append(QLatin1String("method=pwg.images.getInfo")); + qsl2.append(QLatin1String("image_id=") + QString::number(d->photoId)); + QString dataParameters = qsl2.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); return; } } } } if (!foundResponse) { emit signalAddPhotoFailed(i18n("Invalid response received from remote Piwigo")); return; } if (!success) { emit signalAddPhotoFailed(i18n("Failed to upload photo")); return; } if (d->version >= PIWIGO_VER_2_4) { QFileInfo fi(d->path); d->state = GE_ADDPHOTOCHUNK; d->talker_buffer.resize(0); + // Compute the number of chunks for the image + d->nbOfChunks = (fi.size() / CHUNK_MAX_SIZE) + 1; d->chunkId = 0; addNextChunk(); } else { emit signalAddPhotoFailed(i18n("Upload to Piwigo version < 2.4 is no longer supported")); return; } } void PiwigoTalker::parseResponseGetInfo(const QByteArray& data) { QString str = QString::fromUtf8(data); QXmlStreamReader ts(data); QString line; bool foundResponse = false; bool success = false; QList categories; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseGetInfo: " << QString::fromUtf8(data); while (!ts.atEnd()) { ts.readNext(); if (ts.isStartElement()) { if (ts.name() == QLatin1String("rsp")) { foundResponse = true; if (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + { success = true; + } } if (ts.name() == QLatin1String("category")) { if (ts.attributes().hasAttribute(QLatin1String("id"))) { QString id(ts.attributes().value(QLatin1String("id")).toString()); categories.append(id.toInt()); } } } } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "success : " << success; if (!foundResponse) { emit signalAddPhotoFailed(i18n("Invalid response received from remote Piwigo")); return; } if (categories.contains(d->albumId)) { emit signalAddPhotoFailed(i18n("Photo '%1' already exists in this album.", d->title)); return; } else { categories.append(d->albumId); } d->state = GE_SETINFO; d->talker_buffer.resize(0); QStringList qsl_cat; - for (int i = 0; i < categories.size(); ++i) + for (int i = 0 ; i < categories.size() ; ++i) { qsl_cat.append(QString::number(categories.at(i))); } QStringList qsl; qsl.append(QLatin1String("method=pwg.images.setInfo")); qsl.append(QLatin1String("image_id=") + QString::number(d->photoId)); qsl.append(QLatin1String("categories=") + QString::fromUtf8(qsl_cat.join(QLatin1Char(';')).toUtf8().toPercentEncoding())); QString dataParameters = qsl.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); return; } void PiwigoTalker::parseResponseSetInfo(const QByteArray& data) { QString str = QString::fromUtf8(data); QXmlStreamReader ts(data); QString line; bool foundResponse = false; bool success = false; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseSetInfo: " << QString::fromUtf8(data); while (!ts.atEnd()) { ts.readNext(); if (ts.isStartElement()) { if (ts.name() == QLatin1String("rsp")) { foundResponse = true; if (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + { success = true; + } break; } } } if (!foundResponse) { emit signalAddPhotoFailed(i18n("Invalid response received from remote Piwigo")); + return; } if (!success) { emit signalAddPhotoFailed(i18n("Failed to upload photo")); + return; } deleteTemporaryFile(); emit signalAddPhotoSucceeded(); } void PiwigoTalker::addNextChunk() { QFile imagefile(d->path); if (!imagefile.open(QIODevice::ReadOnly)) { emit signalProgressInfo(i18n("Error : Cannot open photo: %1", QUrl(d->path).fileName())); return; } d->chunkId++; // We start with chunk 1 imagefile.seek((d->chunkId - 1) * CHUNK_MAX_SIZE); d->talker_buffer.resize(0); QStringList qsl; qsl.append(QLatin1String("method=pwg.images.addChunk")); qsl.append(QLatin1String("original_sum=") + QLatin1String(d->md5sum.toHex())); qsl.append(QLatin1String("position=") + QString::number(d->chunkId)); qsl.append(QLatin1String("type=file")); qsl.append(QLatin1String("data=") + QString::fromUtf8(imagefile.read(CHUNK_MAX_SIZE).toBase64().toPercentEncoding())); QString dataParameters = qsl.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); imagefile.close(); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); emit signalProgressInfo(i18n("Upload the chunk %1/%2 of %3", d->chunkId, d->nbOfChunks, QUrl(d->path).fileName())); } void PiwigoTalker::parseResponseAddPhotoChunk(const QByteArray& data) { QString str = QString::fromUtf8(data); QXmlStreamReader ts(data); QString line; bool foundResponse = false; bool success = false; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseAddPhotoChunk: " << QString::fromUtf8(data); while (!ts.atEnd()) { ts.readNext(); if (ts.isStartElement()) { if (ts.name() == QLatin1String("rsp")) { foundResponse = true; if (ts.attributes().value(QLatin1String("stat")) == QLatin1String("ok")) + { success = true; + } break; } } } if (!foundResponse || !success) { emit signalProgressInfo(i18n("Warning : The full size photo cannot be uploaded.")); } if (d->chunkId < d->nbOfChunks) { addNextChunk(); } else { addPhotoSummary(); } } void PiwigoTalker::addPhotoSummary() { d->state = GE_ADDPHOTOSUMMARY; d->talker_buffer.resize(0); QStringList qsl; qsl.append(QLatin1String("method=pwg.images.add")); qsl.append(QLatin1String("original_sum=") + QLatin1String(d->md5sum.toHex())); qsl.append(QLatin1String("original_filename=") + QString::fromUtf8(QUrl(d->path).fileName().toUtf8().toPercentEncoding())); qsl.append(QLatin1String("name=") + QString::fromUtf8(d->title.toUtf8().toPercentEncoding())); if (!d->author.isEmpty()) + { qsl.append(QLatin1String("author=") + QString::fromUtf8(d->author.toUtf8().toPercentEncoding())); + } if (!d->comment.isEmpty()) + { qsl.append(QLatin1String("comment=") + QString::fromUtf8(d->comment.toUtf8().toPercentEncoding())); + } qsl.append(QLatin1String("categories=") + QString::number(d->albumId)); qsl.append(QLatin1String("file_sum=") + QLatin1String(computeMD5Sum(d->path).toHex())); qsl.append(QLatin1String("date_creation=") + QString::fromUtf8(d->date.toString(QLatin1String("yyyy-MM-dd hh:mm:ss")).toUtf8().toPercentEncoding())); //qsl.append("tag_ids="); // TODO Implement this function + QString dataParameters = qsl.join(QLatin1Char('&')); QByteArray buffer; buffer.append(dataParameters.toUtf8()); QNetworkRequest netRequest(d->url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); netRequest.setRawHeader("Authorization", s_authToken.toLatin1()); d->reply = d->netMngr->post(netRequest, buffer); emit signalProgressInfo(i18n("Upload the metadata of %1", QUrl(d->path).fileName())); } void PiwigoTalker::parseResponseAddPhotoSummary(const QByteArray& data) { QString str = QString::fromUtf8(data); QXmlStreamReader ts(data.mid(data.indexOf("tmpPath.size()) { QFile(d->tmpPath).remove(); d->tmpPath = QLatin1String(""); } } } // namespace DigikamGenericPiwigoPlugin diff --git a/core/dplugins/generic/webservices/piwigo/piwigotalker.h b/core/dplugins/generic/webservices/piwigo/piwigotalker.h index d1a73b8c05..b9b928ba30 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigotalker.h +++ b/core/dplugins/generic/webservices/piwigo/piwigotalker.h @@ -1,152 +1,152 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2014-09-30 * Description : a tool to export items to Piwigo web service * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006 by Colin Guthrie * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2008 by Andrea Diamantini * Copyright (C) 2010-2019 by Frederic Coiffier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_PIWIGO_TALKER_H #define DIGIKAM_PIWIGO_TALKER_H // Qt includes #include #include #include #include #include #include #include #include // Local includes #include "dinfointerface.h" using namespace Digikam; template class QList; namespace DigikamGenericPiwigoPlugin { class PiwigoAlbum; class PiwigoTalker : public QObject { Q_OBJECT public: enum State { GE_LOGOUT = -1, GE_LOGIN = 0, GE_GETVERSION, GE_LISTALBUMS, GE_CHECKPHOTOEXIST, GE_GETINFO, GE_SETINFO, GE_ADDPHOTOCHUNK, GE_ADDPHOTOSUMMARY }; enum { CHUNK_MAX_SIZE = 512*1024, PIWIGO_VER_2_4 = 204 }; public: explicit PiwigoTalker(DInfoInterface* const iface, QWidget* const parent); ~PiwigoTalker(); public: bool loggedIn() const; void login(const QUrl& url, const QString& name, const QString& passwd); void listAlbums(); void listPhotos(const QString& albumName); /* TODO Implement this function void createAlbum(const QString& parentAlbumName, const QString& albumName, const QString& albumTitle, const QString& albumCaption); */ bool addPhoto(int albumId, const QString& photoPath, bool rescale = false, int maxWidth = 1600, int maxHeight = 1600, int quality = 95); void cancel(); static QString getAuthToken(); Q_SIGNALS: void signalProgressInfo(const QString& msg); void signalError(const QString& msg); void signalLoginFailed(const QString& msg); void signalBusy(bool val); void signalAlbums(const QList& albumList); void signalAddPhotoSucceeded(); void signalAddPhotoFailed(const QString& msg); private: void parseResponseLogin(const QByteArray& data); void parseResponseGetVersion(const QByteArray& data); void parseResponseListAlbums(const QByteArray& data); void parseResponseDoesPhotoExist(const QByteArray& data); void parseResponseGetInfo(const QByteArray& data); void parseResponseSetInfo(const QByteArray& data); void addNextChunk(); void parseResponseAddPhotoChunk(const QByteArray& data); void addPhotoSummary(); void parseResponseAddPhotoSummary(const QByteArray& data); QByteArray computeMD5Sum(const QString& filepath); void deleteTemporaryFile(); private Q_SLOTS: void slotFinished(QNetworkReply* reply); private: class Private; Private* const d; - + static QString s_authToken; }; } // namespace DigikamGenericPiwigoPlugin #endif // PIWIGOTALKER_H diff --git a/core/dplugins/generic/webservices/piwigo/piwigowindow.cpp b/core/dplugins/generic/webservices/piwigo/piwigowindow.cpp index e971d936b0..fac48202b1 100644 --- a/core/dplugins/generic/webservices/piwigo/piwigowindow.cpp +++ b/core/dplugins/generic/webservices/piwigo/piwigowindow.cpp @@ -1,640 +1,663 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2014-09-30 * Description : a tool to export items to Piwigo web service * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006 by Colin Guthrie * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2008 by Andrea Diamantini * Copyright (C) 2010-2014 by Frederic Coiffier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "piwigowindow.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "piwigosession.h" #include "piwigologindlg.h" #include "piwigoitem.h" #include "piwigotalker.h" #include "imagedialog.h" namespace DigikamGenericPiwigoPlugin { class Q_DECL_HIDDEN PiwigoWindow::Private { public: explicit Private(PiwigoWindow* const parent, DInfoInterface* const interface); QWidget* widget; QTreeWidget* albumView; QPushButton* confButton; QCheckBox* resizeCheckBox; QSpinBox* widthSpinBox; QSpinBox* heightSpinBox; QSpinBox* qualitySpinBox; QHash albumDict; PiwigoTalker* talker; PiwigoSession* pPiwigo; DInfoInterface* iface; QProgressDialog* progressDlg; unsigned int uploadCount; unsigned int uploadTotal; QStringList pUploadList; }; PiwigoWindow::Private::Private(PiwigoWindow* const parent, DInfoInterface* const interface) + : widget(new QWidget(parent)), + albumView(nullptr), + confButton(nullptr), + resizeCheckBox(nullptr), + widthSpinBox(nullptr), + heightSpinBox(nullptr), + qualitySpinBox(nullptr), + talker(nullptr), + pPiwigo(nullptr), + iface(interface), + progressDlg(nullptr), + uploadCount(0), + uploadTotal(0) { - iface = interface; - talker = nullptr; - pPiwigo = nullptr; - progressDlg = nullptr; - uploadCount = 0; - uploadTotal = 0; - widget = new QWidget(parent); parent->setMainWidget(widget); parent->setModal(false); QHBoxLayout* const hlay = new QHBoxLayout(widget); // --------------------------------------------------------------------------- QLabel* const logo = new QLabel(); logo->setContentsMargins(QMargins()); logo->setScaledContents(false); logo->setOpenExternalLinks(true); logo->setTextFormat(Qt::RichText); logo->setFocusPolicy(Qt::NoFocus); logo->setTextInteractionFlags(Qt::LinksAccessibleByMouse); logo->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); logo->setToolTip(i18n("Visit Piwigo website")); logo->setAlignment(Qt::AlignLeft); QImage img = QImage(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/pics/logo-piwigo.png"))); QByteArray byteArray; QBuffer buffer(&byteArray); img.save(&buffer, "PNG"); logo->setText(QString::fromLatin1("%2") .arg(QLatin1String("http://piwigo.org")) .arg(QString::fromLatin1("") .arg(QLatin1String(byteArray.toBase64().data())))); // --------------------------------------------------------------------------- albumView = new QTreeWidget; QStringList labels; labels << i18n("Albums"); albumView->setHeaderLabels(labels); albumView->setSortingEnabled(true); albumView->sortByColumn(0, Qt::AscendingOrder); // --------------------------------------------------------------------------- QFrame* const optionFrame = new QFrame; QVBoxLayout* const vlay = new QVBoxLayout(); confButton = new QPushButton; confButton->setText(i18n("Change Account")); confButton->setIcon(QIcon::fromTheme(QLatin1String("system-switch-user"))); confButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QGroupBox* const optionsBox = new QGroupBox(i18n("Options")); QVBoxLayout* const vlay2 = new QVBoxLayout(); resizeCheckBox = new QCheckBox(optionsBox); resizeCheckBox->setText(i18n("Resize photos before uploading")); QGridLayout* const glay = new QGridLayout; QLabel* const widthLabel = new QLabel(i18n("Maximum width:")); widthSpinBox = new QSpinBox; widthSpinBox->setRange(1,8000); widthSpinBox->setValue(1600); QLabel* const heightLabel = new QLabel(i18n("Maximum height:")); heightSpinBox = new QSpinBox; heightSpinBox->setRange(1,8000); heightSpinBox->setValue(1600); QLabel* const qualityLabel= new QLabel(i18n("Resized JPEG quality:")); qualitySpinBox = new QSpinBox; qualitySpinBox->setRange(1,100); qualitySpinBox->setValue(95); resizeCheckBox->setChecked(false); widthSpinBox->setEnabled(false); heightSpinBox->setEnabled(false); qualitySpinBox->setEnabled(false); // --------------------------------------------------------------------------- glay->addWidget(widthLabel, 0, 0); glay->addWidget(widthSpinBox, 0, 1); glay->addWidget(heightLabel, 1, 0); glay->addWidget(heightSpinBox, 1, 1); glay->addWidget(qualityLabel, 2, 0); glay->addWidget(qualitySpinBox, 2, 1); // --------------------------------------------------------------------------- vlay2->addWidget(resizeCheckBox); vlay2->addLayout(glay); vlay2->addStretch(0); optionsBox->setLayout(vlay2); // --------------------------------------------------------------------------- vlay->addWidget(confButton); vlay->addWidget(optionsBox); optionFrame->setLayout(vlay); // --------------------------------------------------------------------------- hlay->addWidget(logo); hlay->addWidget(albumView); hlay->addWidget(optionFrame); widget->setLayout(hlay); } // --------------------------------------------------------------------------- PiwigoWindow::PiwigoWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(nullptr, QLatin1String("PiwigoSync Dialog")), d(new Private(this, iface)) { d->pPiwigo = new PiwigoSession(); setWindowTitle(i18n("Piwigo Export")); setModal(false); // "Start Upload" button + startButton()->setText(i18n("Start Upload")); startButton()->setEnabled(false); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotAddPhoto())); // we need to let d->talker work.. + d->talker = new PiwigoTalker(iface, d->widget); // setting progressDlg and its numeric hints + d->progressDlg = new QProgressDialog(this); d->progressDlg->setModal(true); d->progressDlg->setAutoReset(true); d->progressDlg->setAutoClose(true); d->progressDlg->setMaximum(0); d->progressDlg->reset(); // connect functions + connectSignals(); KConfig config; if (!config.hasGroup("Piwigo Settings")) { QPointer dlg = new PiwigoLoginDlg(QApplication::activeWindow(), d->pPiwigo, i18n("Edit Piwigo Data")); dlg->exec(); delete dlg; } readSettings(); slotDoLogin(); } PiwigoWindow::~PiwigoWindow() { // write config + KConfig config; KConfigGroup group = config.group("PiwigoSync Galleries"); group.writeEntry("Resize", d->resizeCheckBox->isChecked()); group.writeEntry("Maximum Width", d->widthSpinBox->value()); group.writeEntry("Maximum Height", d->heightSpinBox->value()); group.writeEntry("Quality", d->qualitySpinBox->value()); delete d->talker; delete d->pPiwigo; delete d; } void PiwigoWindow::connectSignals() { connect(d->albumView, SIGNAL(itemSelectionChanged()), this, SLOT(slotAlbumSelected())); connect(d->confButton, SIGNAL(clicked()), this, SLOT(slotSettings())); connect(d->resizeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotEnableSpinBox(int))); connect(d->progressDlg, SIGNAL(canceled()), this, SLOT(slotAddPhotoCancel())); connect(d->talker, SIGNAL(signalProgressInfo(QString)), this, SLOT(slotProgressInfo(QString))); connect(d->talker, SIGNAL(signalError(QString)), this, SLOT(slotError(QString))); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalLoginFailed(QString)), this, SLOT(slotLoginFailed(QString))); connect(d->talker, SIGNAL(signalAlbums(QList)), this, SLOT(slotAlbums(QList))); connect(d->talker, SIGNAL(signalAddPhotoSucceeded()), this, SLOT(slotAddPhotoSucceeded())); connect(d->talker, SIGNAL(signalAddPhotoFailed(QString)), this, SLOT(slotAddPhotoFailed(QString))); } void PiwigoWindow::readSettings() { KConfig config; KConfigGroup group = config.group("PiwigoSync Galleries"); if (group.readEntry("Resize", false)) { d->resizeCheckBox->setChecked(true); d->widthSpinBox->setEnabled(true); d->heightSpinBox->setEnabled(true); } else { d->resizeCheckBox->setChecked(false); d->heightSpinBox->setEnabled(false); d->widthSpinBox->setEnabled(false); } d->widthSpinBox->setValue(group.readEntry("Maximum Width", 1600)); d->heightSpinBox->setValue(group.readEntry("Maximum Height", 1600)); d->qualitySpinBox->setValue(group.readEntry("Quality", 95)); } void PiwigoWindow::slotDoLogin() { QUrl url(d->pPiwigo->url()); if (url.scheme().isEmpty()) { url.setScheme(QLatin1String("http")); url.setHost(d->pPiwigo->url()); } // If we've done something clever, save it back to the piwigo. - if (!url.url().isEmpty() && d->pPiwigo->url() != url.url()) + + if (!url.url().isEmpty() && (d->pPiwigo->url() != url.url())) { d->pPiwigo->setUrl(url.url()); d->pPiwigo->save(); } d->talker->login(url, d->pPiwigo->username(), d->pPiwigo->password()); } void PiwigoWindow::slotLoginFailed(const QString& msg) { if (QMessageBox::question(this, i18n("Login Failed"), i18n("Failed to login into remote piwigo. ") + msg + i18n("\nDo you want to check your settings and try again?")) != QMessageBox::Yes) { close(); return; } QPointer dlg = new PiwigoLoginDlg(QApplication::activeWindow(), d->pPiwigo, i18n("Edit Piwigo Data")); int result = dlg->exec(); delete dlg; if (result != QDialog::Accepted) { return; } slotDoLogin(); } void PiwigoWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); startButton()->setEnabled(false); } else { setCursor(Qt::ArrowCursor); bool loggedIn = d->talker->loggedIn(); startButton()->setEnabled(loggedIn && d->albumView->currentItem()); } } void PiwigoWindow::slotProgressInfo(const QString& msg) { d->progressDlg->setLabelText(msg); } void PiwigoWindow::slotError(const QString& msg) { d->progressDlg->hide(); QMessageBox::critical(this, QString(), msg); } void PiwigoWindow::slotAlbums(const QList& albumList) { d->albumDict.clear(); d->albumView->clear(); // album work list + QList workList(albumList); QList parentItemList; // fill QTreeWidget + while (!workList.isEmpty()) { // the album to work on + PiwigoAlbum album = workList.takeFirst(); int parentRefNum = album.m_parentRefNum; if (parentRefNum == -1) { QTreeWidgetItem* const item = new QTreeWidgetItem(); item->setText(0, cleanName(album.m_name)); item->setIcon(0, QIcon::fromTheme(QLatin1String("inode-directory"))); item->setData(1, Qt::UserRole, QVariant(album.m_refNum)); item->setText(2, i18n("Album")); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Top : " << album.m_name << " " << album.m_refNum << "\n"; d->albumView->addTopLevelItem(item); d->albumDict.insert(album.m_name, album); parentItemList << item; } else { QTreeWidgetItem* parentItem = nullptr; bool found = false; int i = 0; while (!found && i < parentItemList.size()) { parentItem = parentItemList.at(i); if (parentItem && (parentItem->data(1, Qt::UserRole).toInt() == parentRefNum)) { QTreeWidgetItem* const item = new QTreeWidgetItem(parentItem); item->setText(0, cleanName(album.m_name)); item->setIcon(0, QIcon::fromTheme(QLatin1String("inode-directory"))); item->setData(1, Qt::UserRole, album.m_refNum); item->setText(2, i18n("Album")); parentItem->addChild(item); d->albumDict.insert(album.m_name, album); parentItemList << item; found = true; } i++; } } } } void PiwigoWindow::slotAlbumSelected() { QTreeWidgetItem* const item = d->albumView->currentItem(); // stop loading if user clicked an image - if (item && item->text(2) == i18n("Image")) + + if (item && (item->text(2) == i18n("Image"))) + { return; + } if (!item) { startButton()->setEnabled(false); } else { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Album selected\n"; int albumId = item->data(1, Qt::UserRole).toInt(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << albumId << "\n"; if (d->talker->loggedIn() && albumId) { startButton()->setEnabled(true); } else { startButton()->setEnabled(false); } } } void PiwigoWindow::slotAddPhoto() { const QList urls(d->iface->currentSelectedItems()); if (urls.isEmpty()) { QMessageBox::critical(this, QString(), i18n("Nothing to upload - please select photos to upload.")); return; } - for (QList::const_iterator it = urls.constBegin(); - it != urls.constEnd(); ++it) + for (QList::const_iterator it = urls.constBegin() ; + it != urls.constEnd() ; ++it) { d->pUploadList.append((*it).toLocalFile()); } d->uploadTotal = d->pUploadList.count(); d->progressDlg->reset(); d->progressDlg->setMaximum(d->uploadTotal); d->uploadCount = 0; slotAddPhotoNext(); } void PiwigoWindow::slotAddPhotoNext() { if (d->pUploadList.isEmpty()) { d->progressDlg->reset(); d->progressDlg->hide(); return; } QTreeWidgetItem* const item = d->albumView->currentItem(); int column = d->albumView->currentColumn(); QString albumTitle = item->text(column); const PiwigoAlbum& album = d->albumDict.value(albumTitle); QString photoPath = d->pUploadList.takeFirst(); bool res = d->talker->addPhoto(album.m_refNum, photoPath, d->resizeCheckBox->isChecked(), d->widthSpinBox->value(), d->heightSpinBox->value(), d->qualitySpinBox->value()); if (!res) { slotAddPhotoFailed(i18n("The file %1 is not a supported image or video format", QUrl(photoPath).fileName())); return; } d->progressDlg->setLabelText(i18n("Uploading file %1", QUrl(photoPath).fileName())); if (d->progressDlg->isHidden()) + { d->progressDlg->show(); + } } void PiwigoWindow::slotAddPhotoSucceeded() { d->uploadCount++; d->progressDlg->setValue(d->uploadCount); slotAddPhotoNext(); } void PiwigoWindow::slotAddPhotoFailed(const QString& msg) { d->progressDlg->reset(); d->progressDlg->hide(); if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload media into remote Piwigo. ") + msg + i18n("\nDo you want to continue?")) != QMessageBox::Yes) { return; } else { slotAddPhotoNext(); } } void PiwigoWindow::slotAddPhotoCancel() { d->progressDlg->reset(); d->progressDlg->hide(); d->talker->cancel(); } void PiwigoWindow::slotEnableSpinBox(int n) { bool b; switch (n) { case 0: b = false; break; + case 1: case 2: b = true; break; + default: b = false; break; } d->widthSpinBox->setEnabled(b); d->heightSpinBox->setEnabled(b); d->qualitySpinBox->setEnabled(b); } void PiwigoWindow::slotSettings() { // TODO: reload albumlist if OK slot used. + QPointer dlg = new PiwigoLoginDlg(QApplication::activeWindow(), d->pPiwigo, i18n("Edit Piwigo Data")); if (dlg->exec() == QDialog::Accepted) { slotDoLogin(); } delete dlg; } QString PiwigoWindow::cleanName(const QString& str) const { QString plain = str; plain.replace(QLatin1String("<"), QLatin1String("<")); plain.replace(QLatin1String(">"), QLatin1String(">")); plain.replace(QLatin1String("""), QLatin1String("\"")); plain.replace(QLatin1String("&"), QLatin1String("&")); return plain; } } // namespace DigikamGenericPiwigoPlugin