1 /*
2 This file is part of Choqok, the KDE micro-blogging client
3
4 Copyright (C) 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of
9 the License or (at your option) version 3 or any later version
10 accepted by the membership of KDE e.V. (or its successor approved
11 by the membership of KDE e.V.), which shall act as a proxy
12 defined in Section 14 of version 3 of the license.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see http://www.gnu.org/licenses/
21 */
22 #include "postwidget.h"
23
24 #include <QCloseEvent>
25 #include <QGridLayout>
26 #include <QTimer>
27 #include <QPushButton>
28
29 #include <KLocalizedString>
30 #include <KMessageBox>
31
32 #include "choqokappearancesettings.h"
33 #include "choqokbehaviorsettings.h"
34 #include "choqoktools.h"
35 #include "choqokuiglobal.h"
36 #include "libchoqokdebug.h"
37 #include "mediamanager.h"
38 #include "quickpost.h"
39 #include "timelinewidget.h"
40 #include "textbrowser.h"
41 #include "urlutils.h"
42
43 static const int _15SECS = 15000;
44 static const int _MINUTE = 60000;
45 static const int _HOUR = 60 * _MINUTE;
46
47 using namespace Choqok;
48 using namespace Choqok::UI;
49
50 class PostWidget::Private
51 {
52 public:
Private(Account * account,Choqok::Post * post)53 Private(Account *account, Choqok::Post *post)
54 : mCurrentPost(post), mCurrentAccount(account), dir(QLatin1String("ltr")), timeline(nullptr)
55 {
56 mCurrentPost->owners++;
57
58 if (!mCurrentPost->media.isEmpty()) {
59 imageUrl = mCurrentPost->media;
60 }
61 }
62 QGridLayout *buttonsLayout;
63 QMap<QString, QPushButton *> mUiButtons; //<Object name, Button>
64 Post *mCurrentPost;
65 Account *mCurrentAccount;
66 // bool mRead;
67 QTimer mTimer;
68
69 //BEGIN UI contents:
70 QString mSign;
71 QString mContent;
72 QString mProfileImage;
73 QString mImage;
74 QUrl imageUrl;
75 QString dir;
76 QPixmap originalImage;
77 QString extraContents;
78 //END UI contents;
79
80 QStringList detectedUrls;
81
82 TimelineWidget *timeline;
83
84 static const QLatin1String resourceImageUrl;
85 };
86
87 const QString mImageTemplate(QLatin1String("<div style=\"padding-top:5px;padding-bottom:3px;\"><img width=\"%1\" height=\"%2\" src=\"%3\"/></div>"));
88
89 const QLatin1String PostWidget::Private::resourceImageUrl("img://postImage");
90
91 const QString PostWidget::baseTextTemplate(QLatin1String("<table height=\"100%\" width=\"100%\"><tr><td width=\"48\" style=\"padding-right: 5px;\">%1</td><td dir=\"%4\" style=\"padding-right:3px;\"><p>%2</p></td></tr>%6%5<tr><td></td><td style=\"font-size:small;\" dir=\"ltr\" align=\"right\" valign=\"bottom\">%3</td></tr></table>"));
92
93 const QString PostWidget::baseStyle(QLatin1String("QTextBrowser {border: 1px solid rgb(150,150,150);\
94 border-radius:5px; color:%1; background-color:%2; %3}\
95 QPushButton{border:0px} QPushButton::menu-indicator{image:none;}"));
96
97 const QString PostWidget::hrefTemplate(QLatin1String("<a href='%1' title='%1' target='_blank'>%2</a>"));
98
99 const QRegExp PostWidget::dirRegExp(QLatin1String("(RT|RD)|(@([^\\s\\W]+))|(#([^\\s\\W]+))|(!([^\\s\\W]+))"));
100
101 QString PostWidget::readStyle;
102 QString PostWidget::unreadStyle;
103 QString PostWidget::ownStyle;
104 const QString PostWidget::webIconText(QLatin1String("☛"));
105
PostWidget(Account * account,Choqok::Post * post,QWidget * parent)106 PostWidget::PostWidget(Account *account, Choqok::Post *post, QWidget *parent/* = 0*/)
107 : QWidget(parent), _mainWidget(new TextBrowser(this)), d(new Private(account, post))
108 {
109 setAttribute(Qt::WA_DeleteOnClose);
110 _mainWidget->setFrameShape(QFrame::NoFrame);
111 if (isOwnPost()) {
112 d->mCurrentPost->isRead = true;
113 }
114 d->mTimer.start(_MINUTE);
115 connect(&d->mTimer, &QTimer::timeout, this, &PostWidget::updateUi);
116 connect(_mainWidget, &TextBrowser::clicked, this, &PostWidget::mousePressEvent);
117 connect(_mainWidget, &TextBrowser::anchorClicked, this, &PostWidget::checkAnchor);
118
119 d->timeline = qobject_cast<TimelineWidget *>(parent);
120
121 setHeight();
122 }
123
checkAnchor(const QUrl & url)124 void PostWidget::checkAnchor(const QUrl &url)
125 {
126 if (url.scheme() == QLatin1String("choqok")) {
127 if (url.host() == QLatin1String("showoriginalpost")) {
128 setContent(prepareStatus(currentPost()->content).replace(QLatin1String("<a href"), QLatin1String("<a style=\"text-decoration:none\" href"), Qt::CaseInsensitive));
129 updateUi();
130 }
131 } else {
132 Choqok::openUrl(url);
133 }
134 }
135
~PostWidget()136 PostWidget::~PostWidget()
137 {
138 if (d->mCurrentPost->owners < 2) {
139 delete d->mCurrentPost;
140 } else {
141 d->mCurrentPost->owners--;
142 }
143 delete d;
144 }
145
currentAccount()146 Account *PostWidget::currentAccount()
147 {
148 return d->mCurrentAccount;
149 }
150
generateSign()151 QString PostWidget::generateSign()
152 {
153 QString ss = QStringLiteral("<b>%1 - </b>").arg(getUsernameHyperlink(d->mCurrentPost->author));
154
155 QDateTime time;
156 if (d->mCurrentPost->repeatedDateTime.isNull()) {
157 time = d->mCurrentPost->creationDateTime;
158 } else {
159 time = d->mCurrentPost->repeatedDateTime;
160 }
161
162 ss += QStringLiteral("<a href=\"%1\" title=\"%2\">%3</a>").arg(d->mCurrentPost->link.toDisplayString())
163 .arg(time.toString(Qt::DefaultLocaleLongDate)).arg(formatDateTime(time));
164
165 if (!d->mCurrentPost->source.isEmpty()) {
166 ss += QLatin1String(" - ") + d->mCurrentPost->source;
167 }
168
169 return ss;
170 }
171
getUsernameHyperlink(const Choqok::User & user) const172 QString PostWidget::getUsernameHyperlink(const Choqok::User &user) const
173 {
174 return QStringLiteral("<a href=\"%1\" title=\"%2\">%3</a>")
175 .arg(d->mCurrentAccount->microblog()->profileUrl(d->mCurrentAccount, user.userName).toDisplayString())
176 .arg(user.description.isEmpty() ? user.realName : user.description)
177 .arg(user.userName);
178 }
179
setupUi()180 void PostWidget::setupUi()
181 {
182 setLayout(new QVBoxLayout);
183 layout()->setMargin(0);
184 layout()->setContentsMargins(0, 0, 0, 0);
185 layout()->addWidget(_mainWidget);
186 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
187 _mainWidget->setFocusProxy(this);
188
189 d->buttonsLayout = new QGridLayout(_mainWidget);
190 d->buttonsLayout->setRowStretch(0, 100);
191 d->buttonsLayout->setColumnStretch(5, 100);
192 d->buttonsLayout->setMargin(0);
193 d->buttonsLayout->setSpacing(0);
194
195 _mainWidget->setLayout(d->buttonsLayout);
196 connect(_mainWidget, &TextBrowser::textChanged, this, &PostWidget::setHeight);
197
198 }
199
initUi()200 void PostWidget::initUi()
201 {
202 setupUi();
203 _mainWidget->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("img://profileImage")),
204 MediaManager::self()->defaultImage());
205
206 if (isRemoveAvailable()) {
207 QPushButton *btnRemove = addButton(QLatin1String("btnRemove"), i18nc("@info:tooltip", "Remove"), QLatin1String("edit-delete"));
208 connect(btnRemove, &QPushButton::clicked, this, &PostWidget::removeCurrentPost);
209 }
210
211 if (isResendAvailable()) {
212 QPushButton *btnResend = addButton(QLatin1String("btnResend"), i18nc("@info:tooltip", "ReSend"), QLatin1String("retweet"));
213 connect(btnResend, &QPushButton::clicked, this, &PostWidget::slotResendPost);
214 }
215
216 d->mProfileImage = QLatin1String("<img src=\"img://profileImage\" title=\"") + d->mCurrentPost->author.realName + QLatin1String("\" width=\"48\" height=\"48\" />");
217 d->mContent = prepareStatus(d->mCurrentPost->content);
218 d->mSign = generateSign();
219 setupAvatar();
220 fetchImage();
221 d->dir = getDirection(d->mCurrentPost->content);
222 setUiStyle();
223
224 d->mContent.replace(QLatin1String("<a href"), QLatin1String("<a style=\"text-decoration:none\" href"), Qt::CaseInsensitive);
225 d->mContent.replace(QLatin1String("\n"), QLatin1String("<br/>"));
226 d->extraContents.replace(QLatin1String("<a href"), QLatin1String("<a style=\"text-decoration:none\" href"), Qt::CaseInsensitive);
227 d->mSign.replace(QLatin1String("<a href"), QLatin1String("<a style=\"text-decoration:none\" href"), Qt::CaseInsensitive);
228
229 updateUi();
230 }
231
updateUi()232 void PostWidget::updateUi()
233 {
234 _mainWidget->setHtml(baseTextTemplate.arg( d->mProfileImage, /*1*/
235 d->mContent, /*2*/
236 d->mSign, /*3*/
237 d->dir, /*4*/
238 d->mImage, /*5*/
239 d->extraContents /*6*/
240 ));
241 }
242
setStyle(const QColor & color,const QColor & back,const QColor & read,const QColor & readBack,const QColor & own,const QColor & ownBack,const QFont & font)243 void PostWidget::setStyle(const QColor &color, const QColor &back, const QColor &read, const QColor &readBack, const QColor &own, const QColor &ownBack, const QFont &font)
244 {
245 QString fntStr = QLatin1String("font-family:\"") + font.family() + QLatin1String("\"; font-size:") + QString::number(font.pointSize()) + QLatin1String("pt;");
246 fntStr += (font.bold() ? QLatin1String(" font-weight:bold;") : QString()) + (font.italic() ? QLatin1String(" font-style:italic;") : QString());
247 unreadStyle = baseStyle.arg(getColorString(color), getColorString(back), fntStr);
248 readStyle = baseStyle.arg(getColorString(read), getColorString(readBack), fntStr);
249 ownStyle = baseStyle.arg(getColorString(own), getColorString(ownBack), fntStr);
250 }
251
addButton(const QString & objName,const QString & toolTip,const QString & icon)252 QPushButton *PostWidget::addButton(const QString &objName, const QString &toolTip, const QString &icon)
253 {
254 return addButton(objName, toolTip, QIcon::fromTheme(icon));
255
256 }
257
addButton(const QString & objName,const QString & toolTip,const QIcon & icon)258 QPushButton *PostWidget::addButton(const QString &objName, const QString &toolTip, const QIcon &icon)
259 {
260 QPushButton *button = new QPushButton(icon, QString(), _mainWidget);
261 button->setObjectName(objName);
262 button->setToolTip(toolTip);
263 button->setIconSize(QSize(16, 16));
264 button->setMinimumSize(QSize(20, 20));
265 button->setMaximumSize(QSize(20, 20));
266 button->setFlat(true);
267 button->setVisible(false);
268 button->setCursor(Qt::PointingHandCursor);
269
270 d->mUiButtons.insert(objName, button);
271 d->buttonsLayout->addWidget(button, 1, d->mUiButtons.count());
272 return button;
273 }
274
currentPost() const275 Post *PostWidget::currentPost() const
276 {
277 return d->mCurrentPost;
278 }
279
setCurrentPost(Post * post)280 void PostWidget::setCurrentPost(Post *post)
281 {
282 d->mCurrentPost = post;
283 }
284
setRead(bool read)285 void PostWidget::setRead(bool read/* = true*/)
286 {
287 if (!read && !currentPost()->isRead &&
288 currentAccount()->username().compare(currentPost()->author.userName, Qt::CaseInsensitive) == 0) {
289 d->mCurrentPost->isRead = true; ///Always Set own posts as read.
290 setUiStyle();
291 } else if (currentPost()->isRead != read) {
292 d->mCurrentPost->isRead = read;
293 setUiStyle();
294 }
295 }
296
setReadWithSignal()297 void PostWidget::setReadWithSignal()
298 {
299 if (!isRead()) {
300 setRead();
301 Q_EMIT postReaded();
302 }
303 }
304
isRead() const305 bool PostWidget::isRead() const
306 {
307 return currentPost()->isRead;
308 }
309
setUiStyle()310 void PostWidget::setUiStyle()
311 {
312 if (isOwnPost()) {
313 setStyleSheet(ownStyle);
314 } else {
315 if (currentPost()->isRead) {
316 setStyleSheet(readStyle);
317 } else {
318 setStyleSheet(unreadStyle);
319 }
320 }
321 setHeight();
322 }
323
isOwnPost()324 bool PostWidget::isOwnPost()
325 {
326 return currentAccount()->username().compare(currentPost()->author.userName, Qt::CaseInsensitive) == 0;
327 }
328
setHeight()329 void PostWidget::setHeight()
330 {
331 _mainWidget->document()->setTextWidth(width() - 2);
332 int h = _mainWidget->document()->size().toSize().height() + 2;
333 setFixedHeight(h);
334 }
335
closeEvent(QCloseEvent * event)336 void PostWidget::closeEvent(QCloseEvent *event)
337 {
338 clearFocus();
339 if (!isRead()) {
340 setReadWithSignal();
341 }
342 Q_EMIT aboutClosing(currentPost()->postId, this);
343 event->accept();
344 }
345
mousePressEvent(QMouseEvent * ev)346 void PostWidget::mousePressEvent(QMouseEvent *ev)
347 {
348 if (!isRead()) {
349 setReadWithSignal();
350 }
351 QWidget::mousePressEvent(ev);
352 }
353
resizeEvent(QResizeEvent * event)354 void PostWidget::resizeEvent(QResizeEvent *event)
355 {
356 updatePostImage( event->size().width() );
357 setHeight();
358 updateUi();
359 QWidget::resizeEvent(event);
360 }
361
enterEvent(QEvent * event)362 void PostWidget::enterEvent(QEvent *event)
363 {
364 for (QPushButton *btn: buttons()) {
365 if (btn) { //A crash happens here :/
366 btn->show();
367 }
368 }
369 QWidget::enterEvent(event);
370 }
371
leaveEvent(QEvent * event)372 void PostWidget::leaveEvent(QEvent *event)
373 {
374 for (QPushButton *btn: buttons()) {
375 if (btn) {
376 btn->hide();
377 }
378 }
379 QWidget::enterEvent(event);
380 }
381
updatePostImage(int width)382 void PostWidget::updatePostImage(int width)
383 {
384 if ( !d->originalImage.isNull() ) {
385 // TODO: Find a way to calculate the difference we need to subtract.
386 width -= 76;
387
388 QPixmap newPixmap = d->originalImage.scaledToWidth(width, Qt::SmoothTransformation);
389 auto newW = newPixmap.width();
390 auto newH = newPixmap.height();
391 auto origW = d->originalImage.width();
392 auto origH = d->originalImage.height();
393
394 const QUrl url(d->resourceImageUrl);
395 // only use scaled image if it's smaller than the original one
396 if (newW <= origW && newH <= origH) { // never scale up
397 d->mImage = mImageTemplate.arg(QString::number(newW), QString::number(newH), d->resourceImageUrl);
398 _mainWidget->document()->addResource(QTextDocument::ImageResource, url, newPixmap);
399 } else {
400 d->mImage = mImageTemplate.arg(QString::number(origW), QString::number(origH), d->resourceImageUrl);
401 _mainWidget->document()->addResource(QTextDocument::ImageResource, url, d->originalImage);
402 }
403 }
404 }
405
prepareStatus(const QString & txt)406 QString PostWidget::prepareStatus(const QString &txt)
407 {
408 QString text = removeTags(txt);
409
410 d->detectedUrls = UrlUtils::detectUrls(text);
411 for (const QString &url: d->detectedUrls) {
412 QString httpUrl(url);
413 if (!httpUrl.startsWith(QLatin1String("http"), Qt::CaseInsensitive) &&
414 !httpUrl.startsWith(QLatin1String("ftp"), Qt::CaseInsensitive)) {
415 httpUrl.prepend(QLatin1String("http://"));
416 text.replace(url, httpUrl);
417 }
418
419 text.replace(url, hrefTemplate.arg(httpUrl, url));
420 }
421
422 text = UrlUtils::detectEmails(text);
423
424 if (AppearanceSettings::isEmoticonsEnabled()) {
425 text = MediaManager::self()->parseEmoticons(text);
426 }
427
428 return text;
429 }
430
removeTags(const QString & text) const431 QString PostWidget::removeTags(const QString &text) const
432 {
433 QString txt(text);
434
435 txt.replace(QLatin1Char('<'), QLatin1String("<"));
436 txt.replace(QLatin1Char('>'), QLatin1String(">"));
437
438 return txt;
439 }
getDirection(QString txt)440 QLatin1String PostWidget::getDirection(QString txt)
441 {
442 txt.remove(dirRegExp);
443 txt = txt.trimmed();
444 if (txt.isRightToLeft()) {
445 return QLatin1String("rtl");
446 }
447 else {
448 return QLatin1String("ltr");
449 }
450 }
451
formatDateTime(const QDateTime & time)452 QString PostWidget::formatDateTime(const QDateTime &time)
453 {
454 if (!time.isValid()) {
455 return tr("Invalid Time");
456 }
457 auto seconds = time.secsTo(QDateTime::currentDateTime());
458 if (seconds <= 15) {
459 d->mTimer.setInterval(_15SECS);
460 return i18n("Just now");
461 }
462
463 if (seconds <= 45) {
464 d->mTimer.setInterval(_15SECS);
465 return i18np("1 sec ago", "%1 secs ago", seconds);
466 }
467
468 auto minutes = (seconds - 45 + 59) / 60;
469 if (minutes <= 45) {
470 d->mTimer.setInterval(_MINUTE);
471 return i18np("1 min ago", "%1 mins ago", minutes);
472 }
473
474 auto hours = (seconds - 45 * 60 + 3599) / 3600;
475 if (hours <= 18) {
476 d->mTimer.setInterval(_MINUTE * 15);
477 return i18np("1 hour ago", "%1 hours ago", hours);
478 }
479
480 d->mTimer.setInterval(_HOUR);
481 auto days = (seconds - 18 * 3600 + 24 * 3600 - 1) / (24 * 3600);
482 return i18np("1 day ago", "%1 days ago", days);
483 }
484
removeCurrentPost()485 void PostWidget::removeCurrentPost()
486 {
487 if (KMessageBox::warningYesNo(this, i18n("Are you sure you want to remove this post from the server?")) == KMessageBox::Yes) {
488 connect(d->mCurrentAccount->microblog(), &MicroBlog::postRemoved,
489 this, &PostWidget::slotCurrentPostRemoved);
490 connect(d->mCurrentAccount->microblog(), &MicroBlog::errorPost, this, &PostWidget::slotPostError);
491 setReadWithSignal();
492 d->mCurrentAccount->microblog()->removePost(d->mCurrentAccount, d->mCurrentPost);
493 }
494 }
495
slotCurrentPostRemoved(Account * theAccount,Post * post)496 void PostWidget::slotCurrentPostRemoved(Account *theAccount, Post *post)
497 {
498 if (theAccount == currentAccount() && post == d->mCurrentPost) {
499 this->close();
500 }
501 }
502
slotResendPost()503 void PostWidget::slotResendPost()
504 {
505 QString text = generateResendText();
506 setReadWithSignal();
507 if ((BehaviorSettings::resendWithQuickPost() || currentAccount()->isReadOnly()) && Global::quickPostWidget()) {
508 Global::quickPostWidget()->setText(text);
509 } else {
510 Q_EMIT resendPost(text);
511 }
512 }
513
generateResendText()514 QString PostWidget::generateResendText()
515 {
516 if (BehaviorSettings::useCustomRT()) {
517 return QString(BehaviorSettings::customRT()) + QLatin1String(" @") + currentPost()->author.userName + QLatin1String(": ") + currentPost()->content;
518 } else {
519 QChar re(0x267B);
520 return QString(re) + QLatin1String(" @") + currentPost()->author.userName + QLatin1String(": ") + currentPost()->content;
521 }
522 }
523
fetchImage()524 void PostWidget::fetchImage()
525 {
526 if (d->imageUrl.isEmpty()) {
527 return;
528 }
529
530 QPixmap pix = MediaManager::self()->fetchImage(d->imageUrl, MediaManager::Async);
531
532 if (!pix.isNull()) {
533 slotImageFetched(d->imageUrl, pix);
534 } else {
535 connect(MediaManager::self(), &MediaManager::imageFetched, this,
536 &PostWidget::slotImageFetched);
537 }
538 }
539
slotImageFetched(const QUrl & remoteUrl,const QPixmap & pixmap)540 void PostWidget::slotImageFetched(const QUrl &remoteUrl, const QPixmap &pixmap)
541 {
542 if (remoteUrl == d->imageUrl) {
543 disconnect(MediaManager::self(), &MediaManager::imageFetched, this, &PostWidget::slotImageFetched);
544 d->originalImage = pixmap;
545 updatePostImage( width() );
546 updateUi();
547 }
548 }
549
setupAvatar()550 void PostWidget::setupAvatar()
551 {
552 QPixmap pix = MediaManager::self()->fetchImage(d->mCurrentPost->author.profileImageUrl,
553 MediaManager::Async);
554 if (!pix.isNull()) {
555 avatarFetched(d->mCurrentPost->author.profileImageUrl, pix);
556 } else {
557 connect(MediaManager::self(), &MediaManager::imageFetched, this, &PostWidget::avatarFetched);
558 connect(MediaManager::self(), &MediaManager::fetchError, this, &PostWidget::avatarFetchError);
559 }
560 }
561
avatarFetched(const QUrl & remoteUrl,const QPixmap & pixmap)562 void PostWidget::avatarFetched(const QUrl &remoteUrl, const QPixmap &pixmap)
563 {
564 if (remoteUrl == d->mCurrentPost->author.profileImageUrl) {
565 const QUrl url(QLatin1String("img://profileImage"));
566 _mainWidget->document()->addResource(QTextDocument::ImageResource, url, pixmap);
567 updateUi();
568 disconnect(MediaManager::self(), &MediaManager::imageFetched, this, &PostWidget::avatarFetched);
569 disconnect(MediaManager::self(), &MediaManager::fetchError, this, &PostWidget::avatarFetchError);
570 }
571 }
572
avatarFetchError(const QUrl & remoteUrl,const QString & errMsg)573 void PostWidget::avatarFetchError(const QUrl &remoteUrl, const QString &errMsg)
574 {
575 Q_UNUSED(errMsg);
576 if (remoteUrl == d->mCurrentPost->author.profileImageUrl) {
577 ///Avatar fetching is failed! but will not disconnect to get the img if it fetches later!
578 const QUrl url(QLatin1String("img://profileImage"));
579 _mainWidget->document()->addResource(QTextDocument::ImageResource,
580 url, QIcon::fromTheme(QLatin1String("image-missing")).pixmap(48));
581 updateUi();
582 }
583 }
584
buttons()585 QMap<QString, QPushButton * > &PostWidget::buttons()
586 {
587 return d->mUiButtons;
588 }
589
slotPostError(Account * theAccount,Choqok::Post * post,MicroBlog::ErrorType,const QString & errorMessage)590 void PostWidget::slotPostError(Account *theAccount, Choqok::Post *post,
591 MicroBlog::ErrorType , const QString &errorMessage)
592 {
593 if (theAccount == currentAccount() && post == d->mCurrentPost) {
594 qCDebug(CHOQOK) << errorMessage;
595 disconnect(d->mCurrentAccount->microblog(), &MicroBlog::postRemoved,
596 this, &PostWidget::slotCurrentPostRemoved);
597 disconnect(d->mCurrentAccount->microblog(), &MicroBlog::errorPost,
598 this, &PostWidget::slotPostError);
599 }
600 }
601
avatarText() const602 QString PostWidget::avatarText() const
603 {
604 return d->mProfileImage;
605 }
606
setAvatarText(const QString & text)607 void PostWidget::setAvatarText(const QString &text)
608 {
609 d->mProfileImage = text;
610 updateUi();
611 }
612
content() const613 QString PostWidget::content() const
614 {
615 return d->mContent;
616 }
617
setContent(const QString & content)618 void PostWidget::setContent(const QString &content)
619 {
620 d->mContent = content;
621 updateUi();
622 }
623
urls()624 QStringList PostWidget::urls()
625 {
626 return d->detectedUrls;
627 }
628
sign() const629 QString PostWidget::sign() const
630 {
631 return d->mSign;
632 }
633
setSign(const QString & sign)634 void PostWidget::setSign(const QString &sign)
635 {
636 d->mSign = sign;
637 updateUi();
638 }
639
deleteLater()640 void PostWidget::deleteLater()
641 {
642 close();
643 }
644
mainWidget()645 TextBrowser *PostWidget::mainWidget()
646 {
647 return _mainWidget;
648 }
649
wheelEvent(QWheelEvent * event)650 void PostWidget::wheelEvent(QWheelEvent *event)
651 {
652 event->ignore();
653 }
654
addAction(QAction * action)655 void PostWidget::addAction(QAction *action)
656 {
657 TextBrowser::addAction(action);
658 }
659
timelineWidget() const660 TimelineWidget *PostWidget::timelineWidget() const
661 {
662 return d->timeline;
663 }
664
665 class PostWidgetUserData::Private
666 {
667 public:
Private(PostWidget * postwidget)668 Private(PostWidget *postwidget)
669 : postWidget(postwidget)
670 {}
671 PostWidget *postWidget;
672 };
673
PostWidgetUserData(PostWidget * postWidget)674 PostWidgetUserData::PostWidgetUserData(PostWidget *postWidget)
675 : QObjectUserData(), d(new Private(postWidget))
676 {
677
678 }
679
~PostWidgetUserData()680 PostWidgetUserData::~PostWidgetUserData()
681 {
682 delete d;
683 }
684
postWidget()685 PostWidget *PostWidgetUserData::postWidget()
686 {
687 return d->postWidget;
688 }
689
setPostWidget(PostWidget * widget)690 void PostWidgetUserData::setPostWidget(PostWidget *widget)
691 {
692 d->postWidget = widget;
693 }
694
getBaseStyle()695 QString PostWidget::getBaseStyle()
696 {
697 return baseStyle;
698 }
699
isRemoveAvailable()700 bool PostWidget::isRemoveAvailable()
701 {
702 return d->mCurrentAccount->username().compare(d->mCurrentPost->author.userName, Qt::CaseInsensitive) == 0;
703 }
704
isResendAvailable()705 bool PostWidget::isResendAvailable()
706 {
707 return d->mCurrentAccount->username().compare(d->mCurrentPost->author.userName, Qt::CaseInsensitive) != 0;
708 }
709
setExtraContents(const QString & text)710 void PostWidget::setExtraContents(const QString& text)
711 {
712 d->extraContents = text;
713 }
714
extraContents() const715 QString PostWidget::extraContents() const
716 {
717 return d->extraContents;
718 }
719
720