Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -247,6 +247,7 @@ add_subdirectory(dropbox) add_subdirectory(facebook) add_subdirectory(imgur) + add_subdirectory(ipfs) add_subdirectory(piwigo) add_subdirectory(rajce) add_subdirectory(smug) Index: ipfs/CMakeLists.txt =================================================================== --- /dev/null +++ ipfs/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright (C) 2018 by Amar Lakshya +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +subdirs(icons) + +add_definitions(-DTRANSLATION_DOMAIN=\"kipiplugin_ipfs\") + +set(kipiplugin_ipfs_PART_SRCS + plugin_ipfs.cpp + ipfsglobaluploadapi.cpp + ipfswindow.cpp + ipfsimageslist.cpp + ) + +add_library(kipiplugin_ipfs MODULE ${kipiplugin_ipfs_PART_SRCS}) + +target_link_libraries(kipiplugin_ipfs + Qt5::Network + + KF5::Kipi + KF5::WindowSystem + KF5::I18n + + KF5kipiplugins +) + +configure_file(kipiplugin_ipfs.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kipiplugin_ipfs.desktop) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kipiplugin_ipfs.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +install(TARGETS kipiplugin_ipfs DESTINATION ${PLUGIN_INSTALL_DIR}) +install(FILES kipiplugin_ipfsui.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/kipi) Index: ipfs/Messages.sh =================================================================== --- /dev/null +++ ipfs/Messages.sh @@ -0,0 +1,4 @@ +#! /bin/sh +$EXTRACTRC `find . -name "*.ui" -o -name "*.rc" -o -name "*.kcfg" ` >> rc.cpp +$XGETTEXT `find . -name "*.cpp" -o -name "*.h"` -o $podir/kipiplugin_ipfs.pot +rm -f rc.cpp Index: ipfs/icons/.directory =================================================================== --- /dev/null +++ ipfs/icons/.directory @@ -0,0 +1,3 @@ +[Dolphin] +Timestamp=2018,10,13,0,33,45 +Version=4 Index: ipfs/icons/CMakeLists.txt =================================================================== --- /dev/null +++ ipfs/icons/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright (c) 2010-2015, Gilles Caulier, +# Copyright (c) 2015, Alexander Potashev, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +ecm_install_icons( + ICONS + 16-apps-kipi-ipfs.png + 22-apps-kipi-ipfs.png + 32-apps-kipi-ipfs.png + 48-apps-kipi-ipfs.png + sc-apps-kipi-ipfs.svgz + DESTINATION ${ICON_INSTALL_DIR} +) Index: ipfs/icons/sc-apps-kipi-ipfs.svgz =================================================================== --- /dev/null +++ ipfs/icons/sc-apps-kipi-ipfs.svgz @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: ipfs/ipfs.kde4 =================================================================== --- /dev/null +++ ipfs/ipfs.kde4 @@ -0,0 +1,4 @@ +[Project] +CreatedFrom=CMakeLists.txt +Manager=KDevCMakeManager +Name=IPFS Index: ipfs/ipfsglobaluploadapi.h =================================================================== --- /dev/null +++ ipfs/ipfsglobaluploadapi.h @@ -0,0 +1,124 @@ +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 IMGURGLOBALUPLOADAPI_H +#define IMGURGLOBALUPLOADAPI_H + +// C++ includes + +#include +#include + +// Qt includes + +#include +#include +#include +#include + +// Local includes + +#include "o2.h" + +enum class IPFSGLOBALUPLOADAPIActionType +{ + IMG_UPLOAD, /* Action: upload Result: image */ +}; + +struct IPFSGLOBALUPLOADAPIAction +{ + IPFSGLOBALUPLOADAPIActionType type; + struct + { + QString imgpath; + QString title; + QString description; + } upload; +}; + +struct IPFSGLOBALUPLOADAPIResult +{ + const IPFSGLOBALUPLOADAPIAction* action; + + struct IPFSImage + { + QString name; + QString url; + uint size; + } image; +}; + +/* Main class, handles the client side of the globalupload.io API */ +class IPFSGLOBALUPLOADAPI : public QObject +{ +Q_OBJECT + +public: + IPFSGLOBALUPLOADAPI(QObject* parent = nullptr); + ~IPFSGLOBALUPLOADAPI(); + unsigned int workQueueLength(); + void queueWork(const IPFSGLOBALUPLOADAPIAction& action); + void cancelAllWork(); + +Q_SIGNALS: + /* Emitted on progress changes. */ + void progress(unsigned int percent, const IPFSGLOBALUPLOADAPIAction& action); + void success(const IPFSGLOBALUPLOADAPIResult& result); + void error(const QString& msg, const IPFSGLOBALUPLOADAPIAction& action); + + /* Emitted when the status changes. */ + void busy(bool b); + +public Q_SLOTS: + /* Connected to the current QNetworkReply. */ + void uploadProgress(qint64 sent, qint64 total); + void replyFinished(); + +protected: + void timerEvent(QTimerEvent* event) override; + +private: + /* Starts m_work_timer if m_work_queue not empty. */ + void startWorkTimer(); + /* Stops m_work_timer if running. */ + void stopWorkTimer(); + + /* Start working on the first item of m_work_queue + * by sending a request. */ + void doWork(); + + /* Work queue. */ + std::queue m_work_queue; + /* ID of timer triggering on idle (0ms). */ + int m_work_timer = 0; + + /* Current QNetworkReply */ + QNetworkReply* m_reply = nullptr; + + /* Current image being uploaded */ + QFile* m_image = nullptr; + + /* The QNetworkAccessManager used for connections */ + QNetworkAccessManager m_net; +}; + +#endif // IMGURGLOBALUPLOADAPI_H Index: ipfs/ipfsglobaluploadapi.cpp =================================================================== --- /dev/null +++ ipfs/ipfsglobaluploadapi.cpp @@ -0,0 +1,244 @@ +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 "ipfsglobaluploadapi.h" + +// Qt includes + +#include +#include +#include +#include +#include +#include +#include + +// KDE includes + +#include + +// Local includes + +#include "kipiplugins_debug.h" +#include "o0settingsstore.h" +#include "o0globals.h" + +static const QString ipfs_upload_url = QLatin1String("https://api.globalupload.io/transport/add"); + +IPFSGLOBALUPLOADAPI::IPFSGLOBALUPLOADAPI(QObject* parent) + : QObject(parent) +{ +} + +IPFSGLOBALUPLOADAPI::~IPFSGLOBALUPLOADAPI() +{ + /* Disconnect all signals as cancelAllWork may emit */ + disconnect(this, 0, 0, 0); + cancelAllWork(); +} + +unsigned int IPFSGLOBALUPLOADAPI::workQueueLength() +{ + return m_work_queue.size(); +} + +void IPFSGLOBALUPLOADAPI::queueWork(const IPFSGLOBALUPLOADAPIAction& action) +{ + m_work_queue.push(action); + startWorkTimer(); +} + +void IPFSGLOBALUPLOADAPI::cancelAllWork() +{ + stopWorkTimer(); + + if (m_reply) + m_reply->abort(); + + /* Should error be emitted for those actions? */ + while (!m_work_queue.empty()) + m_work_queue.pop(); +} + +void IPFSGLOBALUPLOADAPI::uploadProgress(qint64 sent, qint64 total) +{ + if (total > 0) /* Don't divide by 0 */ + emit progress((sent * 100) / total, m_work_queue.front()); +} + +void IPFSGLOBALUPLOADAPI::replyFinished() +{ + auto* reply = m_reply; + reply->deleteLater(); + m_reply = nullptr; + + if (this->m_image) + { + delete this->m_image; + this->m_image = nullptr; + } + + if (m_work_queue.empty()) + { + qCDebug(KIPIPLUGINS_LOG) << "Received result without request"; + return; + } + + /* toInt() returns 0 if conversion fails. That fits nicely already. */ + int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + auto response = QJsonDocument::fromJson(reply->readAll()); + if (code == 200 && !response.isEmpty()) + { + /* Success! */ + IPFSGLOBALUPLOADAPIResult result; + result.action = &m_work_queue.front(); + switch (result.action->type) + { + case IPFSGLOBALUPLOADAPIActionType::IMG_UPLOAD: + result.image.name = response.object()[QLatin1String("Name")].toString(); + result.image.size = response.object()[QLatin1String("Size")].toInt(); + result.image.url = QLatin1String("https://ipfs.io/ipfs/") + response.object()[QLatin1String("Hash")].toString(); + break; + default: + qCWarning(KIPIPLUGINS_LOG) << "Unexpected action"; + qCDebug(KIPIPLUGINS_LOG) << response.toJson(); + break; + } + + emit success(result); + } + else + { + if (code == 403) + { + /* HTTP 403 Forbidden -> Invalid token? + * That needs to be handled internally, so don't emit progress + * and keep the action in the queue for later retries. */ + return; + } + else + { + /* Failed. */ + auto msg = response.object()[QLatin1String("data")] + .toObject()[QLatin1String("error")] + .toString(QLatin1String("Could not read response.")); + + emit error(msg, m_work_queue.front()); + } + } + + /* Next work item. */ + m_work_queue.pop(); + startWorkTimer(); +} + +void IPFSGLOBALUPLOADAPI::timerEvent(QTimerEvent* event) +{ + if (event->timerId() != m_work_timer) + return QObject::timerEvent(event); + + event->accept(); + + /* One-shot only. */ + QObject::killTimer(event->timerId()); + m_work_timer = 0; + + doWork(); +} + +void IPFSGLOBALUPLOADAPI::startWorkTimer() +{ + if (!m_work_queue.empty() && m_work_timer == 0) + { + m_work_timer = QObject::startTimer(0); + emit busy(true); + } + else + emit busy(false); +} + +void IPFSGLOBALUPLOADAPI::stopWorkTimer() +{ + if (m_work_timer != 0) + { + QObject::killTimer(m_work_timer); + m_work_timer = 0; + } +} + +void IPFSGLOBALUPLOADAPI::doWork() +{ + if (m_work_queue.empty() || m_reply != nullptr) + return; + + auto &work = m_work_queue.front(); + + switch(work.type) + { + case IPFSGLOBALUPLOADAPIActionType::IMG_UPLOAD: + { + this->m_image = new QFile(work.upload.imgpath); + + if (!m_image->open(QIODevice::ReadOnly)) + { + delete this->m_image; + this->m_image = nullptr; + + /* Failed. */ + emit error(i18n("Could not open file"), m_work_queue.front()); + + m_work_queue.pop(); + return doWork(); + } + + /* Set ownership to m_image to delete that as well. */ + auto* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType, m_image); + QHttpPart title; + title.setHeader(QNetworkRequest::ContentDispositionHeader, + QLatin1String("form-data; name=\"keyphrase\"")); + multipart->append(title); + + QHttpPart description; + description.setHeader(QNetworkRequest::ContentDispositionHeader, + QLatin1String("form-data; name=\"user\"")); + multipart->append(description); + + QHttpPart image; + image.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant(QString::fromLatin1("form-data; name=\"file\"; filename=\"%1\"") + .arg(QLatin1String(QFileInfo(work.upload.imgpath).fileName().toUtf8().toPercentEncoding())))); + image.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("image/jpeg")); + image.setBodyDevice(this->m_image); + multipart->append(image); + QNetworkRequest request(QUrl(QLatin1String("https://api.globalupload.io/transport/add"))); + this->m_reply = this->m_net.post(request, multipart); + + break; + } + } + + if (this->m_reply) + { + connect(m_reply, &QNetworkReply::uploadProgress, this, &IPFSGLOBALUPLOADAPI::uploadProgress); + connect(m_reply, &QNetworkReply::finished, this, &IPFSGLOBALUPLOADAPI::replyFinished); + } +} Index: ipfs/ipfsimageslist.h =================================================================== --- /dev/null +++ ipfs/ipfsimageslist.h @@ -0,0 +1,89 @@ + +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 IMGURIMAGESLIST_H +#define IMGURIMAGESLIST_H + +// Qt includes + +#include + +// Local includes + +#include "kpimageslist.h" +#include "ipfsglobaluploadapi.h" + +using namespace KIPI; +using namespace KIPIPlugins; + +namespace KIPIIPFSPlugin +{ + +class IPFSImageListViewItem; + +class IPFSImagesList : public KPImagesList +{ + Q_OBJECT + +public: + /* The different columns in a list. */ + enum FieldType + { + Title = KPImagesListView::User1, + Description = KPImagesListView::User2, + URL = KPImagesListView::User3, + }; + + IPFSImagesList(QWidget* const parent = 0); + ~IPFSImagesList() override {} + + QList getPendingItems(); + +public Q_SLOTS: + void slotAddImages(const QList& list) override; + void slotSuccess(const IPFSGLOBALUPLOADAPIResult& result); + void slotDoubleClick(QTreeWidgetItem* element, int i); +}; + +// ------------------------------------------------------------------------- + +class IPFSImageListViewItem : public KPImagesListViewItem +{ +public: + IPFSImageListViewItem(KPImagesListView* const view, const QUrl& url); + ~IPFSImageListViewItem() override {} + + void setTitle(const QString& str); + QString Title() const; + + void setDescription(const QString& str); + QString Description() const; + + void setIPFSUrl(const QString& str); + QString IPFSUrl() const; + +}; + +} // namespace KIPIIPFSPlugin + +#endif // IMGURIMAGESLIST_H Index: ipfs/ipfsimageslist.cpp =================================================================== --- /dev/null +++ ipfs/ipfsimageslist.cpp @@ -0,0 +1,199 @@ + +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 "ipfsimageslist.h" + +// C++ includes + +#include + +// Qt includes + +#include +#include +#include + +// KDE includes + +#include + +// Libkipi includes + +#include + +// Local includes + +#include "kipiplugins_debug.h" + +namespace KIPIIPFSPlugin +{ + +IPFSImagesList::IPFSImagesList(QWidget* const parent) + : KPImagesList(parent) +{ + setControlButtonsPlacement(KPImagesList::ControlButtonsBelow); + setAllowDuplicate(false); + setAllowRAW(false); + + auto* list = listView(); + + list->setColumnLabel(KPImagesListView::Thumbnail, i18n("Thumbnail")); + + list->setColumnLabel(static_cast(IPFSImagesList::Title), + i18n("Submission title")); + + list->setColumnLabel(static_cast(IPFSImagesList::Description), + i18n("Submission description")); + + list->setColumn(static_cast(IPFSImagesList::URL), + i18n("IPFS URL"), true); + + connect(list, &KPImagesListView::itemDoubleClicked, + this, &IPFSImagesList::slotDoubleClick); +} + +QList IPFSImagesList::getPendingItems() +{ + QList ret; + + for (unsigned int i = listView()->topLevelItemCount(); i--;) + { + const auto* item = dynamic_cast(listView()->topLevelItem(i)); + + if (item && item->IPFSUrl().isEmpty()) + ret << item; + } + + return ret; +} + +void IPFSImagesList::slotAddImages(const QList& list) +{ + /* Replaces the KPImagesList::slotAddImages method, so that + * IPFSImageListViewItems can be added instead of ImagesListViewItems */ + + std::unique_ptr meta; + + if (iface()) + meta = std::unique_ptr(iface()->createMetadataProcessor()); + + for (QList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) + { + // Already in the list? + if (listView()->findItem(*it) == nullptr) + { + auto* item = new IPFSImageListViewItem(listView(), *it); + + // Load URLs from meta data, if possible + if (meta && meta->load(*it)) + { + item->setIPFSUrl(meta->getXmpTagString(QLatin1String("Xmp.kipi.IPFSId"))); + } + } + } + + emit signalImageListChanged(); + emit signalAddItems(list); +} + +void IPFSImagesList::slotSuccess(const IPFSGLOBALUPLOADAPIResult& result) +{ + QUrl ipfsl = QUrl::fromLocalFile(result.action->upload.imgpath); + + processed(ipfsl, true); + + Interface* intf = iface(); + + if (intf) + { + QPointer meta = intf->createMetadataProcessor(); + + // Save URLs to meta data, if possible + if (meta && meta->load(ipfsl)) + { + meta->setXmpTagString(QLatin1String("Xmp.kipi.IPFSId"), result.image.url); + bool saved = meta->applyChanges(); + qCDebug(KIPIPLUGINS_LOG) << "Metadata" << (saved ? "Saved" : "Not Saved") << "to" << ipfsl; + } + } + + IPFSImageListViewItem* const currItem = dynamic_cast(listView()->findItem(ipfsl)); + + if (!currItem) + return; + + if (!result.image.url.isEmpty()) + currItem->setIPFSUrl(result.image.url); +} + +void IPFSImagesList::slotDoubleClick(QTreeWidgetItem* element, int i) +{ + if (i == URL ) + { + const QUrl url = QUrl(element->text(i)); + // The delete page asks for confirmation, so we don't need to do that here + QDesktopServices::openUrl(url); + } +} + +// ------------------------------------------------------------------------------------------------ + +IPFSImageListViewItem::IPFSImageListViewItem(KPImagesListView* const view, const QUrl& url) + : KPImagesListViewItem(view, url) +{ + const QColor blue(50, 50, 255); + + setTextColor(IPFSImagesList::URL, blue); +} + +void IPFSImageListViewItem::setTitle(const QString& str) +{ + setText(IPFSImagesList::Title, str); +} + +QString IPFSImageListViewItem::Title() const +{ + return text(IPFSImagesList::Title); +} + +void IPFSImageListViewItem::setDescription(const QString& str) +{ + setText(IPFSImagesList::Description, str); +} + +QString IPFSImageListViewItem::Description() const +{ + return text(IPFSImagesList::Description); +} + +void IPFSImageListViewItem::setIPFSUrl(const QString& str) +{ + setText(IPFSImagesList::URL, str); +} + +QString IPFSImageListViewItem::IPFSUrl() const +{ + return text(IPFSImagesList::URL); +} + +} // namespace KIPIIPFSPlugin Index: ipfs/ipfswindow.h =================================================================== --- /dev/null +++ ipfs/ipfswindow.h @@ -0,0 +1,93 @@ +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 IMGURWINDOW_H +#define IMGURWINDOW_H + +// Qt includes + +#include +#include + +// Libkipi includes + +#include + +// Local includes + +#include "ipfsimageslist.h" +#include "kptooldialog.h" +#include "ipfsglobaluploadapi.h" + +namespace KIPI +{ + class Interface; +} + +using namespace KIPI; +using namespace KIPIPlugins; + +namespace KIPIIPFSPlugin +{ + +class IPFSWindow : public KPToolDialog +{ + Q_OBJECT + +public: + IPFSWindow(QWidget* const parent = 0); + ~IPFSWindow(); + + void reactivate(); + +public Q_SLOTS: + /* UI callbacks */ + void slotUpload(); + void slotFinished(); + void slotCancel(); + + /* IPFSGLOBALUPLOADAPI callbacks */ +/* void apiAuthorized(bool success, const QString& username); */ + /* void apiAuthError(const QString& msg); */ + void apiProgress(unsigned int percent, const IPFSGLOBALUPLOADAPIAction& action); + void apiRequestPin(const QUrl& url); + void apiSuccess(const IPFSGLOBALUPLOADAPIResult& result); + void apiError(const QString &msg, const IPFSGLOBALUPLOADAPIAction& action); + void apiBusy(bool busy); + +private: + void closeEvent(QCloseEvent* e) Q_DECL_OVERRIDE; + void setContinueUpload(bool state); + void readSettings(); + void saveSettings(); + +private: + IPFSImagesList* list = nullptr; + IPFSGLOBALUPLOADAPI* api = nullptr; + /* Contains the ipfs username if API authorized. + * If not, username is null. */ + QString username; +}; + +} // namespace KIPIIPFSPlugin + +#endif /* IMGURWINDOW_H */ Index: ipfs/ipfswindow.cpp =================================================================== --- /dev/null +++ ipfs/ipfswindow.cpp @@ -0,0 +1,254 @@ +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 "ipfswindow.h" + +// Qt includes + +#include +#include +#include +#include +#include +#include + +// KDE includes + +#include +#include +#include + +// Local includes + +#include "kipiplugins_debug.h" +#include "kpimageinfo.h" +#include "kpaboutdata.h" +#include "kpversion.h" + +namespace KIPIIPFSPlugin +{ + +IPFSWindow::IPFSWindow(QWidget* const /*parent*/) + : KPToolDialog(0) +{ + api = new IPFSGLOBALUPLOADAPI(this); + + /* Connect API signals */ + + connect(api, &IPFSGLOBALUPLOADAPI::progress, this, &IPFSWindow::apiProgress); + connect(api, &IPFSGLOBALUPLOADAPI::success, this, &IPFSWindow::apiSuccess); + connect(api, &IPFSGLOBALUPLOADAPI::error, this, &IPFSWindow::apiError); + connect(api, &IPFSGLOBALUPLOADAPI::busy, this, &IPFSWindow::apiBusy); + + /* | List | Auth | */ + auto* mainLayout = new QHBoxLayout; + auto* mainWidget = new QWidget(this); + mainWidget->setLayout(mainLayout); + this->setMainWidget(mainWidget); + + this->list = new IPFSImagesList; + mainLayout->addWidget(list); + + /* | Logged in as: | + * | | + * | Forget | */ + + + + auto* authLayout = new QVBoxLayout; + mainLayout->addLayout(authLayout); + + authLayout->insertStretch(-1, 1); + + /* Add anonymous upload button */ + /* Connect UI signals */ + connect(startButton(), &QPushButton::clicked, + this, &IPFSWindow::slotUpload); + connect(this, &IPFSWindow::finished, + this, &IPFSWindow::slotFinished); + connect(this, &IPFSWindow::cancelClicked, + this, &IPFSWindow::slotCancel); + + setWindowIcon(QIcon::fromTheme(QString::fromLatin1("kipi-ipfs"))); + setWindowTitle(i18n("Export to IPFS")); + setModal(false); + + startButton()->setText(i18n("Upload")); + startButton()->setToolTip(i18n("Start upload to IPFS")); + startButton()->setEnabled(true); + + /* Add about data */ + + KPAboutData* const about = new KPAboutData(ki18n("IPFS Export"), + ki18n("A tool to export images to IPFS web service"), + ki18n("(c) 2018, Amar Lakshya")); + + about->addAuthor(ki18n("Amar Lakshya").toString(), + ki18n("Author").toString(), + QString::fromLatin1("amar dot lakshya at xaviers dot edu dot in")); + + about->setHandbookEntry(QString::fromLatin1("tool-ipfsexport")); + setAboutData(about); + + /* Only used if not overwritten by readSettings() */ + resize(650, 320); + readSettings(); +} + +IPFSWindow::~IPFSWindow() +{ + saveSettings(); +} + +void IPFSWindow::reactivate() +{ + list->loadImagesFromCurrentSelection(); + show(); +} + +void IPFSWindow::slotUpload() +{ + QList pending = this->list->getPendingItems(); + + for (auto item : pending) + { + IPFSGLOBALUPLOADAPIAction action; + action.type = IPFSGLOBALUPLOADAPIActionType::IMG_UPLOAD; + action.upload.imgpath = item->url().toLocalFile(); + action.upload.title = item->Title(); + action.upload.description = item->Description(); + + api->queueWork(action); + } +} + + +void IPFSWindow::slotFinished() +{ + saveSettings(); +} + +void IPFSWindow::slotCancel() +{ + api->cancelAllWork(); +} + +/* void IPFSWindow::apiAuthorized(bool success, const QString& username) */ +// { + // if (success) + // { + // this->username = username; + // this->userLabel->setText(this->username); + // this->forgetButton->setEnabled(true); + // return; + // } +// + // this->username = QString(); + // this->userLabel->setText(i18n("")); + // this->forgetButton->setEnabled(false); +/* } */ + +/* void IPFSWindow::apiAuthError(const QString& msg) */ +// { + // QMessageBox::critical(this, + // i18n("Authorization Failed"), + // i18n("Failed to log into IPFS: %1\n", msg)); +// } +/* */ +void IPFSWindow::apiProgress(unsigned int /*percent*/, const IPFSGLOBALUPLOADAPIAction& action) +{ + list->processing(QUrl::fromLocalFile(action.upload.imgpath)); +} + +void IPFSWindow::apiRequestPin(const QUrl& url) +{ + QDesktopServices::openUrl(url); +} + +void IPFSWindow::apiSuccess(const IPFSGLOBALUPLOADAPIResult& result) +{ + list->slotSuccess(result); +} + +void IPFSWindow::apiError(const QString& msg, const IPFSGLOBALUPLOADAPIAction& action) +{ + list->processed(QUrl::fromLocalFile(action.upload.imgpath), false); + + /* 1 here because the current item is still in the queue. */ + if (api->workQueueLength() <= 1) + { + QMessageBox::critical(this, + i18n("Uploading Failed"), + i18n("Failed to upload photo to IPFS: %1\n", msg)); + return; + } + + QMessageBox::StandardButton cont = + QMessageBox::question(this, + i18n("Uploading Failed"), + i18n("Failed to upload photo to IPFS: %1\n" + "Do you want to continue?", msg)); + + if (cont != QMessageBox::Yes) + api->cancelAllWork(); +} + +void IPFSWindow::apiBusy(bool busy) +{ + setCursor(busy ? Qt::WaitCursor : Qt::ArrowCursor); + startButton()->setEnabled(!busy); +} + +void IPFSWindow::closeEvent(QCloseEvent* e) +{ + if (!e) + return; + + slotFinished(); + e->accept(); +} + +void IPFSWindow::readSettings() +{ + KConfig config(QString::fromLatin1("kipirc")); + KConfigGroup groupAuth = config.group("IPFS Auth"); + username = groupAuth.readEntry("username", QString()); + // apiAuthorized(!username.isEmpty(), username); + + winId(); + KConfigGroup groupDialog = config.group("IPFS Dialog"); + KWindowConfig::restoreWindowSize(windowHandle(), groupDialog); + resize(windowHandle()->size()); +} + +void IPFSWindow::saveSettings() +{ + KConfig config(QString::fromLatin1("kipirc")); + KConfigGroup groupAuth = config.group("IPFS Auth"); + groupAuth.writeEntry("username", username); + + KConfigGroup groupDialog = config.group("IPFS Dialog"); + KWindowConfig::saveWindowSize(windowHandle(), groupDialog); + config.sync(); +} + +} // namespace KIPIIPFSPlugin Index: ipfs/kipiplugin_ipfs.desktop.cmake =================================================================== --- /dev/null +++ ipfs/kipiplugin_ipfs.desktop.cmake @@ -0,0 +1,11 @@ +[Desktop Entry] +UntranslatedGenericName=IPFS Export +Name=IPFS Export +Comment=A tool to export images to the ipfs.com image hosting service +Type=Service +Icon=kipi-ipfs +ServiceTypes=KIPI/Plugin +X-KDE-Library=kipiplugin_ipfs +X-KIPI-PluginCategories=Export +X-KIPI-BinaryVersion=${KIPI_LIB_SO_CUR_VERSION} +author=Amar Lakshya, amar at lakshya dot xaviers dot edu dot in Index: ipfs/kipiplugin_ipfsui.rc =================================================================== --- /dev/null +++ ipfs/kipiplugin_ipfsui.rc @@ -0,0 +1,17 @@ + + + + + + + &Export + + + + + + Main Toolbar + + + + Index: ipfs/plugin_ipfs.h =================================================================== --- /dev/null +++ ipfs/plugin_ipfs.h @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 PLUGIN_IMGUR_H +#define PLUGIN_IMGUR_H + +// Qt includes + +#include + +// Libkipi includes + +#include + +// Local includes + +#include "ipfswindow.h" + +using namespace KIPI; + +namespace KIPIIPFSPlugin +{ + +class Plugin_IPFS : public Plugin +{ + Q_OBJECT + +public: + + explicit Plugin_IPFS(QObject* const parent, const QVariantList& args); + ~Plugin_IPFS(); + + void setup(QWidget* const) Q_DECL_OVERRIDE; + +public Q_SLOTS: + + void slotActivate(); + +private: + + void setupActions(); + +private: + + class Private; + Private* const d; +}; + +} // namespace KIPIIPFSPlugin + +#endif // PLUGIN_IMGUREXPORT_H Index: ipfs/plugin_ipfs.cpp =================================================================== --- /dev/null +++ ipfs/plugin_ipfs.cpp @@ -0,0 +1,135 @@ +/* ============================================================ + * + * This file is a part of KDE project + * + * + * Date : 2016-06-06 + * Description : a kipi plugin to export images to the IPFS web service + * + * Copyright (C) 2018 by Amar Lakshya + * + * 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 "plugin_ipfs.h" + +// Qt includes + +#include +#include + +// KDE includes + +#include +#include +#include +#include + +// Libkipi includes + +#include + +// Local includes + +#include "kipiplugins_debug.h" + +using namespace KIPIPlugins; + +namespace KIPIIPFSPlugin +{ + +K_PLUGIN_FACTORY( IPFSFactory, registerPlugin(); ) + +class Plugin_IPFS::Private +{ +public: + + Private() + { + actionExport = 0; + winExport = 0; + } + + QAction* actionExport; + IPFSWindow* winExport; +}; + +Plugin_IPFS::Plugin_IPFS(QObject* const parent, const QVariantList& /*args*/) + : Plugin(parent, "IPFS"), + d(new Private) +{ + qCDebug(KIPIPLUGINS_LOG) << "IPFS plugin loaded"; + + setUiBaseName("kipiplugin_ipfsui.rc"); + setupXML(); +} + +Plugin_IPFS::~Plugin_IPFS() +{ + delete d->winExport; + delete d; +} + +void Plugin_IPFS::setup(QWidget* const widget) +{ + d->winExport = 0; + + Plugin::setup(widget); + + if (!interface()) + { + qCCritical(KIPIPLUGINS_LOG) << "Kipi interface is null!"; + return; + } + + setupActions(); +} + +void Plugin_IPFS::setupActions() +{ + setDefaultCategory(ExportPlugin); + + d->actionExport = new QAction(this); + d->actionExport->setText(i18n("Export to &IPFS...")); + d->actionExport->setIcon(QIcon::fromTheme(QString::fromLatin1("kipi-ipfs"))); + + connect(d->actionExport, SIGNAL(triggered(bool)), + this, SLOT(slotActivate())); + + addAction(QString::fromLatin1("ipfsexport"), d->actionExport); +} + +void Plugin_IPFS::slotActivate() +{ + if (!d->winExport) + { + // We clean it up in the close button + d->winExport = new IPFSWindow(QApplication::activeWindow()); + } + else + { + if (d->winExport->isMinimized()) + { + KWindowSystem::unminimizeWindow(d->winExport->winId()); + } + + KWindowSystem::activateWindow(d->winExport->winId()); + } + + d->winExport->reactivate(); + + qCDebug(KIPIPLUGINS_LOG) << "We have activated the ipfs exporter!"; +} + +} // namespace KIPIIPFSPlugin + +#include "plugin_ipfs.moc"