Run astyle-kdelibs on the source

This commit is contained in:
Luca Beltrame 2014-10-05 09:53:19 +02:00
parent 4b85d63d68
commit 39aac8c95b
22 changed files with 1227 additions and 1264 deletions

View file

@ -17,8 +17,6 @@
* along with Danbooru Client. If not, see <http://www.gnu.org/licenses/>. * along with Danbooru Client. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "danbooruclientview.h" #include "danbooruclientview.h"
// Own // Own
@ -35,54 +33,53 @@
#include <KRun> #include <KRun>
#include <KFileDialog> #include <KFileDialog>
namespace Danbooru { namespace Danbooru
{
DanbooruClientView::DanbooruClientView(QWidget * parent): QWidget(parent), DanbooruClientView::DanbooruClientView(QWidget *parent): QWidget(parent),
m_model(new DanbooruPostModel(this)), m_model(new DanbooruPostModel(this)),
m_delegate(0), m_delegate(0),
m_service(0), m_service(0),
m_timer(0) m_timer(0)
{ {
setupUi(this); setupUi(this);
m_delegate = new DanbooruPostDelegate(m_listView); m_delegate = new DanbooruPostDelegate(m_listView);
m_listView->setFlow(QListView::LeftToRight); m_listView->setFlow(QListView::LeftToRight);
m_listView->setResizeMode(QListView::Adjust); m_listView->setResizeMode(QListView::Adjust);
m_listView->setWrapping(true); m_listView->setWrapping(true);
m_listView->setViewMode(QListView::IconMode); m_listView->setViewMode(QListView::IconMode);
m_listView->setGridSize(QSize(256,256)); m_listView->setGridSize(QSize(256, 256));
m_listView->setModel(m_model); m_listView->setModel(m_model);
m_listView->setItemDelegate(m_delegate); m_listView->setItemDelegate(m_delegate);
// signal-slot connections // signal-slot connections
connect(m_delegate, &DanbooruPostDelegate::postDownloadRequested, this, &DanbooruClientView::slotHandleDownload); connect(m_delegate, &DanbooruPostDelegate::postDownloadRequested, this, &DanbooruClientView::slotHandleDownload);
connect(m_delegate, &DanbooruPostDelegate::postViewRequested, this, &DanbooruClientView::slotHandleView); connect(m_delegate, &DanbooruPostDelegate::postViewRequested, this, &DanbooruClientView::slotHandleView);
// connect(m_listView, SIGNAL(clicked(const QModelIndex&)), parent(), // connect(m_listView, SIGNAL(clicked(QModelIndex)), parent(),
// SLOT(displayInfo(const QModelIndex&)); // SLOT(displayInfo(QModelIndex));
}
} DanbooruClientView::~DanbooruClientView()
{
DanbooruClientView::~DanbooruClientView() }
{
} void DanbooruClientView::slotHandleDownload(QUrl url)
{
void DanbooruClientView::slotHandleDownload(QUrl url) // TODO
{ Q_UNUSED(url)
// TODO }
Q_UNUSED(url)
}
void DanbooruClientView::slotHandleView(QUrl url)
{
KRun* runViewer = new KRun(url, this /*window*/, true /*showProgressInfo*/,
"" /*asn*/);
runViewer->setAutoDelete(true);
}
void DanbooruClientView::slotHandleView(QUrl url)
{
KRun *runViewer = new KRun(url, this /*window*/, true /*showProgressInfo*/,
"" /*asn*/);
runViewer->setAutoDelete(true);
}
} // namespace Danbooru } // namespace Danbooru

View file

@ -28,47 +28,48 @@
class QTimer; class QTimer;
namespace Danbooru { namespace Danbooru
{
class DanbooruPostModel; class DanbooruPostModel;
class DanbooruPostDelegate; class DanbooruPostDelegate;
class DanbooruService; class DanbooruService;
/**
* This is the main view class for danbooru_client. Most of the non-menu,
* non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
* here.
*
* @short Main view
* @author %{AUTHOR} <%{EMAIL}>
* @version %{VERSION}
*/
class DanbooruClientView : public QWidget, public Ui::DanbooruClientView
{
Q_OBJECT
public:
/**
* Default constructor
*/
DanbooruClientView(QWidget *parent = 0);
/** /**
* This is the main view class for danbooru_client. Most of the non-menu, * Destructor
* non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
* here.
*
* @short Main view
* @author %{AUTHOR} <%{EMAIL}>
* @version %{VERSION}
*/ */
virtual ~DanbooruClientView();
class DanbooruClientView : public QWidget, public Ui::DanbooruClientView private Q_SLOTS:
{ void slotHandleDownload(QUrl);
Q_OBJECT void slotHandleView(QUrl);
public: private:
/** DanbooruPostModel *m_model;
* Default constructor DanbooruPostDelegate *m_delegate;
*/ DanbooruService *m_service;
DanbooruClientView(QWidget *parent=0);
/** QTimer *m_timer;
* Destructor
*/
virtual ~DanbooruClientView();
private Q_SLOTS:
void slotHandleDownload(QUrl);
void slotHandleView(QUrl);
private:
DanbooruPostModel* m_model;
DanbooruPostDelegate* m_delegate;
DanbooruService* m_service;
QTimer* m_timer;
}; };

View file

@ -27,10 +27,10 @@
#include <KWallet> #include <KWallet>
using KWallet::Wallet; using KWallet::Wallet;
namespace Danbooru { namespace Danbooru
{
const QMap< QUrl, QString > initBoardSalts() const QMap< QUrl, QString > initBoardSalts()
{ {
@ -38,13 +38,13 @@ const QMap< QUrl, QString > initBoardSalts()
QMap< QUrl, QString > boardSalts; QMap< QUrl, QString > boardSalts;
boardSalts.insert(QUrl("http://konachan.com"), boardSalts.insert(QUrl("http://konachan.com"),
QString("So-I-Heard-You-Like-Mupkids-?--%1--")); QString("So-I-Heard-You-Like-Mupkids-?--%1--"));
boardSalts.insert(QUrl("http://konachan.net"), boardSalts.insert(QUrl("http://konachan.net"),
QString("So-I-Heard-You-Like-Mupkids-?--%1--")); QString("So-I-Heard-You-Like-Mupkids-?--%1--"));
boardSalts.insert(QUrl("http://yande.re"), boardSalts.insert(QUrl("http://yande.re"),
QString("choujin-steiner--%1--")); QString("choujin-steiner--%1--"));
boardSalts.insert(QUrl("http://danbooru.donmai.us"), boardSalts.insert(QUrl("http://danbooru.donmai.us"),
QString("choujin-steiner--%1--")); QString("choujin-steiner--%1--"));
return boardSalts; return boardSalts;
} }
@ -52,9 +52,9 @@ const QMap< QUrl, QString > initBoardSalts()
const QMap<QUrl, QString> DanbooruConnectWidget::boardSalts = initBoardSalts(); const QMap<QUrl, QString> DanbooruConnectWidget::boardSalts = initBoardSalts();
DanbooruConnectWidget::DanbooruConnectWidget(QVector< QUrl > urlList, DanbooruConnectWidget::DanbooruConnectWidget(QVector< QUrl > urlList,
QWidget* parent): QWidget *parent):
QWidget(parent), QWidget(parent),
m_wallet(0) m_wallet(0)
{ {
setupUi(this); setupUi(this);
@ -74,13 +74,13 @@ DanbooruConnectWidget::DanbooruConnectWidget(QVector< QUrl > urlList,
danbooruUrlComboBox->clear(); danbooruUrlComboBox->clear();
for (auto item: urlList) { for (auto item : urlList) {
danbooruUrlComboBox->insertUrl(urlList.indexOf(item), item); danbooruUrlComboBox->insertUrl(urlList.indexOf(item), item);
} }
m_wallet = Wallet::openWallet(Wallet::NetworkWallet(), winid, m_wallet = Wallet::openWallet(Wallet::NetworkWallet(), winid,
Wallet::Asynchronous Wallet::Asynchronous
); );
connect(m_wallet, &KWallet::Wallet::walletOpened, this, &DanbooruConnectWidget::checkWallet); connect(m_wallet, &KWallet::Wallet::walletOpened, this, &DanbooruConnectWidget::checkWallet);
@ -122,7 +122,6 @@ void DanbooruConnectWidget::getWalletData()
if (m_wallet->hasEntry(key)) { if (m_wallet->hasEntry(key)) {
if (m_wallet->readMap(key, valueMap) != 0) { if (m_wallet->readMap(key, valueMap) != 0) {
return; return;
} }
@ -133,7 +132,6 @@ void DanbooruConnectWidget::getWalletData()
} }
} }
void DanbooruConnectWidget::toggleLineEdits(int state) void DanbooruConnectWidget::toggleLineEdits(int state)
{ {
if (state == Qt::Unchecked) { if (state == Qt::Unchecked) {
@ -145,7 +143,6 @@ void DanbooruConnectWidget::toggleLineEdits(int state)
} }
} }
void DanbooruConnectWidget::emitRejected() void DanbooruConnectWidget::emitRejected()
{ {
Q_EMIT rejected(); Q_EMIT rejected();
@ -161,7 +158,6 @@ QString DanbooruConnectWidget::username() const
return m_username; return m_username;
} }
QString DanbooruConnectWidget::password() const QString DanbooruConnectWidget::password() const
{ {
return m_password; return m_password;
@ -178,7 +174,7 @@ void DanbooruConnectWidget::accept()
if (!m_username.isEmpty() && !m_password.isEmpty()) { if (!m_username.isEmpty() && !m_password.isEmpty()) {
if (m_wallet && !m_wallet->hasEntry(m_boardUrl.url())) { if (m_wallet && !m_wallet->hasEntry(m_boardUrl.url())) {
QMap<QString,QString> dataMap; QMap<QString, QString> dataMap;
dataMap.insert(QLatin1String("username"), m_username); dataMap.insert(QLatin1String("username"), m_username);
dataMap.insert(QLatin1String("password"), m_password); dataMap.insert(QLatin1String("password"), m_password);
m_wallet->writeMap(m_boardUrl.url(), dataMap); m_wallet->writeMap(m_boardUrl.url(), dataMap);
@ -186,16 +182,15 @@ void DanbooruConnectWidget::accept()
hashedPassword = boardSalts.value(m_boardUrl).arg(m_password); hashedPassword = boardSalts.value(m_boardUrl).arg(m_password);
hashedPassword = QCryptographicHash::hash(hashedPassword.toUtf8(), hashedPassword = QCryptographicHash::hash(hashedPassword.toUtf8(),
QCryptographicHash::Sha1 QCryptographicHash::Sha1
).toHex(); ).toHex();
} }
DanbooruService* service = new DanbooruService(m_boardUrl, m_username, DanbooruService *service = new DanbooruService(m_boardUrl, m_username,
hashedPassword); hashedPassword);
Q_EMIT(connectionEstablished(service)); Q_EMIT(connectionEstablished(service));
hide(); hide();
} }
}; // namespace Danbooru }; // namespace Danbooru

View file

@ -28,46 +28,48 @@
#include <QUrl> #include <QUrl>
namespace KWallet { namespace KWallet
class Wallet; {
class Wallet;
} }
namespace Danbooru { namespace Danbooru
{
class DanbooruService; class DanbooruService;
const QMap< QUrl, QString > initBoardSalts(); const QMap< QUrl, QString > initBoardSalts();
class DanbooruConnectWidget: public QWidget, public Ui::DanbooruConnectWidget { class DanbooruConnectWidget: public QWidget, public Ui::DanbooruConnectWidget
Q_OBJECT {
Q_OBJECT
public: public:
explicit DanbooruConnectWidget(QVector<QUrl> urlList, explicit DanbooruConnectWidget(QVector<QUrl> urlList,
QWidget* parent = 0); QWidget *parent = 0);
~DanbooruConnectWidget(); ~DanbooruConnectWidget();
QString username() const; QString username() const;
QString password() const; QString password() const;
QUrl boardUrl() const; QUrl boardUrl() const;
private: private:
QUrl m_boardUrl; QUrl m_boardUrl;
QString m_username; QString m_username;
QString m_password; QString m_password;
KWallet::Wallet* m_wallet; KWallet::Wallet *m_wallet;
static const QMap<QUrl, QString> boardSalts; static const QMap<QUrl, QString> boardSalts;
Q_SIGNALS: Q_SIGNALS:
void connectionEstablished(DanbooruService* service); void connectionEstablished(DanbooruService *service);
void rejected(); void rejected();
private Q_SLOTS:
private Q_SLOTS: void checkWallet(bool);
void checkWallet(bool); void getWalletData();
void getWalletData(); void toggleLineEdits(int state);
void toggleLineEdits(int state); void emitRejected();
void emitRejected(); void accept();
void accept(); };
};
} // namespace Danbooru } // namespace Danbooru

View file

@ -32,8 +32,8 @@
* @file danbooru.h * @file danbooru.h
* *
**/ **/
namespace Danbooru { namespace Danbooru
{
}; // namespace Danbooru }; // namespace Danbooru

View file

@ -22,10 +22,11 @@
#include "danboorupool.h" #include "danboorupool.h"
namespace Danbooru { namespace Danbooru
{
DanbooruPool::DanbooruPool(const QVariantMap& postData, QObject* parent): DanbooruPool::DanbooruPool(const QVariantMap &postData, QObject *parent):
QObject(parent), m_posts(QList<int>()) QObject(parent), m_posts(QList<int>())
{ {
m_id = postData.value("id").toInt(); m_id = postData.value("id").toInt();
m_name = postData.value("name").toString(); m_name = postData.value("name").toString();
@ -68,13 +69,12 @@ void DanbooruPool::addPosts(QList< int > posts)
m_posts.append(posts); m_posts.append(posts);
} }
void DanbooruPool::addPosts(const QStringList& posts) void DanbooruPool::addPosts(const QStringList &posts)
{ {
for (auto post: posts) { for (auto post : posts) {
m_posts.append(post.toInt()); m_posts.append(post.toInt());
} }
} }
} // namespace Danbooru } // namespace Danbooru

View file

@ -37,74 +37,75 @@
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtXml/QXmlStreamAttributes> #include <QtXml/QXmlStreamAttributes>
namespace Danbooru { namespace Danbooru
{
/** /**
* @brief Class representing a Danbooru pool. * @brief Class representing a Danbooru pool.
* *
* Pools are organized groups of images, often by a common theme, for * Pools are organized groups of images, often by a common theme, for
* example taken from the same artbook. They are identified by unique IDs * example taken from the same artbook. They are identified by unique IDs
* and are represented by a name, a description, and the posts they * and are represented by a name, a description, and the posts they
* contain. * contain.
* *
* @author Luca Beltrame (lbeltrame@kde.org) * @author Luca Beltrame (lbeltrame@kde.org)
* *
* **/ * **/
class DanbooruPool : public QObject class DanbooruPool : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
int m_id; int m_id;
int m_postCount; int m_postCount;
QString m_name; QString m_name;
QString m_description; QString m_description;
QList<int> m_posts; QList<int> m_posts;
public: public:
/** /**
* @brief Construct a Danbooru pool from a QVariantMap. * @brief Construct a Danbooru pool from a QVariantMap.
* *
* This form is the easiest to use and should be used when dealing with * This form is the easiest to use and should be used when dealing with
* responses in JSON format. Unfortunately most Danbooru * responses in JSON format. Unfortunately most Danbooru
* implementations produce broken JSON for some responses. * implementations produce broken JSON for some responses.
* *
* @param postData A QVariantMap from parsed JSON representing the * @param postData A QVariantMap from parsed JSON representing the
* data from a single pool. * data from a single pool.
* *
* *
**/ **/
DanbooruPool(const QVariantMap& postData, QObject* parent = 0); DanbooruPool(const QVariantMap &postData, QObject *parent = 0);
/** /**
* @brief Construct a Danbooru pool from a QVariantMap. * @brief Construct a Danbooru pool from a QVariantMap.
* *
* This form is the easiest to use and should be used when dealing with * This form is the easiest to use and should be used when dealing with
* responses in JSON format. Unfortunately most Danbooru * responses in JSON format. Unfortunately most Danbooru
* implementations produce broken JSON for some responses. * implementations produce broken JSON for some responses.
* *
* @param postData A QXmlStreamAttributes instance holding the * @param postData A QXmlStreamAttributes instance holding the
* attributes for the given pool. * attributes for the given pool.
* *
* *
**/ **/
DanbooruPool(const QXmlStreamAttributes& postData, QObject* parent=0); DanbooruPool(const QXmlStreamAttributes &postData, QObject *parent = 0);
int id() const; int id() const;
int postCount() const; int postCount() const;
QString name() const; QString name() const;
QString description() const; QString description() const;
QList<int> posts() const; QList<int> posts() const;
void addPost(int post); void addPost(int post);
void addPosts(QList<int> posts); void addPosts(QList<int> posts);
void addPosts(const QStringList& posts); void addPosts(const QStringList &posts);
}; };
}; // namespace Danbooru }; // namespace Danbooru
Q_DECLARE_METATYPE(Danbooru::DanbooruPool*) Q_DECLARE_METATYPE(Danbooru::DanbooruPool *)
#endif // DANBOORUPOOL_H #endif // DANBOORUPOOL_H

View file

@ -33,14 +33,13 @@
#include "danboorupost.h" #include "danboorupost.h"
namespace Danbooru namespace Danbooru
{ {
const QMap<QString, DanbooruPost::Rating> DanbooruPost::RATING_MAP = initRatingMap(); const QMap<QString, DanbooruPost::Rating> DanbooruPost::RATING_MAP = initRatingMap();
DanbooruPost::DanbooruPost(QVariantMap postData, QPixmap pixmap, DanbooruPost::DanbooruPost(QVariantMap postData, QPixmap pixmap,
QObject* parent): QObject *parent):
QObject(parent), QObject(parent),
m_pixmap(pixmap) m_pixmap(pixmap)
{ {
@ -57,7 +56,7 @@ DanbooruPost::DanbooruPost(QVariantMap postData, QPixmap pixmap,
} }
DanbooruPost::DanbooruPost(QXmlStreamAttributes& postData, QPixmap pixmap, QObject* parent): DanbooruPost::DanbooruPost(QXmlStreamAttributes &postData, QPixmap pixmap, QObject *parent):
QObject(parent), QObject(parent),
m_pixmap(pixmap) m_pixmap(pixmap)
{ {
@ -73,12 +72,10 @@ DanbooruPost::DanbooruPost(QXmlStreamAttributes& postData, QPixmap pixmap, QObje
m_rating = RATING_MAP.value(postData.value("rating").toString()); m_rating = RATING_MAP.value(postData.value("rating").toString());
} }
DanbooruPost::~DanbooruPost() DanbooruPost::~DanbooruPost()
{ {
} }
const QMap< QString, DanbooruPost::Rating > DanbooruPost::initRatingMap() const QMap< QString, DanbooruPost::Rating > DanbooruPost::initRatingMap()
{ {
@ -91,13 +88,11 @@ const QMap< QString, DanbooruPost::Rating > DanbooruPost::initRatingMap()
} }
bool DanbooruPost::operator==(const Danbooru::DanbooruPost &other)
bool DanbooruPost::operator==(const Danbooru::DanbooruPost& other)
{ {
return m_url == other.m_url && m_id == other.m_id; return m_url == other.m_url && m_id == other.m_id;
} }
void DanbooruPost::setPixmap(const QPixmap &pixmap) void DanbooruPost::setPixmap(const QPixmap &pixmap)
{ {
m_pixmap = pixmap; m_pixmap = pixmap;
@ -155,7 +150,5 @@ Danbooru::DanbooruPost::Rating DanbooruPost::rating() const
return m_rating; return m_rating;
} }
} // namespace Danbooru } // namespace Danbooru

View file

@ -45,28 +45,28 @@
#include "danbooru.h" #include "danbooru.h"
namespace Danbooru
{
namespace Danbooru { /**
* @brief A class representing a Danbooru post.
/** *
* @brief A class representing a Danbooru post. * A Danbooru post is an object that models the posts present in a
* * Danbooru board, that is an image with associated information.
* A Danbooru post is an object that models the posts present in a *
* Danbooru board, that is an image with associated information. * In particular, posts contain information on the id, size and dimensions
* * of the image, its tags, "preview url" (URL to the thumbnail) and
* In particular, posts contain information on the id, size and dimensions * file URL.
* of the image, its tags, "preview url" (URL to the thumbnail) and *
* file URL. * This is used directly by the DanbooruService class.
* *
* This is used directly by the DanbooruService class. * @author Luca Beltrame (lbeltrame@kde.org)
* *
* @author Luca Beltrame (lbeltrame@kde.org) * @see DanbooruService, DanbooruPool
* *
* @see DanbooruService, DanbooruPool **/
* class DanbooruPost : public QObject
**/ {
class DanbooruPost : public QObject
{
Q_OBJECT Q_OBJECT
@ -76,7 +76,7 @@ namespace Danbooru {
Q_PROPERTY(QSet<QString> tags READ tags) Q_PROPERTY(QSet<QString> tags READ tags)
Q_PROPERTY(QUrl thumbnailUrl READ thumbnailUrl) Q_PROPERTY(QUrl thumbnailUrl READ thumbnailUrl)
public: public:
/** /**
* @brief Ratings for a Danbooru item * @brief Ratings for a Danbooru item
@ -88,140 +88,136 @@ namespace Danbooru {
Safe = 1, /**< Safe for the general public **/ Safe = 1, /**< Safe for the general public **/
Questionable = 2, /**< Might contain hints of risqueness of violence **/ Questionable = 2, /**< Might contain hints of risqueness of violence **/
Explicit = 4 /**< Explicit material **/ Explicit = 4 /**< Explicit material **/
};
Q_DECLARE_FLAGS(Ratings, DanbooruPost::Rating)
private:
QPixmap m_pixmap;
// basic features of a post
int m_id;
int m_height;
int m_width;
int m_size;
QUrl m_url;
QUrl m_thumbnailUrl;
QSet<QString> m_tags;
DanbooruPost::Rating m_rating;
static const QMap<QString, Rating> RATING_MAP;
// Private functions
static const QMap< QString, Rating > initRatingMap();
public:
/**
* @brief Construct a Danbooru post from a QVariantMap.
*
* This form is the easiest to use and should be used when dealing with
* responses in JSON format. Unfortunately most Danbooru
* implementations produce broken JSON for some responses.
*
* @param postData A QVariantMap from parsed JSON representing the
* data from a single post.
* @param pixmap A QPixmap pointer to the post thumbnail.
* @param parent A pointer to the parent QObject.
*
**/
explicit DanbooruPost(QVariantMap postData, QPixmap pixmap = QPixmap(),
QObject* parent = 0);
/**
* @brief Construct a Danbooru post from XML attributes
*
* This is an overloaded function which uses XML attributes rather
* than JSON. It should be used in case the JSON responses aren't
* complete or broken (for example pools' posts in most Danbooru
* instances).
*
* @param postData A QXmlStreamAttributes instance holding the
* attributes for the given post.
* @param pixmap A QPixmap pointer to the post thumbnail.
* @param parent A pointer to the parent QObject.
*
**/
explicit DanbooruPost(QXmlStreamAttributes& postData,
QPixmap pixmap = QPixmap(), QObject* parent =0);
bool operator==(const DanbooruPost&);
~DanbooruPost();
// Post attributes
/**
* @return The ID of the post.
**/
int id() const;
/**
* @return The height in pixels of the post's image.
**/
int height() const;
/**
* @return The width in pixels of the post's image.
**/
int width() const;
/**
* @return The size in bytes of the post's image.
**/
int size() const;
/**
* @return The URL to the post's image.
**/
const QUrl fileUrl() const;
/**
* @return The tags associated to the post.
**/
const QSet< QString > tags() const;
/**
* @return The URL to the post's thumbnail.
**/
const QUrl thumbnailUrl() const;
/**
* @return A pointer to the thumbnail's pixmap.
**/
QPixmap pixmap() const;
/**
* @return The current post's rating.
**/
Rating rating() const;
/**
* Set the post's pixmap to a specific QPixmap instance's pointer.
*
**/
void setPixmap(const QPixmap& pixmap);
/**
* @return A string representation of the post.
*
* **/
const QString toString();
}; };
Q_DECLARE_FLAGS(Ratings, DanbooruPost::Rating)
private:
Q_DECLARE_OPERATORS_FOR_FLAGS(DanbooruPost::Ratings) QPixmap m_pixmap;
// basic features of a post
int m_id;
int m_height;
int m_width;
int m_size;
QUrl m_url;
QUrl m_thumbnailUrl;
QSet<QString> m_tags;
DanbooruPost::Rating m_rating;
static const QMap<QString, Rating> RATING_MAP;
// Private functions
static const QMap< QString, Rating > initRatingMap();
public:
/**
* @brief Construct a Danbooru post from a QVariantMap.
*
* This form is the easiest to use and should be used when dealing with
* responses in JSON format. Unfortunately most Danbooru
* implementations produce broken JSON for some responses.
*
* @param postData A QVariantMap from parsed JSON representing the
* data from a single post.
* @param pixmap A QPixmap pointer to the post thumbnail.
* @param parent A pointer to the parent QObject.
*
**/
explicit DanbooruPost(QVariantMap postData, QPixmap pixmap = QPixmap(),
QObject *parent = 0);
/**
* @brief Construct a Danbooru post from XML attributes
*
* This is an overloaded function which uses XML attributes rather
* than JSON. It should be used in case the JSON responses aren't
* complete or broken (for example pools' posts in most Danbooru
* instances).
*
* @param postData A QXmlStreamAttributes instance holding the
* attributes for the given post.
* @param pixmap A QPixmap pointer to the post thumbnail.
* @param parent A pointer to the parent QObject.
*
**/
explicit DanbooruPost(QXmlStreamAttributes &postData,
QPixmap pixmap = QPixmap(), QObject *parent = 0);
bool operator==(const DanbooruPost &);
~DanbooruPost();
// Post attributes
/**
* @return The ID of the post.
**/
int id() const;
/**
* @return The height in pixels of the post's image.
**/
int height() const;
/**
* @return The width in pixels of the post's image.
**/
int width() const;
/**
* @return The size in bytes of the post's image.
**/
int size() const;
/**
* @return The URL to the post's image.
**/
const QUrl fileUrl() const;
/**
* @return The tags associated to the post.
**/
const QSet< QString > tags() const;
/**
* @return The URL to the post's thumbnail.
**/
const QUrl thumbnailUrl() const;
/**
* @return A pointer to the thumbnail's pixmap.
**/
QPixmap pixmap() const;
/**
* @return The current post's rating.
**/
Rating rating() const;
/**
* Set the post's pixmap to a specific QPixmap instance's pointer.
*
**/
void setPixmap(const QPixmap &pixmap);
/**
* @return A string representation of the post.
*
* **/
const QString toString();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DanbooruPost::Ratings)
}; // namespace Danbooru }; // namespace Danbooru
Q_DECLARE_METATYPE(Danbooru::DanbooruPost*) Q_DECLARE_METATYPE(Danbooru::DanbooruPost *)
#endif // DANBOORUPOST_H #endif // DANBOORUPOST_H

View file

@ -53,9 +53,9 @@ const QString DanbooruService::ARTIST_URL = "artist/index.json";
const QString DanbooruService::POOL_DATA_URL = "pool/show.xml"; const QString DanbooruService::POOL_DATA_URL = "pool/show.xml";
const QString DanbooruService::RELATED_TAG_URL = "tag/related.json"; const QString DanbooruService::RELATED_TAG_URL = "tag/related.json";
DanbooruService::DanbooruService(QUrl& boardUrl, QString username, DanbooruService::DanbooruService(QUrl &boardUrl, QString username,
QString password, KImageCache* cache, QString password, KImageCache *cache,
QObject* parent): QObject *parent):
QObject(parent), QObject(parent),
m_url(boardUrl), m_url(boardUrl),
m_username(username), m_username(username),
@ -71,7 +71,6 @@ DanbooruService::~DanbooruService()
} }
void DanbooruService::getPostList(int page, QStringList tags, int limit) void DanbooruService::getPostList(int page, QStringList tags, int limit)
{ {
@ -89,7 +88,7 @@ void DanbooruService::getPostList(int page, QStringList tags, int limit)
// qDebug() << "Final constructed post URL" << danbooruUrl.url(); // qDebug() << "Final constructed post URL" << danbooruUrl.url();
KIO::StoredTransferJob* job = KIO::storedGet(danbooruUrl, KIO::NoReload, KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload,
KIO::HideProgressInfo); KIO::HideProgressInfo);
// This job can use JSON data // This job can use JSON data
@ -97,7 +96,6 @@ void DanbooruService::getPostList(int page, QStringList tags, int limit)
connect(job, &KIO::StoredTransferJob::result, this, &DanbooruService::processPostList); connect(job, &KIO::StoredTransferJob::result, this, &DanbooruService::processPostList);
} }
void DanbooruService::getTagList(int limit, QString name) void DanbooruService::getTagList(int limit, QString name)
@ -114,38 +112,38 @@ void DanbooruService::getTagList(int limit, QString name)
parameters); parameters);
//qDebug() << "Final constructed tag URL" << danbooruUrl.url(); //qDebug() << "Final constructed tag URL" << danbooruUrl.url();
KIO::StoredTransferJob* job = KIO::storedGet(danbooruUrl, KIO::NoReload, KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload,
KIO::HideProgressInfo); KIO::HideProgressInfo);
connect(job, &KIO::StoredTransferJob::result, [this](KJob* job) { connect(job, &KIO::StoredTransferJob::result, [this](KJob * job) {
if (job->error()) {
Q_EMIT(downloadError(job->errorString()));
return;
}
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job);
QByteArray data = jobResult->data();
bool ok;
// Most Danbooru implementations return tags in wrong order when
// using JSON, so we have to fall back to XML
QList<QVariant> tagList = parseDanbooruResult(data, "tag", &ok);
if (!ok) {
Q_EMIT(downloadError(QString("Unable to decode data")));
return;
}
for (auto element : tagList) {
QVariantMap map = element.toMap();
DanbooruTag* tag = new DanbooruTag(map);
Q_EMIT(tagDownloaded(tag));
}
if (job->error()) {
Q_EMIT(downloadError(job->errorString()));
return;
} }
);
StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
QByteArray data = jobResult->data();
bool ok;
// Most Danbooru implementations return tags in wrong order when
// using JSON, so we have to fall back to XML
QList<QVariant> tagList = parseDanbooruResult(data, "tag", &ok);
if (!ok) {
Q_EMIT(downloadError(QString("Unable to decode data")));
return;
}
for (auto element : tagList) {
QVariantMap map = element.toMap();
DanbooruTag *tag = new DanbooruTag(map);
Q_EMIT(tagDownloaded(tag));
}
}
);
} }
void DanbooruService::getPool(int poolId, int page) void DanbooruService::getPool(int poolId, int page)
@ -164,8 +162,7 @@ void DanbooruService::getPool(int poolId, int page)
//qDebug() << "Final constructed pool URL" << danbooruUrl.url(); //qDebug() << "Final constructed pool URL" << danbooruUrl.url();
KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload,
KIO::StoredTransferJob* job = KIO::storedGet(danbooruUrl, KIO::NoReload,
KIO::HideProgressInfo); KIO::HideProgressInfo);
//HACK: Most Danbooru implementations don't provide valid data on //HACK: Most Danbooru implementations don't provide valid data on
@ -194,21 +191,21 @@ void DanbooruService::getPoolList(int page)
//qDebug() << "Final constructed pool list URL" << danbooruUrl.url(); //qDebug() << "Final constructed pool list URL" << danbooruUrl.url();
KIO::StoredTransferJob* job = KIO::storedGet(danbooruUrl, KIO::NoReload, KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload,
KIO::HideProgressInfo); KIO::HideProgressInfo);
// This job can use JSON data // This job can use JSON data
job->setProperty("needsXML", false); job->setProperty("needsXML", false);
// connect(job, &KIO::StoredTransferJob::result, this, &DanbooruService::processPoolList); // connect(job, &KIO::StoredTransferJob::result, this, &DanbooruService::processPoolList);
connect(job, &KIO::StoredTransferJob::result, [this] (KJob* job) { connect(job, &KIO::StoredTransferJob::result, [this](KJob * job) {
if (job->error()) { if (job->error()) {
Q_EMIT(downloadError(job->errorString())); Q_EMIT(downloadError(job->errorString()));
return; return;
} }
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job); StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
QByteArray data = jobResult->data(); QByteArray data = jobResult->data();
bool ok; bool ok;
@ -222,7 +219,7 @@ void DanbooruService::getPoolList(int page)
for (auto element : poolList) { for (auto element : poolList) {
QVariantMap map = element.toMap(); QVariantMap map = element.toMap();
DanbooruPool* pool = new DanbooruPool(map); DanbooruPool *pool = new DanbooruPool(map);
Q_EMIT(poolDownloaded(pool)); Q_EMIT(poolDownloaded(pool));
} }
@ -230,11 +227,11 @@ void DanbooruService::getPoolList(int page)
Q_EMIT(poolDownloadFinished()); Q_EMIT(poolDownloadFinished());
} }
); );
} }
void DanbooruService::getRelatedTags(const QStringList& tags, void DanbooruService::getRelatedTags(const QStringList &tags,
DanbooruTag::TagType tagType) DanbooruTag::TagType tagType)
{ {
@ -265,19 +262,19 @@ void DanbooruService::getRelatedTags(const QStringList& tags,
//qDebug() << "Final constructed related tag URL" << danbooruUrl.url(); //qDebug() << "Final constructed related tag URL" << danbooruUrl.url();
StoredTransferJob* job = KIO::storedGet( StoredTransferJob *job = KIO::storedGet(
danbooruUrl, KIO::NoReload, danbooruUrl, KIO::NoReload,
KIO::HideProgressInfo KIO::HideProgressInfo
); );
connect(job, &StoredTransferJob::result, [this](KJob* job) { connect(job, &StoredTransferJob::result, [this](KJob * job) {
if (job->error()) { if (job->error()) {
Q_EMIT(downloadError(job->errorString())); Q_EMIT(downloadError(job->errorString()));
return; return;
} }
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job); StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
QByteArray data = jobResult->data(); QByteArray data = jobResult->data();
bool ok; bool ok;
@ -314,13 +311,13 @@ void DanbooruService::getRelatedTags(const QStringList& tags,
} }
); );
} }
// Getters / setters // Getters / setters
void DanbooruService::setBlacklist(const QSet< QString >& blacklist) void DanbooruService::setBlacklist(const QSet< QString > &blacklist)
{ {
if (!blacklist.isEmpty()) { if (!blacklist.isEmpty()) {
@ -329,7 +326,6 @@ void DanbooruService::setBlacklist(const QSet< QString >& blacklist)
} }
const QSet< QString > DanbooruService::blacklist() const const QSet< QString > DanbooruService::blacklist() const
{ {
return m_blacklist; return m_blacklist;
@ -384,7 +380,7 @@ const DanbooruPost::Ratings DanbooruService::maximumAllowedRating() const
// Slots // Slots
void DanbooruService::processPostList(KJob* job) void DanbooruService::processPostList(KJob *job)
{ {
// qDebug() << "Got post data OK"; // qDebug() << "Got post data OK";
@ -393,7 +389,7 @@ void DanbooruService::processPostList(KJob* job)
Q_EMIT(downloadError(job->errorString())); Q_EMIT(downloadError(job->errorString()));
} }
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job); StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
if (jobResult == 0) { if (jobResult == 0) {
Q_EMIT(downloadError(QString("Internal error"))); Q_EMIT(downloadError(QString("Internal error")));
@ -427,7 +423,7 @@ void DanbooruService::processPostList(KJob* job)
for (auto element : postList) { for (auto element : postList) {
QVariantMap map = element.toMap(); QVariantMap map = element.toMap();
DanbooruPost* post = new DanbooruPost(map); DanbooruPost *post = new DanbooruPost(map);
// Remove unwanted posts // Remove unwanted posts
@ -453,11 +449,11 @@ void DanbooruService::processPostList(KJob* job)
} else { } else {
StoredTransferJob* pixmapJob = KIO::storedGet(post->thumbnailUrl(), StoredTransferJob *pixmapJob = KIO::storedGet(post->thumbnailUrl(),
KIO::NoReload, KIO::HideProgressInfo KIO::NoReload, KIO::HideProgressInfo
); );
KIO::Scheduler::setJobPriority(static_cast<KIO::SimpleJob*>(job), 1); KIO::Scheduler::setJobPriority(static_cast<KIO::SimpleJob *>(job), 1);
QVariant variant; QVariant variant;
variant.setValue(post); variant.setValue(post);
@ -467,23 +463,26 @@ void DanbooruService::processPostList(KJob* job)
pixmapJob->setProperty("danbooruPost", variant); pixmapJob->setProperty("danbooruPost", variant);
connect(pixmapJob, &StoredTransferJob::result, [post, this, pix] (KJob* job) mutable { connect(pixmapJob, &StoredTransferJob::result, [post, this, pix](KJob * job) mutable {
if (job->error()) { if (job->error())
{
Q_EMIT(downloadError(job->errorString())); Q_EMIT(downloadError(job->errorString()));
return; return;
} }
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job); StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
if (!pix.loadFromData(jobResult->data())) { if (!pix.loadFromData(jobResult->data()))
Q_EMIT(downloadError(QString("Pixmap data could not be loaded"))); {
return; Q_EMIT(downloadError(QString("Pixmap data could not be loaded")));
return;
} }
post->setPixmap(pix); post->setPixmap(pix);
if (m_cache) { if (m_cache)
{
//qDebug() << "Inserting item in cache"; //qDebug() << "Inserting item in cache";
m_cache->insertPixmap(post->thumbnailUrl().url(), pix); m_cache->insertPixmap(post->thumbnailUrl().url(), pix);
} }
@ -493,7 +492,8 @@ void DanbooruService::processPostList(KJob* job)
//qDebug() << "Current posts remaining" << m_currentPosts; //qDebug() << "Current posts remaining" << m_currentPosts;
Q_EMIT(postDownloaded(post)); Q_EMIT(postDownloaded(post));
if (m_postsToFetch == 0) { if (m_postsToFetch == 0)
{
qDebug() << "Post download finished"; qDebug() << "Post download finished";
Q_EMIT(postDownloadFinished()); Q_EMIT(postDownloadFinished());
} }
@ -504,30 +504,26 @@ void DanbooruService::processPostList(KJob* job)
} }
} }
void DanbooruService::processTagList(KJob* job) void DanbooruService::processTagList(KJob *job)
{ {
} }
void DanbooruService::processRelatedTagList(KJob *job)
void DanbooruService::processRelatedTagList(KJob* job)
{ {
} }
void DanbooruService::processPoolList(KJob* job) void DanbooruService::processPoolList(KJob *job)
{ {
if (job->error()) { if (job->error()) {
Q_EMIT(downloadError(job->errorString())); Q_EMIT(downloadError(job->errorString()));
} }
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job); StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
if (jobResult == 0) { if (jobResult == 0) {
Q_EMIT(downloadError(QString("Internal error"))); Q_EMIT(downloadError(QString("Internal error")));
@ -549,7 +545,7 @@ void DanbooruService::processPoolList(KJob* job)
for (auto element : poolList) { for (auto element : poolList) {
QVariantMap map = element.toMap(); QVariantMap map = element.toMap();
DanbooruPool* pool = new DanbooruPool(map); DanbooruPool *pool = new DanbooruPool(map);
Q_EMIT(poolDownloaded(pool)); Q_EMIT(poolDownloaded(pool));
} }
@ -558,12 +554,12 @@ void DanbooruService::processPoolList(KJob* job)
} }
void DanbooruService::downloadAllTags(KJob* job) void DanbooruService::downloadAllTags(KJob *job)
{ {
Q_UNUSED(job) Q_UNUSED(job)
} }
void DanbooruService::downloadThumbnail(KJob* job) void DanbooruService::downloadThumbnail(KJob *job)
{ {
if (job->error()) { if (job->error()) {
@ -572,11 +568,11 @@ void DanbooruService::downloadThumbnail(KJob* job)
QVariant postData = job->property("danbooruPost"); QVariant postData = job->property("danbooruPost");
DanbooruPost* post = postData.value<DanbooruPost*>(); DanbooruPost *post = postData.value<DanbooruPost *>();
QPixmap pix; QPixmap pix;
// QPixmap* pix = new QPixmap(); // QPixmap* pix = new QPixmap();
StoredTransferJob* jobResult = qobject_cast<StoredTransferJob*>(job); StoredTransferJob *jobResult = qobject_cast<StoredTransferJob *>(job);
if (jobResult == 0) { if (jobResult == 0) {
Q_EMIT(downloadError(QString("Internal error"))); Q_EMIT(downloadError(QString("Internal error")));

View file

@ -24,7 +24,6 @@
#ifndef DANBOORUSERVICE_H #ifndef DANBOORUSERVICE_H
#define DANBOORUSERVICE_H #define DANBOORUSERVICE_H
/** /**
* @brief Classes to interact with Danbooru boards * @brief Classes to interact with Danbooru boards
* @file danbooruservice.h * @file danbooruservice.h
@ -56,214 +55,214 @@ class KJob;
using Danbooru::DanbooruTag; using Danbooru::DanbooruTag;
namespace Danbooru { namespace Danbooru
{
class DanbooruPool; class DanbooruPool;
using KIO::StoredTransferJob; using KIO::StoredTransferJob;
/** /**
* @brief A class which provides a wrapper around Danbooru's RESTful API. * @brief A class which provides a wrapper around Danbooru's RESTful API.
* *
* This class provides access to Danbooru-based image boards * This class provides access to Danbooru-based image boards
* by making the appropriate RESTful calls to the service and then * by making the appropriate RESTful calls to the service and then
* retrieving and parsing the reuslts. * retrieving and parsing the reuslts.
* *
* @author Luca Beltrame (lbeltrame@kde.org) * @author Luca Beltrame (lbeltrame@kde.org)
* *
* *
**/ **/
class DanbooruService : public QObject class DanbooruService : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
// URL fragments // URL fragments
static const QString POST_URL; static const QString POST_URL;
static const QString TAG_URL; static const QString TAG_URL;
static const QString POOL_URL; static const QString POOL_URL;
static const QString ARTIST_URL; static const QString ARTIST_URL;
static const QString POOL_DATA_URL; static const QString POOL_DATA_URL;
static const QString RELATED_TAG_URL; static const QString RELATED_TAG_URL;
// member variables // member variables
QUrl m_url; QUrl m_url;
QString m_username; QString m_username;
QString m_password; QString m_password;
QSet<QString> m_blacklist; QSet<QString> m_blacklist;
DanbooruPost::Ratings m_maxRating; DanbooruPost::Ratings m_maxRating;
unsigned int m_postsToFetch; // To tell when to quit unsigned int m_postsToFetch; // To tell when to quit
KImageCache* m_cache; // Pixmap cache KImageCache *m_cache; // Pixmap cache
public: public:
/** /**
* @brief Construct a default instance of the service. * @brief Construct a default instance of the service.
* *
* @param boardUrl The URL to connect to. * @param boardUrl The URL to connect to.
* @param username Username to use (optional) * @param username Username to use (optional)
* @param password Password to use (optional) * @param password Password to use (optional)
* @param cache A pointer to a KImageCache instance to enable caching * @param cache A pointer to a KImageCache instance to enable caching
* of downloaded pixmaps. * of downloaded pixmaps.
* @param parent The parent QObject * @param parent The parent QObject
* *
**/ **/
DanbooruService(QUrl& boardUrl, QString username = QString(), DanbooruService(QUrl &boardUrl, QString username = QString(),
QString password = QString(), KImageCache* cache = 0, QString password = QString(), KImageCache *cache = 0,
QObject* parent = 0); QObject *parent = 0);
/** /**
* Default destructor. * Default destructor.
**/ **/
~DanbooruService(); ~DanbooruService();
/** /**
*@brief Get posts from a the board. *@brief Get posts from a the board.
* *
* @param page The page containing posts (default: 1) * @param page The page containing posts (default: 1)
* @param tags The specific tags to query for (default: all tags) * @param tags The specific tags to query for (default: all tags)
* @param limit The number of posts to fetch (maximum 100) * @param limit The number of posts to fetch (maximum 100)
* *
**/ **/
void getPostList(int page=1, QStringList tags=QStringList(), void getPostList(int page = 1, QStringList tags = QStringList(),
int limit=100); int limit = 100);
/** /**
* @brief Get a list of pools from the board. * @brief Get a list of pools from the board.
* *
* @param page The page to get pools from (default: 1) * @param page The page to get pools from (default: 1)
* *
**/ **/
void getPoolList(int page = 1); void getPoolList(int page = 1);
/** /**
* @brief Get the posts associated with a specific pool ID. * @brief Get the posts associated with a specific pool ID.
* *
* @param poolId The ID of the pool to fetch posts from. * @param poolId The ID of the pool to fetch posts from.
* @param page The page of the pool posts (if > 100) * @param page The page of the pool posts (if > 100)
* *
**/ **/
void getPool(int poolId, int page=1); void getPool(int poolId, int page = 1);
/** /**
* @brief Get a list of tags from the board * @brief Get a list of tags from the board
* *
* If name is supplied, a list of tags including the exact name of the * If name is supplied, a list of tags including the exact name of the
* tag is fetched from Danbooru, otherwise the most recent tags are * tag is fetched from Danbooru, otherwise the most recent tags are
* retrieved. * retrieved.
* *
* The tagDownloaded signal is emitted every time a tag has been * The tagDownloaded signal is emitted every time a tag has been
* retrieved. * retrieved.
* *
* @param limit The number of tags to get. * @param limit The number of tags to get.
* @param name The name of the tag to retrieve, or an empty string * @param name The name of the tag to retrieve, or an empty string
* *
**/ **/
void getTagList(int limit=10, QString name=""); void getTagList(int limit = 10, QString name = "");
/** /**
* @brief Get tags related to a specific, user supplied list. * @brief Get tags related to a specific, user supplied list.
* *
* @param tags The tags to query for related terms * @param tags The tags to query for related terms
* @param tagType The type of tag to query for * @param tagType The type of tag to query for
**/ **/
void getRelatedTags(const QStringList& tags, DanbooruTag::TagType tagType = DanbooruTag::General); void getRelatedTags(const QStringList &tags, DanbooruTag::TagType tagType = DanbooruTag::General);
/** /**
* @return The currently allowed ratings when downloading posts. * @return The currently allowed ratings when downloading posts.
**/ **/
const QStringList allowedRatings() const; const QStringList allowedRatings() const;
/** /**
* @return The maximum allowed rating for a post. * @return The maximum allowed rating for a post.
**/ **/
const DanbooruPost::Ratings maximumAllowedRating() const; const DanbooruPost::Ratings maximumAllowedRating() const;
/** /**
* @return The currently blacklisted tags. * @return The currently blacklisted tags.
**/ **/
const QSet<QString> blacklist() const; const QSet<QString> blacklist() const;
void setBlacklist(const QSet<QString>& blacklist); void setBlacklist(const QSet<QString> &blacklist);
/** /**
* @brief Set the maximum allowed rating for the board. * @brief Set the maximum allowed rating for the board.
* *
* Posts whose rating is higher than the maximuk allowed will not be * Posts whose rating is higher than the maximuk allowed will not be
* downloaded. * downloaded.
* *
**/ **/
void setMaximumAllowedRating(DanbooruPost::Rating rating); void setMaximumAllowedRating(DanbooruPost::Rating rating);
/** /**
* @brief Set the tag blacklist. * @brief Set the tag blacklist.
* *
* If a tag is in the blacklist, posts tagged with it will not be downloaded. * If a tag is in the blacklist, posts tagged with it will not be downloaded.
* *
**/ **/
void setBlackList(QStringList blacklist); void setBlackList(QStringList blacklist);
private Q_SLOTS: private Q_SLOTS:
void processPostList(KJob* job); void processPostList(KJob *job);
void processPoolList(KJob* job); void processPoolList(KJob *job);
void processTagList(KJob* job); void processTagList(KJob *job);
void processRelatedTagList(KJob* job); void processRelatedTagList(KJob *job);
void downloadThumbnail(KJob* job); void downloadThumbnail(KJob *job);
void downloadAllTags(KJob* job); void downloadAllTags(KJob *job);
Q_SIGNALS: Q_SIGNALS:
/** /**
* Emitted when there are no more posts to download. * Emitted when there are no more posts to download.
* *
* Connect to this signal to know when downloading is complete. * Connect to this signal to know when downloading is complete.
* *
**/ **/
void postDownloadFinished(); void postDownloadFinished();
/** /**
* Emitted when there are no more pools to download. * Emitted when there are no more pools to download.
**/ **/
void poolDownloadFinished(); void poolDownloadFinished();
/**
* Emitted when a download error occurred.
*
* The parameter contains the error string.
*
**/
void downloadError(QString error);
/** /**
* Emitted when a download error occurred. * Emitted when a post has been downloaded.
* *
* The parameter contains the error string. * The parameter contains a pointer to the post that has been
* * downloaded.
**/ **/
void downloadError(QString error); void postDownloaded(Danbooru::DanbooruPost *post);
/** /**
* Emitted when a post has been downloaded. * Emitted when a pool has been downloaded.
* *
* The parameter contains a pointer to the post that has been * The parameter contains a pointer to the pool that has been
* downloaded. * downloaded.
**/ **/
void postDownloaded(Danbooru::DanbooruPost* post); void poolDownloaded(Danbooru::DanbooruPool *pool);
/** /**
* Emitted when a pool has been downloaded. * Emitted when a tag has been downloaded.
* *
* The parameter contains a pointer to the pool that has been * The parameter contains a pointer to the tag that has been
* downloaded. * downloaded.
**/ **/
void poolDownloaded(Danbooru::DanbooruPool* pool); void tagDownloaded(Danbooru::DanbooruTag *tag);
/** };
* Emitted when a tag has been downloaded.
*
* The parameter contains a pointer to the tag that has been
* downloaded.
**/
void tagDownloaded(Danbooru::DanbooruTag* tag);
};
}; };
#endif // DANBOORUSERVICE_H #endif // DANBOORUSERVICE_H

View file

@ -25,7 +25,7 @@
namespace Danbooru namespace Danbooru
{ {
DanbooruTag::DanbooruTag(const QVariantMap& postData, QObject* parent): DanbooruTag::DanbooruTag(const QVariantMap &postData, QObject *parent):
QObject(parent) QObject(parent)
{ {
m_id = postData.value("id").toInt(); m_id = postData.value("id").toInt();
@ -82,5 +82,4 @@ Danbooru::DanbooruTag::TagType DanbooruTag::type() const
return m_tagType; return m_tagType;
} }
}; // namespace Danbooru }; // namespace Danbooru

View file

@ -20,7 +20,6 @@
* *
*/ */
#ifndef DANBOORUTAG_H #ifndef DANBOORUTAG_H
#define DANBOORUTAG_H #define DANBOORUTAG_H
@ -29,54 +28,55 @@
#include "danbooru.h" #include "danbooru.h"
namespace Danbooru { namespace Danbooru
{
class DanbooruTag : public QObject class DanbooruTag : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
/** /**
* @brief Types of tags * @brief Types of tags
* *
* A Danbooru tag is not simply a string, but carries some (limited) * A Danbooru tag is not simply a string, but carries some (limited)
* semantic information. In particular, tags are organized in what they * semantic information. In particular, tags are organized in what they
* refer to, either something related to the image itself, or to the * refer to, either something related to the image itself, or to the
* artist that drew it, or the copyrights associated to the image, or even * artist that drew it, or the copyrights associated to the image, or even
* the characters that are represented in it. * the characters that are represented in it.
* *
**/ **/
enum TagType { enum TagType {
General = 1, /**< Generic tags **/ General = 1, /**< Generic tags **/
Artist = 2, /**< Tags related to artists **/ Artist = 2, /**< Tags related to artists **/
Copyright = 4, /**<Tags related to copyrights **/ Copyright = 4, /**<Tags related to copyrights **/
Character= 8, /**<Tags related to characters **/ Character = 8, /**<Tags related to characters **/
Unknown = 16 /**< Unknown tags **/ Unknown = 16 /**< Unknown tags **/
}; };
private: private:
int m_id; int m_id;
int m_count; int m_count;
QString m_name; QString m_name;
bool m_ambiguous; bool m_ambiguous;
TagType m_tagType; TagType m_tagType;
public: public:
DanbooruTag(const QVariantMap& postData, QObject* parent=0); DanbooruTag(const QVariantMap &postData, QObject *parent = 0);
int id() const; int id() const;
int count() const; int count() const;
const QString name() const; const QString name() const;
bool ambiguous() const; bool ambiguous() const;
TagType type() const; TagType type() const;
}; };
Q_DECLARE_FLAGS(TagTypes, DanbooruTag::TagType) Q_DECLARE_FLAGS(TagTypes, DanbooruTag::TagType)
Q_DECLARE_OPERATORS_FOR_FLAGS(TagTypes) Q_DECLARE_OPERATORS_FOR_FLAGS(TagTypes)
}; // namespace Danbooru }; // namespace Danbooru
Q_DECLARE_METATYPE(Danbooru::DanbooruTag*) Q_DECLARE_METATYPE(Danbooru::DanbooruTag *)
#endif // DANBOORUTAG_H #endif // DANBOORUTAG_H

View file

@ -34,156 +34,157 @@
#include <QDebug> #include <QDebug>
namespace Danbooru { namespace Danbooru
{
QUrl requestUrl(QUrl& url, const QString& path, QUrl requestUrl(QUrl &url, const QString &path,
const QString& username, const QString& password, const QString &username, const QString &password,
const dictMap& parameters, const QStringList& tags) const dictMap &parameters, const QStringList &tags)
{ {
QUrl danbooruUrl = QUrl(url); QUrl danbooruUrl = QUrl(url);
danbooruUrl = danbooruUrl.adjusted(QUrl::StripTrailingSlash); danbooruUrl = danbooruUrl.adjusted(QUrl::StripTrailingSlash);
danbooruUrl.setPath(danbooruUrl.path() + '/' + path); danbooruUrl.setPath(danbooruUrl.path() + '/' + path);
// If we have parameters, add them // If we have parameters, add them
if (!parameters.isEmpty()) { if (!parameters.isEmpty()) {
for (auto key: parameters.keys()) {
danbooruUrl.addQueryItem(key, parameters.value(key));
}
for (auto key : parameters.keys()) {
danbooruUrl.addQueryItem(key, parameters.value(key));
} }
// Now, let's add tags should we have them
if (!tags.isEmpty()) {
QByteArray encoded_tags = QUrl::toPercentEncoding(tags.join(" "));
danbooruUrl.addEncodedQueryItem("tags", encoded_tags);
}
if (!username.isEmpty() && !password.isEmpty()) {
danbooruUrl.setUserName(username);
danbooruUrl.setPassword(password);
}
return danbooruUrl;
} }
QUrl requestUrl(QUrl& url, const QString& path, const QString& username, // Now, let's add tags should we have them
const QString& password, const dictMap& parameters)
{
QUrl danbooruUrl = QUrl(url); if (!tags.isEmpty()) {
danbooruUrl = danbooruUrl.adjusted(QUrl::StripTrailingSlash); QByteArray encoded_tags = QUrl::toPercentEncoding(tags.join(" "));
danbooruUrl.setPath(danbooruUrl.path() + '/' + path); danbooruUrl.addEncodedQueryItem("tags", encoded_tags);
// If we have parameters, add them
if (!parameters.isEmpty()) {
for (auto key: parameters.keys()) {
danbooruUrl.addQueryItem(key, parameters.value(key));
}
}
if (!username.isEmpty() && !password.isEmpty()) {
danbooruUrl.setUserName(username);
danbooruUrl.setPassword(password);
}
return danbooruUrl;
} }
QUrl requestUrl(QUrl& url, const QString& path, const QString& username, if (!username.isEmpty() && !password.isEmpty()) {
const QString& password) danbooruUrl.setUserName(username);
{ danbooruUrl.setPassword(password);
QUrl danbooruUrl = QUrl(url);
danbooruUrl = danbooruUrl.adjusted(QUrl::StripTrailingSlash);
danbooruUrl.setPath(danbooruUrl.path() + '/' + path);
if (!username.isEmpty() && !password.isEmpty()) {
danbooruUrl.setUserName(username);
danbooruUrl.setPassword(password);
}
return danbooruUrl;
} }
QList< QVariant > parseDanbooruResult(QByteArray data, QString elementName, return danbooruUrl;
bool* result) }
{
QXmlStreamReader reader; QUrl requestUrl(QUrl &url, const QString &path, const QString &username,
reader.addData(data); const QString &password, const dictMap &parameters)
{
QList<QVariant> postData; QUrl danbooruUrl = QUrl(url);
danbooruUrl = danbooruUrl.adjusted(QUrl::StripTrailingSlash);
danbooruUrl.setPath(danbooruUrl.path() + '/' + path);
while(!reader.atEnd() && !reader.hasError()) { // If we have parameters, add them
QXmlStreamReader::TokenType token = reader.readNext(); if (!parameters.isEmpty()) {
if (token == QXmlStreamReader::StartDocument) { for (auto key : parameters.keys()) {
continue; danbooruUrl.addQueryItem(key, parameters.value(key));
} }
if(token == QXmlStreamReader::StartElement && }
reader.name() == elementName) {
QVariantMap values; if (!username.isEmpty() && !password.isEmpty()) {
danbooruUrl.setUserName(username);
danbooruUrl.setPassword(password);
}
QXmlStreamAttributes attributes = reader.attributes(); return danbooruUrl;
}
QUrl requestUrl(QUrl &url, const QString &path, const QString &username,
const QString &password)
{
QUrl danbooruUrl = QUrl(url);
danbooruUrl = danbooruUrl.adjusted(QUrl::StripTrailingSlash);
danbooruUrl.setPath(danbooruUrl.path() + '/' + path);
if (!username.isEmpty() && !password.isEmpty()) {
danbooruUrl.setUserName(username);
danbooruUrl.setPassword(password);
}
return danbooruUrl;
}
QList< QVariant > parseDanbooruResult(QByteArray data, QString elementName,
bool *result)
{
QXmlStreamReader reader;
reader.addData(data);
QList<QVariant> postData;
while (!reader.atEnd() && !reader.hasError()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token == QXmlStreamReader::StartDocument) {
continue;
}
if (token == QXmlStreamReader::StartElement &&
reader.name() == elementName) {
QVariantMap values;
QXmlStreamAttributes attributes = reader.attributes();
// qDebug() << attributes; // qDebug() << attributes;
for (auto attribute: attributes) { for (auto attribute : attributes) {
values.insert(attribute.name().toString(), values.insert(attribute.name().toString(),
attribute.value().toString()); attribute.value().toString());
}
if (values.isEmpty()) {
*result = false;
qWarning() << "No results found when parsing XML";
return QList<QVariant>();
}
QVariant converted = QVariant(values);
postData.append(converted);
} }
if (values.isEmpty()) {
*result = false;
qWarning() << "No results found when parsing XML";
return QList<QVariant>();
}
QVariant converted = QVariant(values);
postData.append(converted);
} }
*result = true; }
return postData; *result = true;
return postData;
}
QVariant parseDanbooruResult(QByteArray data, bool *result)
{
QJsonDocument parsed = QJsonDocument::fromJson(data);
if (parsed.isNull()) {
return QList<QVariant>();
} }
QVariant parseDanbooruResult(QByteArray data, bool* result) QVariant postData = parsed.toVariant();
{
QJsonDocument parsed = QJsonDocument::fromJson(data); *result = true;
if (parsed.isNull()) { return postData;
return QList<QVariant>(); }
}
QVariant postData = parsed.toVariant(); bool isPostBlacklisted(DanbooruPost *post, QSet<QString> blacklist, DanbooruPost::Ratings maxRating)
{
*result = true;
return postData;
}
bool isPostBlacklisted(DanbooruPost *post, QSet<QString> blacklist, DanbooruPost::Ratings maxRating ) {
if (post->rating() > maxRating) { if (post->rating() > maxRating) {
return true; return true;
} }
for (auto tag: post->tags()) { for (auto tag : post->tags()) {
if (blacklist.contains(tag)) { if (blacklist.contains(tag)) {
return true; return true;
} }
} }

View file

@ -39,90 +39,88 @@
* *
**/ **/
namespace Danbooru { namespace Danbooru
{
typedef QMap<QString,QString> dictMap; typedef QMap<QString, QString> dictMap;
/** @brief Generate a request URL for a Danbooru board. /** @brief Generate a request URL for a Danbooru board.
* *
* Given an URL and an API path, this function builds a * Given an URL and an API path, this function builds a
* proper URL which is used for the specific API operation. * proper URL which is used for the specific API operation.
* The processing follows the "normal" way of encoding URLs. * The processing follows the "normal" way of encoding URLs.
* *
* @param url The board URL. * @param url The board URL.
* @param path The API path of the call to use * @param path The API path of the call to use
* @param username The username to supply (optional) * @param username The username to supply (optional)
* @param password The password to use (optional) * @param password The password to use (optional)
* @param parameters A map of key,values representing the parameters * @param parameters A map of key,values representing the parameters
* to use. * to use.
* @param tags The tags to supply (optional). * @param tags The tags to supply (optional).
* *
* @return A constructed URL to be used for a Danbooru API call. * @return A constructed URL to be used for a Danbooru API call.
* @author Luca Beltrame (lbeltrame@kde.org) * @author Luca Beltrame (lbeltrame@kde.org)
* *
* *
**/ **/
QUrl requestUrl(QUrl& url, const QString& path, const QString& username, QUrl requestUrl(QUrl &url, const QString &path, const QString &username,
const QString& password, const dictMap& parameters, const QString &password, const dictMap &parameters,
const QStringList& tags); const QStringList &tags);
/** @brief Generate a request URL for a Danbooru board.
*
* This is an overloaded function provided for convenience.
*
*
* @param url The board URL.
* @param path The API path of the call to use
* @param username The username to supply (optional)
* @param password The password to use (optional)
* @param parameters A map of key,values representing the parameters
* to use.
*
* @return A constructed URL to be used for a Danbooru API call.
* @author Luca Beltrame (lbeltrame@kde.org)
*
*
**/
QUrl requestUrl(QUrl &url, const QString &path, const QString &username,
const QString &password, const dictMap &parameters);
/** @brief Generate a request URL for a Danbooru board. /** @brief Generate a request URL for a Danbooru board.
* *
* This is an overloaded function provided for convenience. * This is an overloaded function provided for convenience.
* *
* * @param url The board URL.
* @param url The board URL. * @param path The API path of the call to use
* @param path The API path of the call to use * @param username The username to supply (optional)
* @param username The username to supply (optional) * @param password The password to use (optional)
* @param password The password to use (optional) *
* @param parameters A map of key,values representing the parameters * @return A constructed URL to be used for a Danbooru API call.
* to use. * @author Luca Beltrame (lbeltrame@kde.org)
* *
* @return A constructed URL to be used for a Danbooru API call. *
* @author Luca Beltrame (lbeltrame@kde.org) **/
* QUrl requestUrl(QUrl &url, const QString &path, const QString &username,
* const QString &password);
**/
QUrl requestUrl(QUrl& url, const QString& path, const QString& username,
const QString& password, const dictMap& parameters);
QList<QVariant> parseDanbooruResult(QByteArray data, QString xlmElement,
bool *result);
QVariant parseDanbooruResult(QByteArray data, bool *result);
/** @brief Generate a request URL for a Danbooru board. /**
* * @brief Check if a post can be allowed.
* This is an overloaded function provided for convenience. *
* * This convenience function checks if a DanbooruPost is not allowed, either because it
* @param url The board URL. * contains blacklisted tags, or because it has a higher rating than allowed.
* @param path The API path of the call to use *
* @param username The username to supply (optional) * @param post A DanbooruPost pointer.
* @param password The password to use (optional) * @param blacklist A QSet containing unwanted tag names as QStrings.
* * @param maxRating The maximum allowed rating expressed as a DanbooruPost::Ratings flag.
* @return A constructed URL to be used for a Danbooru API call. * @return true if the post is unwanted, false otherwise.
* @author Luca Beltrame (lbeltrame@kde.org) * @author Luca Beltrame (lbeltrame@kde.org)
* */
* bool isPostBlacklisted(DanbooruPost *post, QSet<QString> blacklist, DanbooruPost::Ratings maxRating);
**/
QUrl requestUrl(QUrl& url, const QString& path, const QString& username,
const QString& password);
QList<QVariant> parseDanbooruResult(QByteArray data, QString xlmElement,
bool* result);
QVariant parseDanbooruResult(QByteArray data, bool* result);
/**
* @brief Check if a post can be allowed.
*
* This convenience function checks if a DanbooruPost is not allowed, either because it
* contains blacklisted tags, or because it has a higher rating than allowed.
*
* @param post A DanbooruPost pointer.
* @param blacklist A QSet containing unwanted tag names as QStrings.
* @param maxRating The maximum allowed rating expressed as a DanbooruPost::Ratings flag.
* @return true if the post is unwanted, false otherwise.
* @author Luca Beltrame (lbeltrame@kde.org)
*/
bool isPostBlacklisted(DanbooruPost *post, QSet<QString> blacklist, DanbooruPost::Ratings maxRating );
} }
#endif // UTILS_H #endif // UTILS_H

View file

@ -36,8 +36,8 @@ static const char version[] = "%{VERSION}";
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
K4AboutData about("danbooru_client", 0, ki18n("danbooru_client"), version, ki18n(description), K4AboutData about("danbooru_client", 0, ki18n("danbooru_client"), version, ki18n(description),
K4AboutData::License_GPL, ki18n("(C) %{CURRENT_YEAR} %{AUTHOR}"), KLocalizedString(), 0, "%{EMAIL}"); K4AboutData::License_GPL, ki18n("(C) %{CURRENT_YEAR} %{AUTHOR}"), KLocalizedString(), 0, "%{EMAIL}");
about.addAuthor( ki18n("%{AUTHOR}"), KLocalizedString(), "%{EMAIL}" ); about.addAuthor(ki18n("%{AUTHOR}"), KLocalizedString(), "%{EMAIL}");
QApplication app(argc, argv); QApplication app(argc, argv);
QCommandLineParser parser; QCommandLineParser parser;
K4AboutData::setApplicationData(aboutData); K4AboutData::setApplicationData(aboutData);
@ -48,28 +48,21 @@ int main(int argc, char **argv)
parser.process(app); parser.process(app);
aboutData.processCommandLine(&parser); aboutData.processCommandLine(&parser);
parser.addOption(QCommandLineOption(QStringList() << QLatin1String("+[URL]"), i18n( "Document to open" ))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("+[URL]"), i18n("Document to open")));
danbooru_client *widget = new danbooru_client; danbooru_client *widget = new danbooru_client;
// see if we are starting with session management // see if we are starting with session management
if (app.isSessionRestored()) if (app.isSessionRestored()) {
{
RESTORE(danbooru_client); RESTORE(danbooru_client);
} } else {
else
{
// no session.. just start up normally // no session.. just start up normally
if (parser.positionalArguments().count() == 0) if (parser.positionalArguments().count() == 0) {
{
//danbooru_client *widget = new danbooru_client; //danbooru_client *widget = new danbooru_client;
widget->show(); widget->show();
} } else {
else
{
int i = 0; int i = 0;
for (; i < parser.positionalArguments().count(); i++) for (; i < parser.positionalArguments().count(); i++) {
{
//danbooru_client *widget = new danbooru_client; //danbooru_client *widget = new danbooru_client;
widget->show(); widget->show();
} }

View file

@ -30,49 +30,47 @@
#include <KLocale> #include <KLocale>
namespace Danbooru { namespace Danbooru
{
DanbooruMainWindow::DanbooruMainWindow() DanbooruMainWindow::DanbooruMainWindow()
: KXmlGuiWindow(), : KXmlGuiWindow(),
m_view(new DanbooruClientView(this)), m_view(new DanbooruClientView(this)),
m_service(0), m_service(0),
m_model(new(DanbooruPostModel(this))) m_model(new(DanbooruPostModel(this)))
{ {
// tell the KXmlGuiWindow that this is indeed the main widget // tell the KXmlGuiWindow that this is indeed the main widget
setCentralWidget(m_view); setCentralWidget(m_view);
// then, setup our actions // then, setup our actions
setupActions(); setupActions();
// add a status bar // add a status bar
statusBar()->show(); statusBar()->show();
// a call to KXmlGuiWindow::setupGUI() populates the GUI // a call to KXmlGuiWindow::setupGUI() populates the GUI
// with actions, using KXMLGUI. // with actions, using KXMLGUI.
// It also applies the saved mainwindow settings, if any, and ask the // It also applies the saved mainwindow settings, if any, and ask the
// mainwindow to automatically save settings if changed: window size, // mainwindow to automatically save settings if changed: window size,
// toolbar position, icon size, etc. // toolbar position, icon size, etc.
setupGUI(); setupGUI();
}
} DanbooruMainWindow::~DanbooruMainWindow()
{
}
DanbooruMainWindow::~DanbooruMainWindow() void DanbooruMainWindow::setupActions()
{ {
}
void DanbooruMainWindow::setupActions() QAction *connectAction = new QAction(
{
QAction * connectAction = new QAction(
QIcon::fromTheme(QLatin1String("document-open-remote")), QIcon::fromTheme(QLatin1String("document-open-remote")),
i18n("Connect..."), i18n("Connect..."),
this); this);
QAction * fetchAction = new QAction(QIcon::fromTheme(QLatin1String("download")), QAction *fetchAction = new QAction(QIcon::fromTheme(QLatin1String("download")),
i18n("Download"), this); i18n("Download"), this);
connectAction->setShortcut(KStandardShortcut::open()); connectAction->setShortcut(KStandardShortcut::open());
fetchAction->setShortcut(KStandardShortcut::find()); fetchAction->setShortcut(KStandardShortcut::find());
@ -86,29 +84,28 @@ namespace Danbooru {
connect(connectAction, &QAction::triggered, this, &DanbooruMainWindow::connectToBoard); connect(connectAction, &QAction::triggered, this, &DanbooruMainWindow::connectToBoard);
connect(fetch, SIGNAL(triggered(bool)), this, SLOT(downloadPosts())); connect(fetch, SIGNAL(triggered(bool)), this, SLOT(downloadPosts()));
}
void DanbooruMainWindow::connectToBoard()
{
if (!m_view) {
return;
} }
void DanbooruMainWindow::connectToBoard() }
{
if (!m_view) {
return;
}
void DanbooruMainWindow::downloadPosts()
{
if (!m_service) {
return;
} }
}
void DanbooruMainWindow::downloadPosts() void DanbooruMainWindow::optionsPreferences()
{ {
if (!m_service) {
return;
}
}
void DanbooruMainWindow::optionsPreferences()
{
}
}
} // namespace Danbooru } // namespace Danbooru

View file

@ -23,55 +23,54 @@
#ifndef DANBOORU_CLIENT_H #ifndef DANBOORU_CLIENT_H
#define DANBOORU_CLIENT_H #define DANBOORU_CLIENT_H
#include <KXmlGuiWindow> #include <KXmlGuiWindow>
namespace Danbooru { namespace Danbooru
{
class DanbooruClientView; class DanbooruClientView;
class DanbooruService; class DanbooruService;
class DanbooruPostModel; class DanbooruPostModel;
class DanbooruConnectWidget; class DanbooruConnectWidget;
/**
* This class serves as the main window for danbooru_client. It handles the
* menus, toolbars and status bars.
*
* @short Main window class
* @author Luca Beltrame <lbeltrame@kde.org>
* @version 0.01
*/
class DanbooruMainWindow : public KXmlGuiWindow
{
Q_OBJECT
public:
/**
* Default Constructor
*/
DanbooruMainWindow();
/** /**
* This class serves as the main window for danbooru_client. It handles the * Default Destructor
* menus, toolbars and status bars.
*
* @short Main window class
* @author Luca Beltrame <lbeltrame@kde.org>
* @version 0.01
*/ */
class DanbooruMainWindow : public KXmlGuiWindow virtual ~DanbooruMainWindow();
{
Q_OBJECT
public:
/**
* Default Constructor
*/
DanbooruMainWindow();
/** private Q_SLOTS:
* Default Destructor void connectToBoard();
*/ void downloadPosts();
virtual ~DanbooruMainWindow(); void optionsPreferences();
private Q_SLOTS: private:
void connectToBoard(); void setupActions();
void downloadPosts(); void setupConnections();
void optionsPreferences();
private: private:
void setupActions(); DanbooruClientView *m_view;
void setupConnections(); DanbooruPostModel *m_model;
DanbooruService *m_service;
DanbooruConnectWidget *m_connectWidget;
private: };
DanbooruClientView *m_view;
DanbooruPostModel* m_model;
DanbooruService* m_service;
DanbooruConnectWidget* m_connectWidget;
};
} // namespace Danbooru } // namespace Danbooru
#endif // _DANBOORU_CLIENT_H_ #endif // _DANBOORU_CLIENT_H_

View file

@ -39,223 +39,221 @@
#include <KIconLoader> #include <KIconLoader>
#include <KFormat> #include <KFormat>
namespace Danbooru
{
namespace Danbooru { const int DanbooruPostDelegate::MARGIN = 5;
const int DanbooruPostDelegate::MARGIN = 5; DanbooruPostDelegate::DanbooruPostDelegate(QListView *itemView): QStyledItemDelegate(itemView),
m_itemView(itemView)
{
DanbooruPostDelegate::DanbooruPostDelegate(QListView* itemView):QStyledItemDelegate(itemView), // Get the sizes for the buttons
m_itemView(itemView)
{
// Get the sizes for the buttons const int iconSize = KIconLoader::global()->currentSize(
KIconLoader::Toolbar
);
const int iconSize = KIconLoader::global()->currentSize( const QSize sz = itemView->style()->sizeFromContents(
KIconLoader::Toolbar QStyle::CT_ToolButton, 0,
); QSize(iconSize, iconSize));
const QSize sz = itemView->style()->sizeFromContents( m_buttonSize = qMax(sz.width(), sz.height());
QStyle::CT_ToolButton, 0,
QSize(iconSize, iconSize));
m_buttonSize = qMax(sz.width(), sz.height()); m_downloadButton = new QPushButton(QIcon::fromTheme("download"),
QString(), itemView);
m_viewButton = new QPushButton(QIcon::fromTheme("view-preview"), QString(),
itemView);
m_downloadButton = new QPushButton(QIcon::fromTheme("download"), m_downloadButton->hide();
QString(), itemView); m_viewButton->hide();
m_viewButton = new QPushButton(QIcon::fromTheme("view-preview"), QString(),
itemView);
m_downloadButton->resize(m_buttonSize, m_buttonSize);
m_viewButton->resize(m_buttonSize, m_buttonSize);
m_downloadButton->setToolTip(i18n("Download image"));
m_viewButton->setToolTip(i18n("View image"));
// Signal-slot connections
connect(m_viewButton, &QPushButton::clicked, this, &DanbooruPostDelegate::viewButtonClicked);
connect(m_downloadButton, &QPushButton::clicked, this, &DanbooruPostDelegate::downloadButtonClicked);
}
void DanbooruPostDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (!index.isValid()) {
return;
}
QStyleOptionViewItemV4 opt(option);
// Pixmap
QStyle *style = QApplication::style();
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0);
painter->setRenderHint(QPainter::Antialiasing);
QPixmap pixmap = index.data(Qt::DecorationRole).value<QPixmap>();
if (pixmap.isNull()) {
return;
}
QRect rect = opt.rect;
QFontMetrics metrics = opt.fontMetrics;
QRect textRect(rect.left() + MARGIN, rect.bottom() - 3 * metrics.height(),
rect.width(), 3 * metrics.height());
// Scaling is unavoidable to keep things in the right dimension
QPixmap scaled;
// Reserve enough space for the pixmap + the 3 lines of text:
// this prevents issues with images that have height > width
// (like in yande.re which keeps a lot of scans)
int maxHeight = rect.height() - 3 * metrics.height() - 2 * MARGIN;
scaled = pixmap.scaled(rect.width() - 2 * MARGIN,
maxHeight,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
QRect pixRect = scaled.rect();
pixRect.moveCenter(rect.center());
// move the pixmap up to accomodate some lines of text
pixRect.moveTo(pixRect.left(),
pixRect.top() - textRect.height() / 2);
pixRect.moveBottom(textRect.top() - MARGIN);
painter->drawPixmap(pixRect, scaled);
painter->save();
// Show buttons on mouseover
if (option.state & QStyle::State_MouseOver) {
// Get the bottom coordinate for the buttons
// TODO: Perhaps add some transition?
m_downloadButton->move(pixRect.topLeft());
m_viewButton->move(pixRect.bottomLeft() - QPoint(
0, m_viewButton->height() - 1.5 * MARGIN));
m_downloadButton->show();
m_viewButton->show();
} else if (!hoveredIndex().isValid()) {
m_downloadButton->hide(); m_downloadButton->hide();
m_viewButton->hide(); m_viewButton->hide();
m_downloadButton->resize(m_buttonSize, m_buttonSize);
m_viewButton->resize(m_buttonSize, m_buttonSize);
m_downloadButton->setToolTip(i18n("Download image"));
m_viewButton->setToolTip(i18n("View image"));
// Signal-slot connections
connect(m_viewButton, &QPushButton::clicked, this, &DanbooruPostDelegate::viewButtonClicked);
connect(m_downloadButton, &QPushButton::clicked, this, &DanbooruPostDelegate::downloadButtonClicked);
} }
void DanbooruPostDelegate::paint(QPainter* painter, painter->restore();
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
if (!index.isValid()) { // Text
return;
}
QStyleOptionViewItemV4 opt(option); DanbooruPost *post = index.data().value<Danbooru::DanbooruPost *>();
// Pixmap painter->save();
QStyle *style = QApplication::style(); int imageHeight = post->height();
int imageWidth = post->width();
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0); KFormat format;
painter->setRenderHint(QPainter::Antialiasing);
QPixmap pixmap = index.data(Qt::DecorationRole).value<QPixmap>(); QString imageText = i18n(
"File size: %1",
format.formatByteSize(post->size()));
if (pixmap.isNull()) { KLocalizedString sizestr = ki18np("1 pixel", "%1 pixels");
return;
}
QRect rect = opt.rect; imageText += "\n";
QFontMetrics metrics = opt.fontMetrics; imageText += i18n("Resolution: %1 x %2",
QRect textRect(rect.left() + MARGIN, rect.bottom() - 3 * metrics.height(), sizestr.subs(imageWidth).toString(),
rect.width(), 3 * metrics.height()); sizestr.subs(imageHeight).toString());
imageText += "\n";
// Scaling is unavoidable to keep things in the right dimension QString ratingString;
QPixmap scaled;
// Reserve enough space for the pixmap + the 3 lines of text:
// this prevents issues with images that have height > width
// (like in yande.re which keeps a lot of scans)
int maxHeight = rect.height() - 3 * metrics.height() - 2 * MARGIN;
scaled = pixmap.scaled(rect.width() - 2 * MARGIN,
maxHeight,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
QRect pixRect = scaled.rect();
pixRect.moveCenter(rect.center());
// move the pixmap up to accomodate some lines of text
pixRect.moveTo(pixRect.left(),
pixRect.top() - textRect.height() / 2);
pixRect.moveBottom(textRect.top() - MARGIN);
painter->drawPixmap(pixRect, scaled);
painter->save();
// Show buttons on mouseover
if (option.state & QStyle::State_MouseOver) {
// Get the bottom coordinate for the buttons
// TODO: Perhaps add some transition?
m_downloadButton->move(pixRect.topLeft());
m_viewButton->move(pixRect.bottomLeft() - QPoint(
0, m_viewButton->height() - 1.5 * MARGIN));
m_downloadButton->show();
m_viewButton->show();
} else if (!hoveredIndex().isValid()) {
m_downloadButton->hide();
m_viewButton->hide();
}
painter->restore();
// Text
DanbooruPost* post = index.data().value<Danbooru::DanbooruPost*>();
painter->save();
int imageHeight = post->height();
int imageWidth = post->width();
KFormat format;
QString imageText = i18n(
"File size: %1",
format.formatByteSize(post->size()));
KLocalizedString sizestr = ki18np("1 pixel", "%1 pixels");
imageText += "\n";
imageText += i18n("Resolution: %1 x %2",
sizestr.subs(imageWidth).toString(),
sizestr.subs(imageHeight).toString());
imageText += "\n";
QString ratingString;
switch (post->rating()) {
case DanbooruPost::Safe:
ratingString = i18n("Safe");
break;
case DanbooruPost::Questionable:
ratingString = i18n("Questionable");
break;
case DanbooruPost::Explicit:
ratingString = i18n("Explicit");
break;
default:
ratingString = i18nc("Unknown post rating", "Unknown");
}
imageText += i18n("Rating: %1", ratingString);
painter->drawText(textRect, imageText);
painter->restore();
switch (post->rating()) {
case DanbooruPost::Safe:
ratingString = i18n("Safe");
break;
case DanbooruPost::Questionable:
ratingString = i18n("Questionable");
break;
case DanbooruPost::Explicit:
ratingString = i18n("Explicit");
break;
default:
ratingString = i18nc("Unknown post rating", "Unknown");
} }
QSize DanbooruPostDelegate::sizeHint(const QStyleOptionViewItem& option, imageText += i18n("Rating: %1", ratingString);
const QModelIndex& index) const
{
Q_UNUSED(option) painter->drawText(textRect, imageText);
painter->restore();
if (!index.isValid()) { }
return QSize();
}
return m_itemView->gridSize(); QSize DanbooruPostDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
Q_UNUSED(option)
if (!index.isValid()) {
return QSize();
} }
QModelIndex DanbooruPostDelegate::hoveredIndex() const return m_itemView->gridSize();
{
const QPoint pos = m_itemView->viewport()->mapFromGlobal(QCursor::pos()); }
return m_itemView->indexAt(pos);
QModelIndex DanbooruPostDelegate::hoveredIndex() const
{
const QPoint pos = m_itemView->viewport()->mapFromGlobal(QCursor::pos());
return m_itemView->indexAt(pos);
}
void DanbooruPostDelegate::downloadButtonClicked()
{
QModelIndex index = hoveredIndex();
if (!index.isValid()) {
return;
} }
void DanbooruPostDelegate::downloadButtonClicked() QVariant data = index.data(Qt::DisplayRole);
{ const DanbooruPost *post = data.value<DanbooruPost *>();
QModelIndex index = hoveredIndex();
if (!index.isValid()) { if (post) {
return; Q_EMIT(postDownloadRequested(post->fileUrl()));
} }
}
QVariant data = index.data(Qt::DisplayRole); void DanbooruPostDelegate::viewButtonClicked()
const DanbooruPost* post = data.value<DanbooruPost*>(); {
if (post) { QModelIndex index = hoveredIndex();
Q_EMIT(postDownloadRequested(post->fileUrl()));
} if (!index.isValid()) {
return;
} }
void DanbooruPostDelegate::viewButtonClicked() QVariant data = index.data(Qt::DisplayRole);
{ const DanbooruPost *post = data.value<DanbooruPost *>();
if (post) {
QModelIndex index = hoveredIndex(); Q_EMIT(postViewRequested(post->fileUrl()));
if (!index.isValid()) {
return;
}
QVariant data = index.data(Qt::DisplayRole);
const DanbooruPost* post = data.value<DanbooruPost*>();
if (post) {
Q_EMIT(postViewRequested(post->fileUrl()));
}
} }
}
} // namespace Danbooru } // namespace Danbooru

View file

@ -37,67 +37,63 @@ class QListView;
class QPainter; class QPainter;
class QPushButton; class QPushButton;
namespace Danbooru
{
namespace Danbooru { /**
* @brief Specific delegate for Danbooru items.
*
*/
/** class DanbooruPost;
* @brief Specific delegate for Danbooru items.
*
*/
class DanbooruPost; class DanbooruPostDelegate : public QStyledItemDelegate
{
class DanbooruPostDelegate : public QStyledItemDelegate
{
Q_OBJECT Q_OBJECT
public: public:
DanbooruPostDelegate(QListView* itemView); DanbooruPostDelegate(QListView *itemView);
void paint(QPainter* painter, const QStyleOptionViewItem& option, void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex& index) const; const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem& option, QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex& index) const; const QModelIndex &index) const;
QModelIndex hoveredIndex() const; QModelIndex hoveredIndex() const;
private: private:
QListView* m_itemView; QListView *m_itemView;
QPushButton* m_downloadButton; QPushButton *m_downloadButton;
QPushButton* m_viewButton; QPushButton *m_viewButton;
int m_buttonSize; int m_buttonSize;
static const int MARGIN; static const int MARGIN;
Q_SIGNALS: Q_SIGNALS:
/** /**
* @brief Emitted when the view button is clicked. * @brief Emitted when the view button is clicked.
* *
* @param postUrl the URL to the full picture. * @param postUrl the URL to the full picture.
* *
*/ */
void postViewRequested(QUrl postUrl); void postViewRequested(QUrl postUrl);
/**
* @brief Emitted when the download button is clicked.
*
* @param postUrl the URL to the full picture.
*
*/
void postDownloadRequested(QUrl postUrl);
/** private Q_SLOTS:
* @brief Emitted when the download button is clicked. void viewButtonClicked();
* void downloadButtonClicked();
* @param postUrl the URL to the full picture.
*
*/
void postDownloadRequested(QUrl postUrl);
};
private Q_SLOTS:
void viewButtonClicked();
void downloadButtonClicked();
};
} // namespace Danbooru } // namespace Danbooru

View file

@ -30,88 +30,90 @@
#include <QDebug> #include <QDebug>
#include <QPixmap> #include <QPixmap>
namespace Danbooru { namespace Danbooru
{
DanbooruPostModel::DanbooruPostModel(QObject* parent): QAbstractListModel(parent) DanbooruPostModel::DanbooruPostModel(QObject *parent): QAbstractListModel(parent)
{ {
}
DanbooruPostModel::~DanbooruPostModel()
{
if (!m_items.isEmpty()) {
qDeleteAll(m_items);
m_items.clear();
} }
}
DanbooruPostModel::~DanbooruPostModel() int DanbooruPostModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent)
return m_items.size();
}
if (!m_items.isEmpty()) { void DanbooruPostModel::addPost(Danbooru::DanbooruPost *post)
qDeleteAll(m_items); {
m_items.clear();
}
}
int DanbooruPostModel::rowCount(const QModelIndex& parent) const beginInsertRows(QModelIndex(), m_items.size(), m_items.size());
{ m_items.append(post);
Q_UNUSED(parent) endInsertRows();
return m_items.size(); }
}
void DanbooruPostModel::addPost(Danbooru::DanbooruPost* post) QVariant DanbooruPostModel::data(const QModelIndex &index, int role) const
{ {
beginInsertRows(QModelIndex(), m_items.size(), m_items.size());
m_items.append(post);
endInsertRows();
}
QVariant DanbooruPostModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
if (index.row() >= m_items.size() || index.row() < 0) {
return QVariant();
}
if (m_items.isEmpty()) {
return QVariant();
}
DanbooruPost* post = m_items.at(index.row());
if (!post) {
return QVariant();
}
if (role == Qt::DisplayRole) {
QVariant variant;
variant.setValue(post);
return variant;
}
if (role == Qt::DecorationRole) {
const QPixmap pixmap = post->pixmap();
return pixmap;
}
if (role == Qt::ToolTipRole) {
return post->fileUrl().fileName();
}
if (!index.isValid()) {
return QVariant(); return QVariant();
} }
void DanbooruPostModel::clear() { if (index.row() >= m_items.size() || index.row() < 0) {
return QVariant();
if (m_items.isEmpty()) {
return;
}
beginRemoveRows(QModelIndex(),0, m_items.size());
qDeleteAll(m_items);
m_items.clear();
endRemoveRows();
reset();
} }
if (m_items.isEmpty()) {
return QVariant();
}
DanbooruPost *post = m_items.at(index.row());
if (!post) {
return QVariant();
}
if (role == Qt::DisplayRole) {
QVariant variant;
variant.setValue(post);
return variant;
}
if (role == Qt::DecorationRole) {
const QPixmap pixmap = post->pixmap();
return pixmap;
}
if (role == Qt::ToolTipRole) {
return post->fileUrl().fileName();
}
return QVariant();
}
void DanbooruPostModel::clear()
{
if (m_items.isEmpty()) {
return;
}
beginRemoveRows(QModelIndex(), 0, m_items.size());
qDeleteAll(m_items);
m_items.clear();
endRemoveRows();
reset();
}
}; };

View file

@ -32,49 +32,49 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QVector> #include <QVector>
namespace Danbooru { namespace Danbooru
{
class DanbooruPost; class DanbooruPost;
/** /**
* @brief A model to represent DanbooruItems * @brief A model to represent DanbooruItems
* *
* Since items from a Danbooru service are sent by the service itself, * Since items from a Danbooru service are sent by the service itself,
* there is no need for sorting or table-like structures: everything is * there is no need for sorting or table-like structures: everything is
* represented as a flat list. * represented as a flat list.
* *
* Items are added through the addPost() slot. * Items are added through the addPost() slot.
* *
*/ */
class DanbooruPostModel : public QAbstractListModel class DanbooruPostModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
public: public:
DanbooruPostModel(QObject* parent=0); DanbooruPostModel(QObject *parent = 0);
~DanbooruPostModel(); ~DanbooruPostModel();
int rowCount(const QModelIndex& parent=QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role) const; QVariant data(const QModelIndex &index, int role) const;
void clear(); void clear();
private: private:
QVector<DanbooruPost*> m_items; QVector<DanbooruPost *> m_items;
public Q_SLOTS: public Q_SLOTS:
/** /**
* @brief Add a new post to the model * @brief Add a new post to the model
* *
* Connect to this slot when you want to add items to the model. * Connect to this slot when you want to add items to the model.
* *
* @param post A pointer to a DanbooruPost. * @param post A pointer to a DanbooruPost.
* *
*/ */
void addPost(Danbooru::DanbooruPost* post); void addPost(Danbooru::DanbooruPost *post);
}; };
}; // namespace Danbooru }; // namespace Danbooru
#endif // DANBOORUPOSTMODEL_H #endif // DANBOORUPOSTMODEL_H