PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/src/tools/customwidgets/socialpanel.cpp

https://github.com/AlekSi/Jabbin
C++ | 473 lines | 351 code | 90 blank | 32 comment | 54 complexity | 337a6cd77606501aeb15152b0cae0444 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1, BSD-3-Clause
  1. /*
  2. * Copyright (C) 2009 Ivan Cukic <ivan.cukic+kde@gmail.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser/Library General Public License version 2,
  6. * or (at your option) any later version, as published by the Free
  7. * Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser/Library General Public License for more details
  13. *
  14. * You should have received a copy of the GNU Lesser/Library General Public
  15. * License along with this program; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. #include "socialpanel.h"
  20. #include "socialpanel_p.h"
  21. #include "generic/customwidgetscommon.h"
  22. #include "psicontact.h"
  23. #include "applicationinfo.h"
  24. #include "contacttooltip.h"
  25. #include "avatars.h"
  26. #include <QDebug>
  27. #include <QDateTime>
  28. #include <QScriptEngine>
  29. #include <QScriptValue>
  30. #include <QScriptValueIterator>
  31. #include <QDesktopServices>
  32. #include <QWebSettings>
  33. #include <QNetworkDiskCache>
  34. #include <QDir>
  35. #include <QToolButton>
  36. #define TIMER_INTERVAL 300000
  37. using XMPP::Jid;
  38. void SocialPanel::Private::processScriptValue(QScriptValue value)
  39. {
  40. name = value.property("feed_user").toString();
  41. if (name.contains("@jabbin.com")) {
  42. name = name.replace(QRegExp("@jabbin[.]com.*$"), "");
  43. }
  44. jid = name + "@jabbin.com";
  45. // name
  46. PsiContact * contact = account->findContact(XMPP::Jid(jid));
  47. if (contact) {
  48. name = contact->name();
  49. name = name.replace("@jabbin.com", QString());
  50. }
  51. // date
  52. QDateTime dateObject
  53. = QDateTime::fromString(
  54. value.property("item_date").toString(),
  55. "yyyy-MM-dd hh:mm:ss"
  56. );
  57. date = dateObject.toString(Qt::DefaultLocaleShortDate);
  58. // avatar
  59. qDebug() << "SocialPanel::Private::processScriptValue:"
  60. << jid;
  61. avatar = account->avatarFactory()->getCachedAvatarFileName(
  62. XMPP::Jid(jid));
  63. }
  64. SocialPanel::Private::Private(SocialPanel * parent)
  65. : q(parent)
  66. {
  67. connect(&httpreader, SIGNAL(finished(const QString &)),
  68. this, SLOT(finishedJsonRead(const QString &)));
  69. account = NULL;
  70. }
  71. void SocialPanel::Private::reload()
  72. {
  73. timer.stop();
  74. if (!account || !account->isConnected()) {
  75. web->setHtml("Account offline");
  76. timer.start(1000, q);
  77. return;
  78. }
  79. web->setHtml("Loading...");
  80. QString user = account->jid().node();
  81. // user = "stefanogrini";
  82. QUrl url(
  83. "http://www.jabbin.com/life/services/" + user + "/friends/" + filter + "/json/p/" + QString::number(currentPage)
  84. );
  85. qDebug() << "SocialPanel::Private::reload: " << url;
  86. httpreader.read(url);
  87. }
  88. void SocialPanel::Private::setFilter(const QString & item)
  89. {
  90. filter = item.toLower();
  91. // if (item == tr("All")) {
  92. // filter = QString();
  93. // } else {
  94. // filter = item + "/";
  95. // }
  96. currentPage = 1;
  97. reload();
  98. }
  99. void SocialPanel::Private::buttonMoodClicked()
  100. {
  101. QDesktopServices::openUrl(QUrl("http://www.jabbin.com/life/#mood_container"));
  102. }
  103. void SocialPanel::Private::buttonLifestreamClicked()
  104. {
  105. QDesktopServices::openUrl(QUrl("http://www.jabbin.com/life/networks"));
  106. }
  107. void SocialPanel::Private::buttonSearchClicked()
  108. {
  109. QDesktopServices::openUrl(QUrl("http://www.jabbin.com/life/search"));
  110. }
  111. void SocialPanel::Private::buttonStatusClicked()
  112. {
  113. QDesktopServices::openUrl(QUrl("http://www.jabbin.com/life/#status_container"));
  114. }
  115. void SocialPanel::Private::linkClicked(const QUrl & url)
  116. {
  117. qDebug() << "SocialPanel::Private::linkClicked" << url << " -- " << url.scheme() << url.authority() << url.path();
  118. if (url.scheme() == "go") {
  119. QString command = url.authority();
  120. if (command == "first") {
  121. currentPage = 1;
  122. } else if (command == "previous") {
  123. currentPage--;
  124. } else if (command == "next") {
  125. currentPage++;
  126. } else if (command == "last") {
  127. currentPage = totalPages;
  128. } else {
  129. currentPage = command.toInt();
  130. }
  131. reload();
  132. } else if (url.scheme() == "action") {
  133. // nothing
  134. } else
  135. QDesktopServices::openUrl(url);
  136. }
  137. void SocialPanel::Private::linkHovered(const QString & urlString)
  138. {
  139. QUrl url(urlString);
  140. qDebug() << "SocialPanel::Private::linkHovered" << url << " -- " << url.scheme() << url.authority() << url.path();
  141. if (url.scheme() == "action") {
  142. QString command = url.authority();
  143. if (command == "usertooltip") {
  144. QRect windowRect = QRect(web->window()->mapToGlobal(web->window()->rect().topLeft()),
  145. web->window()->mapToGlobal(web->window()->rect().bottomRight()));
  146. QRect globalRect = QRect(web->mapToGlobal(web->rect().topLeft()),
  147. web->mapToGlobal(web->rect().bottomRight()));
  148. globalRect.setRight(windowRect.right());
  149. PsiContact * contact = account->findContact(XMPP::Jid(url.path().replace("/", "")));
  150. globalRect.setTop(QCursor::pos().y());
  151. globalRect.setHeight(10);
  152. ContactTooltip::instance()->showContact(contact, globalRect);
  153. }
  154. }
  155. }
  156. void SocialPanel::Private::finishedJsonRead(const QString & data)
  157. {
  158. QScriptEngine engine;
  159. qDebug() << "################################# finishedJsonRead";
  160. // QScriptValue value = engine.evaluate(CustomWidgets::Common::readFile("/tmp/json"));
  161. QScriptValue value = engine.evaluate(data);
  162. QString html = CustomWidgets::Common::readFile(
  163. ":/customwidgets/data/social_template.html");
  164. QStringList items = html.split(QRegExp("<!-- ITEM:[^ ]* -->"));
  165. html = items[0];
  166. QString itemPattern = items[1];
  167. QScriptValueIterator it(value.property("data"));
  168. QString pager = "";
  169. if (!value.property("data").isValid()) {
  170. QString item = itemPattern;
  171. html += item
  172. .replace("$NAME", "")
  173. .replace("$TIME", "")
  174. .replace("$TITLE", "")
  175. .replace("$CONTENT", tr("Corrupt data retrieved from the server"))
  176. .replace("$AVATAR", "")
  177. .replace("$JID", "")
  178. .replace("$LINK", "http://www.jabbin.com")
  179. .replace("$SERVICE", "http://www.jabbin.com/life/images/icons/error.png")
  180. .replace("$THUMBNAILS", "")
  181. ;
  182. } else if (!it.hasNext()) {
  183. QString item = itemPattern;
  184. html += item
  185. .replace("$NAME", "")
  186. .replace("$TIME", "")
  187. .replace("$TITLE", "")
  188. .replace("$CONTENT", tr("No items in your friend's lifestreams at the moment"))
  189. .replace("$AVATAR", "")
  190. .replace("$JID", "")
  191. .replace("$LINK", "http://www.jabbin.com")
  192. .replace("$SERVICE", "http://www.jabbin.com/life/images/icons/error.png")
  193. .replace("$THUMBNAILS", "")
  194. ;
  195. } else {
  196. QScriptValue meta = value.property("meta");
  197. int total_records = meta.property("total_records").toInt32();
  198. int items_per_page = meta.property("items_per_page").toInt32();
  199. int current_page = meta.property("current_page").toInt32();
  200. totalPages = total_records / items_per_page;
  201. while (totalPages * items_per_page < total_records) {
  202. totalPages++;
  203. }
  204. if (current_page > 1) {
  205. pager += "<a href=\"go://first\">&lt;&lt;</a>";
  206. pager += "<a href=\"go://previous\">&lt;</a>";
  207. }
  208. int page = current_page - 2;
  209. if (page < 1) { page = 1; }
  210. if (page > 1) { pager += "..."; }
  211. for (int i = 1; i <= 5; i++) {
  212. if (page == current_page) {
  213. pager += "<span>" + QString::number(page) + "</span>";
  214. } else {
  215. pager += "<a href=\"go://" + QString::number(page) + "\">" +
  216. QString::number(page) + "</a>";
  217. }
  218. page++;
  219. if (page > totalPages) {
  220. break;
  221. }
  222. }
  223. page--;
  224. if (page < totalPages) { pager += "..."; }
  225. if (current_page < totalPages) {
  226. pager += "<a href=\"go://next\">&gt;</a>";
  227. pager += "<a href=\"go://last\">&gt;&gt;</a>";
  228. }
  229. pager = "<div class=\"pager\">" + pager + "</div>";
  230. }
  231. while (it.hasNext()) {
  232. QString item = itemPattern;
  233. it.next();
  234. QScriptValue itemValue = it.value();
  235. processScriptValue(itemValue);
  236. QString title = itemValue.property("title").toString();
  237. if (title == "null") title = QString();
  238. QString content = itemValue.property("item_name").toString();
  239. if (content == "null" || content.isEmpty()) {
  240. content = itemValue.property("item_content").toString();
  241. }
  242. if (content == "null") content = QString();
  243. if (title.isEmpty()) {
  244. title = content;
  245. }
  246. // if (title.contains(content) || content.contains(title)) {
  247. // title = QString();
  248. //}
  249. QString domain = itemValue.property("feed_domain").toString();
  250. qDebug() << "SocialPanel::finishedJsonRead: Social domain: " << domain;
  251. if (!domain.contains("http://jabber.org/protocol/")) {
  252. domain.replace(QRegExp("[.](com|org|net|it|us)"), "");
  253. domain.replace(".", "");
  254. domain = "http://www.jabbin.com/life/images/icons/" + domain + ".png";
  255. } else {
  256. domain.replace("http://jabber.org/protocol/", "");
  257. domain = "qrc:/customwidgets/data/social/" + domain + ".png";
  258. }
  259. qDebug() << "SocialPanel::finishedJsonRead: Social domain: " << domain;
  260. html += item
  261. .replace("$NAME", name)
  262. .replace("$TIME", date)
  263. .replace("$TITLE", title)
  264. .replace("$CONTENT", content)
  265. .replace("$AVATAR", avatar)
  266. .replace("$JID", jid)
  267. .replace("$LINK", itemValue.property("permalink").toString())
  268. .replace("$SERVICE", domain)
  269. .replace("$THUMBNAILS", itemValue.property("thumb_data").toString())
  270. ;
  271. }
  272. html += items[2];
  273. html = html.replace("$PAGER", pager);
  274. web->setHtml(html);
  275. web->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
  276. timer.start(TIMER_INTERVAL, this);
  277. }
  278. SocialPanel * SocialPanel::m_instance = NULL;
  279. SocialPanel * SocialPanel::instance()
  280. {
  281. return m_instance;
  282. }
  283. void SocialPanel::init(PsiAccount * account)
  284. {
  285. d->currentPage = 1;
  286. QString path = ApplicationInfo::homeDir() + "/webcache/";
  287. QDir().mkpath(path);
  288. QWebSettings::setOfflineStoragePath(path);
  289. QNetworkDiskCache * diskCache = new QNetworkDiskCache(this);
  290. diskCache->setCacheDirectory(path);
  291. QNetworkAccessManager * networkAccessManager = new QNetworkAccessManager();
  292. networkAccessManager->setCache(diskCache);
  293. d->web->page()->setNetworkAccessManager(networkAccessManager);
  294. QWebSettings::setMaximumPagesInCache(100);
  295. d->account = account;
  296. d->timer.start(TIMER_INTERVAL, this);
  297. connect(d->web, SIGNAL(linkClicked(const QUrl &)),
  298. d, SLOT(linkClicked(const QUrl &)));
  299. connect(d->web->page(), SIGNAL(linkHovered(const QString &, const QString &, const QString &)),
  300. d, SLOT(linkHovered(const QString &)));
  301. d->setFilter("All");
  302. d->reload();
  303. }
  304. void SocialPanel::timerEvent(QTimerEvent * event)
  305. {
  306. if (event->timerId() == d->timer.timerId()) {
  307. d->timer.stop();
  308. d->reload();
  309. if (!d->timer.isActive()) {
  310. d->timer.start(TIMER_INTERVAL, this);
  311. }
  312. }
  313. QWidget::timerEvent(event);
  314. }
  315. void SocialPanel::showEvent(QShowEvent * event)
  316. {
  317. QWidget::showEvent(event);
  318. }
  319. SocialPanel::SocialPanel(QWidget * parent)
  320. : QWidget(parent), d(new Private(this))
  321. {
  322. m_instance = this;
  323. d->web = new QWebView(this);
  324. d->layout = new QVBoxLayout(this);
  325. d->layout->setContentsMargins(0, 0, 0, 0);
  326. d->layout->setSpacing(0);
  327. QFrame * topFrame = new QFrame(this);
  328. topFrame->setName("topFrame");
  329. topFrame->setStyleSheet("\
  330. QFrame#topFrame { background: white; border: none; border-bottom: 1px solid silver; }\
  331. QToolButton { border: none; }");
  332. QHBoxLayout * layout = new QHBoxLayout(topFrame);
  333. layout->setSpacing(0);
  334. layout->setContentsMargins(4, 4, 4, 4);
  335. QToolButton * button = new QToolButton(topFrame);
  336. button->setIcon(QIcon(":/customwidgets/data/social/status.png"));
  337. button->setToolTip(tr("Status"));
  338. layout->addWidget(button);
  339. connect(button, SIGNAL(clicked()), d, SLOT(buttonStatusClicked()));
  340. button = new QToolButton(topFrame);
  341. button->setIcon(QIcon(":/customwidgets/data/social/lifestream.png"));
  342. button->setToolTip(tr("Add a new feed"));
  343. layout->addWidget(button);
  344. connect(button, SIGNAL(clicked()), d, SLOT(buttonLifestreamClicked()));
  345. button = new QToolButton(topFrame);
  346. button->setIcon(QIcon(":/customwidgets/data/social/search.png"));
  347. button->setToolTip(tr("Search"));
  348. layout->addWidget(button);
  349. connect(button, SIGNAL(clicked()), d, SLOT(buttonSearchClicked()));
  350. layout->addStretch();
  351. QLabel * label = new QLabel(topFrame);
  352. label->setText(tr("Show:"));
  353. layout->addWidget(label);
  354. layout->addSpacing(10);
  355. QComboBox * combo = new QComboBox(topFrame);
  356. layout->addWidget(combo);
  357. connect(combo, SIGNAL(activated(const QString &)), d, SLOT(setFilter(const QString &)));
  358. QStringList services;
  359. services
  360. << "flickr"
  361. << "twitter"
  362. << "identi.ca"
  363. << "youtube"
  364. << "digg"
  365. << "delicious"
  366. << "last.fm"
  367. << "slideshare";
  368. combo->addItem("All");
  369. combo->insertSeparator(1);
  370. combo->addItem("Mood");
  371. combo->addItem("Status");
  372. combo->addItem("Activity");
  373. combo->insertSeparator(5);
  374. foreach (QString service, services) {
  375. combo->addItem(service);
  376. }
  377. d->layout->addWidget(topFrame);
  378. d->layout->addWidget(d->web);
  379. }
  380. SocialPanel::~SocialPanel()
  381. {
  382. delete d;
  383. }