No longer honours following status in JSON, instead relies solely on following list.
[larjonas-pumpa.git] / src / qasobject.cpp
blobf200ce04a5c4787361a27d833c26365b364f2bf2
1 /*
2 Copyright 2013-2015 Mats Sjöberg
4 This file is part of the Pumpa programme.
6 Pumpa is free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 Pumpa is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pumpa. If not, see <http://www.gnu.org/licenses/>.
20 #include "qasobject.h"
22 #include "qasactor.h"
23 #include "qasobjectlist.h"
24 #include "qasactorlist.h"
25 #include "util.h"
27 #include <QDebug>
28 #include <QList>
29 #include <QtAlgorithms>
30 #include <QRegExp>
32 //------------------------------------------------------------------------------
34 QMap<QString, QASObject*> QASObject::s_objects;
36 void QASObject::clearCache() { deleteMap<QASObject*>(s_objects); }
38 int QASObject::objectsUnconnected() {
39 int noConnections = 0;
40 QMap<int, int> hist;
41 for (QMap<QString, QASObject*>::const_iterator it = s_objects.begin();
42 it != s_objects.end(); ++it) {
43 int n = it.value()->connections();
44 hist[n] = hist.value(n, 0) + 1;
45 if (n == 0)
46 noConnections++;
49 qDebug() << "QASObject connections:";
50 QList<int> keys = hist.keys();
51 qSort(keys);
52 for (int i=0; i<keys.count(); ++i) {
53 const int& k = keys[i];
54 qDebug() << " " << k << hist[k];
57 return noConnections;
60 int QASObject::connections() const {
61 return receivers(SIGNAL(changed()));
64 //------------------------------------------------------------------------------
66 QASLocation::QASLocation(QObject* parent) :
67 QObject(parent),
68 m_latitude(-1.0),
69 m_longitude(-1.0),
70 m_hasPosition(false) {}
72 //------------------------------------------------------------------------------
74 void QASLocation::update(QVariantMap json) {
75 bool ch;
76 QASAbstractObject::updateVar(json, m_displayName, "displayName", ch);
78 if (json.contains("position"))
79 updatePosition(json["position"].toMap());
80 else
81 updatePosition(json);
84 //------------------------------------------------------------------------------
86 void QASLocation::updatePosition(QVariantMap json) {
87 if (json.contains("latitude") && json.contains("longitude")) {
88 m_hasPosition = true;
89 bool ch;
90 QASAbstractObject::updateVar(json, m_longitude, "longitude", ch);
91 QASAbstractObject::updateVar(json, m_latitude, "latitude", ch);
92 } else {
93 m_hasPosition = false;
97 //------------------------------------------------------------------------------
99 QASObject::QASObject(QString id, QObject* parent) :
100 QASAbstractObject(QAS_OBJECT, parent),
101 m_id(id),
102 m_liked(false),
103 m_shared(false),
104 m_inReplyTo(NULL),
105 m_author(NULL),
106 m_replies(NULL),
107 m_likes(NULL),
108 m_shares(NULL),
109 m_postingActivity(NULL)
111 #ifdef DEBUG_QAS
112 qDebug() << "new Object" << m_id;
113 #endif
114 m_location = new QASLocation(this);
117 //------------------------------------------------------------------------------
119 void QASObject::update(QVariantMap json, bool ignoreLike) {
120 #ifdef DEBUG_QAS
121 qDebug() << "updating Object" << m_id;
122 #endif
123 bool ch = false;
124 bool wasDeleted = isDeleted();
126 m_json = json;
128 updateVar(json, m_objectType, "objectType", ch);
129 updateVar(json, m_url, "url", ch);
130 updateVar(json, m_content, "content", ch);
131 if (!ignoreLike)
132 updateVar(json, m_liked, "liked", ch);
133 updateVar(json, m_displayName, "displayName", ch);
134 updateVar(json, m_shared, "pump_io", "shared", ch);
136 if (m_objectType == "image" && json.contains("image")) {
137 updateUrlOrProxy(json["image"].toMap(), m_imageUrl, ch);
139 if (json.contains("fullImage"))
140 updateVar(json["fullImage"].toMap(), m_fullImageUrl, "url", ch);
143 updateVar(json, m_published, "published", ch);
144 updateVar(json, m_updated, "updated", ch);
145 updateVar(json, m_deleted, "deleted", ch);
147 updateVar(json, m_apiLink, "links", "self", "href", ch);
148 updateVar(json, m_proxyUrl, "pump_io", "proxyURL", ch);
149 updateVar(json, m_streamUrl, "stream", "url", ch);
150 updateVar(json, m_streamUrlProxy, "stream", "pump_io", "proxyURL", ch);
152 updateVar(json, m_fileUrl, "fileUrl", ch);
153 updateVar(json, m_mimeType, "mimeType", ch);
155 if (json.contains("location"))
156 m_location->update(json["location"].toMap());
158 if (json.contains("inReplyTo")) {
159 m_inReplyTo = QASObject::getObject(json["inReplyTo"].toMap(), parent(), true);
160 //connectSignals(m_inReplyTo, true, true);
163 if (json.contains("author")) {
164 m_author = QASActor::getActor(json["author"].toMap(), parent());
165 //connectSignals(m_author);
168 if (json.contains("replies")) {
169 QVariantMap repliesMap = json["replies"].toMap();
171 // don't replace a list with an empty one...
172 size_t rs = repliesMap["items"].toList().size();
173 if (!m_replies || rs>0) {
174 m_replies = QASObjectList::getObjectList(repliesMap, parent());
175 m_replies->isReplies(true);
176 // connectSignals(m_replies);
180 if (json.contains("likes")) {
181 m_likes = QASActorList::getActorList(json["likes"].toMap(), parent());
182 connectSignals(m_likes);
185 if (json.contains("shares")) {
186 m_shares = QASActorList::getActorList(json["shares"].toMap(), parent());
187 connectSignals(m_shares);
190 if (isDeleted()) {
191 m_content = "";
192 m_displayName = "";
193 if (!wasDeleted)
194 ch = true;
197 if (ch)
198 emit changed();
201 //------------------------------------------------------------------------------
203 QASObject* QASObject::getObject(QVariantMap json, QObject* parent,
204 bool ignoreLike) {
205 QString id = json["id"].toString();
207 if (id.isEmpty()) // some objects from Mediagoblin seem to be without "id"
208 id = json["url"].toString();
210 if (id.isEmpty()) {
211 qDebug() << "WARNING: null object";
212 qDebug() << debugDumpJson(json, "object");
213 return NULL;
216 if (json["objectType"] == "person")
217 return QASActor::getActor(json, parent);
219 QASObject* obj = s_objects.contains(id) ? s_objects[id] :
220 new QASObject(id, parent);
221 s_objects.insert(id, obj);
223 obj->update(json, ignoreLike);
224 return obj;
227 //------------------------------------------------------------------------------
229 void QASObject::addReply(QASObject* obj) {
230 if (!m_replies) {
231 m_replies = QASObjectList::initObjectList(id() + "/replies", parent());
232 m_replies->isReplies(true);
233 // connectSignals(m_replies);
235 m_replies->addObject(obj);
236 #ifdef DEBUG_QAS
237 qDebug() << "addReply" << obj->id() << "to" << id();
238 #endif
239 emit changed();
242 //------------------------------------------------------------------------------
244 void QASObject::toggleLiked() {
245 m_liked = !m_liked;
246 emit changed();
249 //------------------------------------------------------------------------------
251 size_t QASObject::numLikes() const {
252 return m_likes ? m_likes->size() : 0;
255 //------------------------------------------------------------------------------
257 void QASObject::addLike(QASActor* actor, bool like) {
258 if (!m_likes)
259 return;
260 if (like)
261 m_likes->addActor(actor);
262 else
263 m_likes->removeActor(actor);
266 //------------------------------------------------------------------------------
268 void QASObject::addShare(QASActor* actor) {
269 if (!m_shares)
270 return;
271 m_shares->addActor(actor);
274 //------------------------------------------------------------------------------
276 size_t QASObject::numShares() const {
277 return m_shares ? m_shares->size() : 0;
280 //------------------------------------------------------------------------------
282 size_t QASObject::numReplies() const {
283 return m_replies ? m_replies->size() : 0;
286 //------------------------------------------------------------------------------
288 QString QASObject::apiLink() const {
289 return
290 !m_proxyUrl.isEmpty() ? m_proxyUrl :
291 !m_apiLink.isEmpty() ? m_apiLink :
292 m_id;
295 //------------------------------------------------------------------------------
297 QVariantMap QASObject::toJson() const {
298 QVariantMap obj;
300 obj["id"] = m_id;
302 addVar(obj, m_content, "content");
303 addVar(obj, m_objectType, "objectType");
304 addVar(obj, m_url, "url");
305 addVar(obj, m_displayName, "displayName");
306 // addVar(obj, m_, "");
308 return obj;
311 //------------------------------------------------------------------------------
313 QASActor* QASObject::asActor() {
314 return qobject_cast<QASActor*>(this);
317 //------------------------------------------------------------------------------
319 QString QASObject::deletedText() const {
320 return "<i>[" + QString(tr("Deleted %1")).arg(deletedDate().toString()) +
321 "]</i>";
324 //------------------------------------------------------------------------------
326 QString QASObject::content() const {
327 return isDeleted() ? deletedText() : m_content;
330 //------------------------------------------------------------------------------
332 QString QASObject::excerpt() const {
333 if (isDeleted())
334 return deletedText();
336 QString text = displayName();
337 if (text.isEmpty()) {
338 text = content();
340 if (!text.isEmpty()) {
341 text.replace(QRegExp(HTML_TAG_REGEX), " ");
342 } else {
343 QString t = type();
344 text = (t == "image" ? "an " : "a ") + t;
346 return text.trimmed();