File indexing completed on 2024-05-05 04:57:28

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 "twitterpostwidget.h"
0010 
0011 #include <QAction>
0012 #include <QMenu>
0013 #include <QPushButton>
0014 
0015 #include <KLocalizedString>
0016 
0017 #include "choqokbehaviorsettings.h"
0018 #include "choqoktools.h"
0019 #include "mediamanager.h"
0020 #include "textbrowser.h"
0021 
0022 #include "twitterapiaccount.h"
0023 #include "twitterapimicroblog.h"
0024 #include "twitterapiwhoiswidget.h"
0025 
0026 #include "twittersearch.h"
0027 
0028 const QRegExp TwitterPostWidget::mTwitterUserRegExp(QLatin1String("([\\s\\W]|^)@([a-z0-9_]+){1,20}"), Qt::CaseInsensitive);
0029 const QRegExp TwitterPostWidget::mTwitterTagRegExp(QLatin1String("([\\s]|^)#([\\w_\\.\\-]+)"), Qt::CaseInsensitive);
0030 const QString TwitterPostWidget::mQuotedTextBase(QLatin1String("<div style=\"padding-top:5px;padding-bottom:3px;\"><table style=\"%4 border-style:groove;\" border=\"1\"><tr><td style=\"padding-top:4px;padding-bottom:4px;padding-left:3px;padding-right:3px;\"><table> <tr><td width=\"40\" style=\"padding-right:5px;\"><img src=\"img://quotedProfileImage\" width=\"40\" height=\"40\" /></td><td dir=\"%2\"><p><b><a>%3:</b>&nbsp;%1</p></td></tr></table></td></tr></table></div>"));
0031 const QUrl TwitterPostWidget::mQuotedAvatarResourceUrl(QLatin1String("img://quotedProfileImage"));
0032 TwitterPostWidget::TwitterPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent): TwitterApiPostWidget(account, post, parent)
0033 {
0034 }
0035 
0036 TwitterPostWidget::~TwitterPostWidget()
0037 {
0038 }
0039 
0040 void TwitterPostWidget::initUi()
0041 {
0042     TwitterApiPostWidget::initUi();
0043     
0044     if ( ! currentPost()->quotedPost.content.isEmpty() ) {
0045         if( !setupQuotedAvatar() ){
0046             _mainWidget->document()->addResource(QTextDocument::ImageResource, mQuotedAvatarResourceUrl,
0047                                                  Choqok::MediaManager::self()->defaultImage());
0048         }
0049         
0050         auto dir = getDirection(currentPost()->quotedPost.content);
0051         auto text = prepareStatus(currentPost()->quotedPost.content);
0052         QString user = QStringLiteral("<a href='user://%1'>%1</a>").arg(currentPost()->quotedPost.user.userName);
0053         QString quoteText = mQuotedTextBase.arg(text, dir, user, QLatin1String("background-color:%1;"));
0054         setExtraContents(quoteText.arg(getBackgroundColor()));
0055         updateUi();
0056     }
0057     
0058     QPushButton *btn = buttons().value(QLatin1String("btnResend"));
0059 
0060     if (btn) {
0061         QMenu *menu = new QMenu(btn);
0062         QAction *resend = new QAction(i18n("Manual ReSend"), menu);
0063         connect(resend, &QAction::triggered, this, &TwitterPostWidget::slotResendPost);
0064         QAction *repeat = new QAction(i18n("Retweet"), menu);
0065         repeat->setToolTip(i18n("Retweet post using API"));
0066         connect(repeat, &QAction::triggered, this, &TwitterPostWidget::repeatPost);
0067         // If person protects their acc, we will use simple adding RT before message
0068         if (!currentPost()->author.isProtected) {
0069             menu->addAction(repeat);
0070         }
0071         menu->addAction(resend);
0072         btn->setMenu(menu);
0073     }
0074 }
0075 
0076 QString TwitterPostWidget::prepareStatus(const QString &text)
0077 {
0078     QString res = TwitterApiPostWidget::prepareStatus(text);
0079     res.replace(mTwitterUserRegExp, QLatin1String("\\1@<a href='user://\\2'>\\2</a>"));
0080     res.replace(mTwitterTagRegExp, QLatin1String("\\1#<a href='tag://\\2'>\\2</a>"));
0081     return res;
0082 }
0083 
0084 bool TwitterPostWidget::isRemoveAvailable()
0085 {
0086     if (currentAccount()->username().compare(currentPost()->author.userName, Qt::CaseInsensitive) == 0) {
0087         return true;
0088     } else if (currentPost()->isPrivate) {
0089         return true;
0090     } else {
0091         return false;
0092     }
0093 }
0094 
0095 void TwitterPostWidget::slotReplyToAll()
0096 {
0097     QStringList nicks;
0098     nicks.append(currentPost()->author.userName);
0099 
0100     QString txt = QStringLiteral("@%1 ").arg(currentPost()->author.userName);
0101 
0102     int pos = 0;
0103     while ((pos = mTwitterUserRegExp.indexIn(currentPost()->content, pos)) != -1) {
0104         if (mTwitterUserRegExp.cap(2).toLower() != currentAccount()->username() &&
0105                 mTwitterUserRegExp.cap(2).toLower() != currentPost()->author.userName &&
0106                 !nicks.contains(mTwitterUserRegExp.cap(2).toLower())) {
0107             nicks.append(mTwitterUserRegExp.cap(2));
0108             txt += QStringLiteral("@%1 ").arg(mTwitterUserRegExp.cap(2));
0109         }
0110         pos += mTwitterUserRegExp.matchedLength();
0111     }
0112 
0113     txt.chop(1);
0114 
0115     Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName);
0116 }
0117 
0118 void TwitterPostWidget::checkAnchor(const QUrl &url)
0119 {
0120     QString scheme = url.scheme();
0121     TwitterApiMicroBlog *blog = qobject_cast<TwitterApiMicroBlog *>(currentAccount()->microblog());
0122     TwitterApiAccount *account = qobject_cast<TwitterApiAccount *>(currentAccount());
0123     if (scheme == QLatin1String("tag")) {
0124         blog->searchBackend()->requestSearchResults(currentAccount(),
0125                 QUrl::fromAce(url.host().toUtf8()),
0126                 (int)TwitterSearch::ReferenceHashtag);
0127     } else if (scheme == QLatin1String("user")) {
0128         QMenu menu;
0129         QAction *info = new QAction(QIcon::fromTheme(QLatin1String("user-identity")), i18nc("Who is user", "Who is %1", url.host()),
0130                                     &menu);
0131         QAction *from = new QAction(QIcon::fromTheme(QLatin1String("edit-find-user")), i18nc("Posts from user", "Posts from %1", url.host()),
0132                                     &menu);
0133         QAction *to = new QAction(QIcon::fromTheme(QLatin1String("meeting-attending")), i18nc("Replies to user", "Replies to %1",
0134                                   url.host()),
0135                                   &menu);
0136         QAction *cont = new QAction(QIcon::fromTheme(QLatin1String("user-properties")), i18nc("Including user name", "Including %1",
0137                                     url.host()),
0138                                     &menu);
0139         QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("internet-services")),
0140                                              i18nc("Open profile page in browser",
0141                                                      "Open profile in browser"), &menu);
0142         from->setData(TwitterSearch::FromUser);
0143         to->setData(TwitterSearch::ToUser);
0144         cont->setData(TwitterSearch::ReferenceUser);
0145         menu.addAction(info);
0146         menu.addAction(from);
0147         menu.addAction(to);
0148         menu.addAction(cont);
0149         menu.addAction(openInBrowser);
0150 
0151         //Subscribe/UnSubscribe/Block
0152         bool isSubscribe = false;
0153         QString accountUsername = currentAccount()->username().toLower();
0154         QString postUsername = url.host().toLower();
0155         QAction *subscribe = nullptr, *block = nullptr, *replyTo = nullptr, *dMessage = nullptr, *reportSpam = nullptr;
0156         if (accountUsername != postUsername) {
0157             menu.addSeparator();
0158             QMenu *actionsMenu = menu.addMenu(QIcon::fromTheme(QLatin1String("applications-system")), i18n("Actions"));
0159             replyTo = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18nc("Write a message to user attention", "Write to %1",
0160                                   url.host()), actionsMenu);
0161             actionsMenu->addAction(replyTo);
0162             if (account->friendsList().contains(url.host(),
0163                                                 Qt::CaseInsensitive)) {
0164                 dMessage = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18nc("Send direct message to user",
0165                                        "Send private message to %1",
0166                                        url.host()), actionsMenu);
0167                 actionsMenu->addAction(dMessage);
0168                 isSubscribe = false;//It's UnSubscribe
0169                 subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-remove-user")),
0170                                         i18nc("Unfollow user",
0171                                               "Unfollow %1", url.host()), actionsMenu);
0172             } else {
0173                 isSubscribe = true;
0174                 subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")),
0175                                         i18nc("Follow user",
0176                                               "Follow %1", url.host()), actionsMenu);
0177             }
0178             block = new QAction(QIcon::fromTheme(QLatin1String("dialog-cancel")),
0179                                 i18nc("Block user",
0180                                       "Block %1", url.host()), actionsMenu);
0181             reportSpam = new QAction(QIcon::fromTheme(QLatin1String("irc-voice")),
0182                                      i18nc("Report user",
0183                                            "Report %1 as spam", url.host()), actionsMenu);
0184 
0185             actionsMenu->addAction(subscribe);
0186             actionsMenu->addAction(block);
0187             actionsMenu->addAction(reportSpam);
0188         }
0189 
0190         QAction *ret = menu.exec(QCursor::pos());
0191         if (ret == nullptr) {
0192             return;
0193         }
0194         if (ret == info) {
0195             TwitterApiWhoisWidget *wd = new TwitterApiWhoisWidget(account, url.host(),  *currentPost(), this);
0196             wd->show(QCursor::pos());
0197             return;
0198         } else if (ret == subscribe) {
0199             if (isSubscribe) {
0200                 blog->createFriendship(currentAccount(), url.host());
0201             } else {
0202                 blog->destroyFriendship(currentAccount(), url.host());
0203             }
0204             return;
0205         } else if (ret == block) {
0206             blog->blockUser(currentAccount(), url.host());
0207             return;
0208         } else if (ret == reportSpam) {
0209             blog->reportUserAsSpam(currentAccount(), url.host());
0210             return;
0211         } else if (ret == openInBrowser) {
0212             Choqok::openUrl(currentAccount()->microblog()->profileUrl(currentAccount(), url.host()));
0213             return;
0214         } else if (ret == replyTo) {
0215             Q_EMIT reply(QStringLiteral("@%1").arg(url.host()), QString(), url.host());
0216             return;
0217         } else if (ret == dMessage) {
0218             blog->showDirectMessageDialog(account, url.host());
0219             return;
0220         }
0221         int type = ret->data().toInt();
0222         blog->searchBackend()->requestSearchResults(currentAccount(),
0223                 url.host(), type, QString(), Choqok::BehaviorSettings::countOfPosts());
0224     } else {
0225         TwitterApiPostWidget::checkAnchor(url);
0226     }
0227 }
0228 
0229 bool TwitterPostWidget::setupQuotedAvatar()
0230 {
0231     QPixmap pix = Choqok::MediaManager::self()->fetchImage(currentPost()->quotedPost.user.profileImageUrl,
0232                                                            Choqok::MediaManager::Async);
0233     if (!pix.isNull()) {
0234         quotedAvatarFetched(currentPost()->quotedPost.user.profileImageUrl, pix);
0235         return true;
0236     } else {
0237         connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched,
0238                 this, &TwitterPostWidget::quotedAvatarFetched);
0239         connect(Choqok::MediaManager::self(), &Choqok::MediaManager::fetchError,
0240                 this, &TwitterPostWidget::quotedAvatarFetchError);
0241         return false;
0242     }
0243 }
0244 
0245 void TwitterPostWidget::quotedAvatarFetched(const QUrl &remoteUrl, const QPixmap &pixmap)
0246 {
0247     if (remoteUrl == currentPost()->quotedPost.user.profileImageUrl) {
0248         _mainWidget->document()->addResource(QTextDocument::ImageResource, mQuotedAvatarResourceUrl, pixmap);
0249         disconnect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched,
0250                    this, &TwitterPostWidget::quotedAvatarFetched);
0251         disconnect(Choqok::MediaManager::self(), &Choqok::MediaManager::fetchError,
0252                    this, &TwitterPostWidget::quotedAvatarFetchError);
0253     }
0254 }
0255 
0256 void TwitterPostWidget::quotedAvatarFetchError(const QUrl &remoteUrl, const QString &errMsg)
0257 {
0258     Q_UNUSED(errMsg);
0259     if (remoteUrl == currentPost()->quotedPost.user.profileImageUrl) {
0260         ///Avatar fetching is failed! but will not disconnect to get the img if it fetches later!
0261         _mainWidget->document()->addResource(QTextDocument::ImageResource, mQuotedAvatarResourceUrl,
0262                                              QIcon::fromTheme(QLatin1String("image-missing")).pixmap(40));
0263     }
0264 }
0265 
0266 QString TwitterPostWidget::getBackgroundColor()
0267 {
0268     QString style = styleSheet();
0269     QLatin1String str{ "background-color:rgb(" };
0270     int idx = style.indexOf(str);
0271     if(idx != -1){
0272         idx += str.size();
0273         int endIdx = style.indexOf(QLatin1String(");"), idx);
0274         if( endIdx != -1 ){
0275             QStringList rgb = style.mid(idx, endIdx-idx).split(QLatin1Char(','));
0276             if( rgb.size() == 3 ){
0277                 return QStringLiteral("#%1%2%3").arg( rgb[0].toInt() - 20, 2, 16, QLatin1Char('0') )
0278                                                 .arg( rgb[1].toInt() - 20, 2, 16, QLatin1Char('0') )
0279                                                 .arg( rgb[2].toInt() - 20, 2, 16, QLatin1Char('0') );
0280             }
0281         }
0282     }
0283     
0284     return QLatin1String("#ffffff");
0285 }
0286 
0287 #include "moc_twitterpostwidget.cpp"