File indexing completed on 2024-05-19 08:48:05
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> <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"