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("&#9755;"));
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("&lt;"));
436     txt.replace(QLatin1Char('>'), QLatin1String("&gt;"));
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