File indexing completed on 2024-04-28 04:55:38

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "twitterapipostwidget.h"
0010 
0011 #include <QAction>
0012 #include <QIcon>
0013 #include <QMenu>
0014 #include <QPushButton>
0015 
0016 #include <KLocalizedString>
0017 #include <KMessageBox>
0018 
0019 #include "choqokappearancesettings.h"
0020 #include "mediamanager.h"
0021 #include "microblog.h"
0022 #include "textbrowser.h"
0023 #include "twitterapiaccount.h"
0024 #include "twitterapidebug.h"
0025 #include "twitterapimicroblog.h"
0026 #include "twitterapishowthread.h"
0027 
0028 const QIcon TwitterApiPostWidget::unFavIcon(Choqok::MediaManager::convertToGrayScale(QIcon::fromTheme(QLatin1String("rating")).pixmap(16)));
0029 
0030 class TwitterApiPostWidget::Private
0031 {
0032 public:
0033     Private(Choqok::Account *account)
0034         : isBasePostShowed(false)
0035     {
0036         mBlog = qobject_cast<TwitterApiMicroBlog *>(account->microblog());
0037     }
0038     QPushButton *btnFav;
0039     bool isBasePostShowed;
0040     TwitterApiMicroBlog *mBlog;
0041 };
0042 
0043 TwitterApiPostWidget::TwitterApiPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent)
0044     : PostWidget(account, post, parent), d(new Private(account))
0045 {
0046     mainWidget()->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://thread")),
0047                                           QIcon::fromTheme(QLatin1String("go-top")).pixmap(10));
0048 }
0049 
0050 TwitterApiPostWidget::~TwitterApiPostWidget()
0051 {
0052     delete d;
0053 }
0054 
0055 void TwitterApiPostWidget::initUi()
0056 {
0057     Choqok::UI::PostWidget::initUi();
0058 
0059     QPushButton *btnRe = addButton(QLatin1String("btnReply"), i18nc("@info:tooltip", "Reply"), QLatin1String("edit-undo"));
0060     connect(btnRe, &QPushButton::clicked, this, &TwitterApiPostWidget::slotReply);
0061     QMenu *menu = new QMenu(btnRe);
0062     btnRe->setMenu(menu);
0063 
0064     QAction *actRep = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18n("Reply to %1", currentPost()->author.userName), menu);
0065     menu->addAction(actRep);
0066     menu->setDefaultAction(actRep);
0067     connect(actRep, &QAction::triggered, this, &TwitterApiPostWidget::slotReply);
0068 
0069     QAction *actWrite = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Write to %1", currentPost()->author.userName), menu);
0070     menu->addAction(actWrite);
0071     connect(actWrite, &QAction::triggered, this, &TwitterApiPostWidget::slotWriteTo);
0072 
0073     if (!currentPost()->isPrivate) {
0074         QAction *actReplytoAll = new QAction(i18n("Reply to all"), menu);
0075         menu->addAction(actReplytoAll);
0076         connect(actReplytoAll, &QAction::triggered, this, &TwitterApiPostWidget::slotReplyToAll);
0077 
0078         d->btnFav = addButton(QLatin1String("btnFavorite"), i18nc("@info:tooltip", "Favorite"), QLatin1String("rating"));
0079         d->btnFav->setCheckable(true);
0080         connect(d->btnFav, &QPushButton::clicked, this, &TwitterApiPostWidget::setFavorite);
0081         updateFavStat();
0082     }
0083 }
0084 
0085 QString TwitterApiPostWidget::generateSign()
0086 {
0087     QString sign = QStringLiteral("<b>%1 - </b>").arg(getUsernameHyperlink(currentPost()->author));
0088 
0089     //<img src=\"icon://web\" />
0090     if (currentPost()->isPrivate) {
0091         sign += QLatin1String("%1");
0092 
0093         if (currentPost()->replyToUser.userName.compare(currentAccount()->username(), Qt::CaseInsensitive) == 0) {
0094             sign.prepend(QLatin1String("From "));
0095         } else {
0096             sign.prepend(QLatin1String("To "));
0097         }
0098     } else {
0099         QDateTime time;
0100         if (currentPost()->repeatedDateTime.isNull()) {
0101             time = currentPost()->creationDateTime;
0102         } else {
0103             time = currentPost()->repeatedDateTime;
0104         }
0105 
0106         sign += QStringLiteral("<a href=\"%1\" title=\"%2\">%3</a>").arg(currentPost()->link.toDisplayString())
0107                 .arg(time.toString(Qt::DefaultLocaleLongDate)).arg(QStringLiteral("%1"));
0108     }
0109 
0110     if (!currentPost()->source.isEmpty()) {
0111         sign += QLatin1String(" - ");
0112         if (currentPost()->source == QLatin1String("ostatus") && !currentPost()->author.homePageUrl.isEmpty()) {
0113             sign += i18n("<a href='%1' title='Sent from %2 via OStatus'>%2</a>",
0114                          currentPost()->author.homePageUrl.toDisplayString(),
0115                          currentPost()->author.homePageUrl.host());
0116         } else {
0117             sign += currentPost()->source;
0118         }
0119     }
0120 
0121     if (!currentPost()->isPrivate) {
0122         if (!currentPost()->replyToPostId.isEmpty()) {
0123             QUrl link = currentAccount()->microblog()->postUrl(currentAccount(), currentPost()->replyToUser.userName,
0124                            currentPost()->replyToPostId);
0125             QString showConMsg = i18n("Show Conversation");
0126             QString threadlink;
0127             if (currentPost()->conversationId.isEmpty()) {
0128                 threadlink = QLatin1String("thread://") + currentPost()->postId;
0129             } else {
0130                 threadlink = QLatin1String("conversation://") + currentPost()->conversationId;
0131             }
0132             sign += QLatin1String(" - ") +
0133                     i18n("<a href='replyto://%1'>in reply to</a> @<a href='user://%4'>%4</a>&nbsp;<a href=\"%2\" title=\"%2\">%3</a>",
0134                          currentPost()->replyToPostId, link.toDisplayString(), webIconText, currentPost()->replyToUser.userName) + QLatin1Char(' ');
0135             sign += QLatin1String("<a title=\"") + showConMsg + QLatin1String("\" href=\"") + threadlink + QLatin1String("\"><img src=\"icon://thread\" /></a>");
0136         }
0137 
0138         //ReTweet detection
0139         if (!currentPost()->repeatedFromUser.userName.isEmpty()) {
0140             const QString retweet = QLatin1String("<br/>") +
0141                     d->mBlog->generateRepeatedByUserTooltip(QStringLiteral("<a href='user://%1'>%2</a>")
0142                                                             .arg(currentPost()->repeatedFromUser.userName)
0143                                                             .arg(currentPost()->repeatedFromUser.userName));
0144             sign.append(retweet);
0145         }
0146     }
0147 
0148     sign.prepend(QLatin1String("<p dir='ltr'>"));
0149     sign.append(QLatin1String("</p>"));
0150 
0151     return sign;
0152 }
0153 
0154 QString TwitterApiPostWidget::getUsernameHyperlink(const Choqok::User &user) const
0155 {
0156     return QStringLiteral("<a href=\"user://%1\" title=\"%2\">%3</a>")
0157             .arg(user.userName)
0158             .arg(user.description.isEmpty() ? user.realName : user.description.toHtmlEscaped())
0159             .arg(user.userName);
0160 }
0161 
0162 void TwitterApiPostWidget::slotReply()
0163 {
0164     setReadWithSignal();
0165     if (currentPost()->isPrivate) {
0166         TwitterApiAccount *account = qobject_cast<TwitterApiAccount *>(currentAccount());
0167         d->mBlog->showDirectMessageDialog(account, currentPost()->author.userName);
0168     } else {
0169         QString replyto = QStringLiteral("@%1").arg(currentPost()->author.userName);
0170         QString postId = currentPost()->postId;
0171         QString username = currentPost()->author.userName;
0172         if (!currentPost()->repeatedFromUser.userName.isEmpty()) {
0173             replyto.prepend(QStringLiteral("@%1 ").arg(currentPost()->repeatedFromUser.userName));
0174             postId = currentPost()->repeatedPostId;
0175         }
0176         Q_EMIT reply(replyto, postId,  username);
0177     }
0178 }
0179 
0180 void TwitterApiPostWidget::slotWriteTo()
0181 {
0182     Q_EMIT reply(QStringLiteral("@%1").arg(currentPost()->author.userName), QString(), currentPost()->author.userName);
0183 }
0184 
0185 void TwitterApiPostWidget::slotReplyToAll()
0186 {
0187     QString txt = QStringLiteral("@%1").arg(currentPost()->author.userName);
0188     Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName);
0189 }
0190 
0191 void TwitterApiPostWidget::setFavorite()
0192 {
0193     setReadWithSignal();
0194     TwitterApiMicroBlog *mic = d->mBlog;
0195     if (currentPost()->isFavorited) {
0196         connect(mic, &TwitterApiMicroBlog::favoriteRemoved, this, &TwitterApiPostWidget::slotSetFavorite);
0197         mic->removeFavorite(currentAccount(), currentPost()->postId);
0198     } else {
0199         connect(mic, &TwitterApiMicroBlog::favoriteCreated, this, &TwitterApiPostWidget::slotSetFavorite);
0200         mic->createFavorite(currentAccount(), currentPost()->postId);
0201     }
0202 }
0203 
0204 void TwitterApiPostWidget::slotSetFavorite(Choqok::Account *theAccount, const QString &postId)
0205 {
0206     if (currentAccount() == theAccount && postId == currentPost()->postId) {
0207         qCDebug(CHOQOK) << postId;
0208         currentPost()->isFavorited = !currentPost()->isFavorited;
0209         updateFavStat();
0210         disconnect(d->mBlog, &TwitterApiMicroBlog::favoriteRemoved, this, &TwitterApiPostWidget::slotSetFavorite);
0211         disconnect(d->mBlog, &TwitterApiMicroBlog::favoriteCreated, this, &TwitterApiPostWidget::slotSetFavorite);
0212     }
0213 }
0214 
0215 void TwitterApiPostWidget::updateFavStat()
0216 {
0217     if (currentPost()->isFavorited) {
0218         d->btnFav->setChecked(true);
0219         d->btnFav->setIcon(QIcon::fromTheme(QLatin1String("rating")));
0220     } else {
0221         d->btnFav->setChecked(false);
0222         d->btnFav->setIcon(unFavIcon);
0223     }
0224 }
0225 
0226 void TwitterApiPostWidget::checkAnchor(const QUrl &url)
0227 {
0228     QString scheme = url.scheme();
0229     if (scheme == QLatin1String("replyto")) {
0230         if (d->isBasePostShowed) {
0231             setContent(prepareStatus(currentPost()->content).replace(QLatin1String("<a href"), QLatin1String("<a style=\"text-decoration:none\" href"), Qt::CaseInsensitive));
0232             updateUi();
0233             d->isBasePostShowed = false;
0234             return;
0235         } else {
0236             connect(currentAccount()->microblog(), &Choqok::MicroBlog::postFetched,
0237                     this, &TwitterApiPostWidget::slotBasePostFetched);
0238             Choqok::Post *ps = new Choqok::Post;
0239             ps->postId = url.host();
0240             currentAccount()->microblog()->fetchPost(currentAccount(), ps);
0241         }
0242     } else if (scheme == QLatin1String("thread")) {
0243         TwitterApiShowThread *wd = new TwitterApiShowThread(currentAccount(), currentPost(), nullptr);
0244         wd->resize(this->width(), wd->height());
0245         connect(wd, &TwitterApiShowThread::forwardReply, this, &TwitterApiPostWidget::reply);
0246         connect(wd, &TwitterApiShowThread::forwardResendPost, this, &TwitterApiPostWidget::resendPost);
0247         wd->show();
0248     } else {
0249         Choqok::UI::PostWidget::checkAnchor(url);
0250     }
0251 
0252 }
0253 
0254 void TwitterApiPostWidget::slotBasePostFetched(Choqok::Account *theAccount, Choqok::Post *post)
0255 {
0256     if (theAccount == currentAccount() && post && post->postId == currentPost()->replyToPostId) {
0257         qCDebug(CHOQOK);
0258         disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postFetched,
0259                    this, &TwitterApiPostWidget::slotBasePostFetched);
0260         if (d->isBasePostShowed) {
0261             return;
0262         }
0263         d->isBasePostShowed = true;
0264         QString color;
0265         if (Choqok::AppearanceSettings::isCustomUi()) {
0266             color = Choqok::AppearanceSettings::readForeColor().lighter().name();
0267         } else {
0268             color = this->palette().dark().color().name();
0269         }
0270         QString baseStatusText = QLatin1String("<p style=\"margin-top:10px; margin-bottom:10px; margin-left:20px;\
0271         margin-right:20px; text-indent:0px\"><span style=\" color:") + color + QLatin1String(";\">");
0272         baseStatusText += QLatin1String("<b><a href='user://") + post->author.userName + QLatin1String("'>") +
0273                           post->author.userName + QLatin1String("</a> :</b> ");
0274 
0275         baseStatusText += prepareStatus(post->content) + QLatin1String("</p>");
0276         setContent(content().prepend(baseStatusText.replace(QLatin1String("<a href"), QLatin1String("<a style=\"text-decoration:none\" href"), Qt::CaseInsensitive)));
0277         updateUi();
0278         if( post->owners < 1 )
0279             delete post;
0280     }
0281 }
0282 
0283 void TwitterApiPostWidget::repeatPost()
0284 {
0285     setReadWithSignal();
0286     QString postId;
0287     if (currentPost()->repeatedPostId.isEmpty()) {
0288         postId = currentPost()->postId;
0289     } else {
0290         postId = currentPost()->repeatedPostId;
0291     }
0292     auto q_answer = KMessageBox::questionYesNo(Choqok::UI::Global::mainWindow(), d->mBlog->repeatQuestion(),
0293                                                QString(), KStandardGuiItem::yes(), KStandardGuiItem::cancel(),
0294                                                QLatin1String("dontAskRepeatConfirm"));
0295     if ( q_answer == KMessageBox::Yes) {
0296         d->mBlog->repeatPost(currentAccount(), postId);
0297     }
0298 }
0299 
0300 #include "moc_twitterapipostwidget.cpp"