summaryrefslogtreecommitdiff
path: root/board.h
blob: c38bd4861d14253bbd4a26768c4dd8841b6e75f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#ifndef BOARD_H
#define BOARD_H

#include <QtCore/QDateTime>
#include <QtCore/QHash>
#include <QtCore/QPair>
#include <QtCore/QRegExp>
#include <QtCore/QSet>
#include <QtCore/QTimer>
#include <QtCore/QQueue>
#include <QtCore/QUrl>
#include <QtCore/QVariant>
#include <QtSql/QSqlDatabase>

class Action;
class XmlRpcInterface;

class Board : public QObject
{
	Q_OBJECT
	Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
	Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged)
	Q_PROPERTY(int rootForumId READ rootForumId CONSTANT)
	Q_ENUMS(TopicType)

public:
	explicit Board(QObject *parent = 0);
	Board(const QUrl& url, const QString& username, const QString& password, QObject *parent = 0);
    ~Board();

	enum TopicType {
		Normal = 0,
		Sticky = 1,
		Announcement = 2
	};

	static const QLatin1String CURRENT_DB_VERSION;

	bool busy() const;

	void enqueueAction(Action* action);

	QSqlDatabase database();
	XmlRpcInterface *service();

	int rootForumId() const;

	// Configuration table
	Q_INVOKABLE QString getConfig(const QString& key) const;
	void setConfig(const QString& key, const QString &value);

	// Login/logout stuff
	QVariant getLoginInfo(const QString& key) const;
	bool loggedIn() const;
	void login(const QString& username, const QString& password);
	void logout();

	// Other functions that query the database
	int getTopicForumId(int topicId);

	// Posting stuff
	Q_INVOKABLE void newTopic(int forumId, const QString& subject, const QString& text);
	Q_INVOKABLE void replyToTopic(int topicId, const QString& text);

	// BBCode-related helper functions
	QString removeHtml(QString text) const;
	QString removeBbcode(QString text) const;
	QString bbcodeToRichText(QString text) const;
	QString parseSmilies(QString text) const;

	Q_INVOKABLE QString renderHumanDate(const QDateTime& dateTime, bool monthOnly = false);
	Q_INVOKABLE QString renderHumanDateTime(const QDateTime& dateTime);

public slots:
	void cancelAllActions();

	// These functions wrap emitting the signals below
	void notifyConfigChanged(const QString& key = QString());
	void notifyForumsChanged();
	void notifyForumChanged(int forumId);
	void notifyForumTopicsChanged(int forumId, Board::TopicType type, int start, int end);
	void notifyForumTopicChanged(int forumId, int topicId);
	void notifyTopicPostsChanged(int topicId, int start, int end);
	void notifyTopicPostsUnread(int topicId, int position);
	void notifyLogin(const QMap<QString, QVariant>& info);
	void notifyLogout();

	// Functions for marking posts as read
	void markTopicAsRead(int topicId);

signals:
	void busyChanged();
	void loggedInChanged();
	void configChanged(const QString& key);
	void forumsChanged();
	void forumChanged(int forumId);
	void forumTopicsChanged(int forumId, Board::TopicType type, int start, int end);
	void forumTopicChanged(int forumId, int topicId);
	void topicPostsChanged(int topicId, int start, int end);
	void topicPostsUnread(int topicId, int position);

private:
	static QString createSlug(const QUrl& url);
	static QString getDbPathFor(const QString& slug);
	static QString getTempDbPathFor(const QString& slug);
	int dbSize() const;
	bool checkCompatibleDb();
	bool initializeDb();
	bool eraseDb();
	bool cleanDb();
	bool removeFromActionQueue(Action *action);
	void executeActionFromQueue();
	void initializeBbCode();
	void initializeSmilies();
	void fetchConfigIfOutdated();
	void fetchForumsIfOutdated();
	void updateForumReadState(int forumId);

private slots:
	void handleActionFinished(Action *action);
	void handleActionError(Action *action, const QString& message);

private:
	QUrl _url;
	QString _slug;
	QSqlDatabase _db;
	XmlRpcInterface *_iface;
	/** The queue of pending actions. The first one is currently being run. */
	QQueue<Action*> _queue;
	/** Configuration cache */
	mutable QHash<QString, QString> _config;
	/** Login information, which is obviously not persistent. */
	QMap<QString, QVariant> _loginInfo;
	/** Bbcodes list and their HTML replacements for quick-and-dirty parsing. */
	QList< QPair<QRegExp, QString> > _bbcodes;
	/** List of smilies and their replacements. */
	QHash<QString, QString> _smilies;
	/** A regular expression that matches every possibly smilie. */
	QRegExp _smilieRegexp;
};

inline bool Board::busy() const
{
	return !_queue.empty();
}

inline bool Board::loggedIn() const
{
	return !_loginInfo.empty();
}

inline int Board::rootForumId() const
{
	return 0;
}

inline QSqlDatabase Board::database()
{
	return _db;
}

inline XmlRpcInterface * Board::service()
{
	return _iface;
}

#endif // BOARD_H