File indexing completed on 2024-05-05 04:57:14
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 "gnusocialapipostwidget.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 "notifymanager.h" 0020 #include "quickpost.h" 0021 0022 #include "twitterapiaccount.h" 0023 #include "twitterapimicroblog.h" 0024 #include "twitterapiwhoiswidget.h" 0025 0026 #include "gnusocialapiaccount.h" 0027 #include "gnusocialapiconversationtimelinewidget.h" 0028 #include "gnusocialapidebug.h" 0029 #include "gnusocialapimicroblog.h" 0030 #include "gnusocialapisearch.h" 0031 0032 const QRegExp GNUSocialApiPostWidget::mGroupRegExp(QLatin1String("([\\s]|^)!([a-z0-9]+){1,64}"), Qt::CaseInsensitive); 0033 const QRegExp GNUSocialApiPostWidget::mGNUSocialApiUserRegExp(QLatin1String("([\\s\\W]|^)@([a-z0-9_]+){1,64}(?!(@))"), Qt::CaseInsensitive); 0034 const QRegExp GNUSocialApiPostWidget::mGNUSocialApiHashRegExp(QLatin1String("([\\s]|^)#([\\w_\\.\\-]+)"), Qt::CaseInsensitive); 0035 0036 const QString subdomains = QLatin1String("(([a-z0-9-_]\\.)?)"); 0037 const QString dname = QLatin1String("(([a-z0-9-\\x0080-\\xFFFF]){1,63}\\.)+"); 0038 const QString zone = QLatin1String("((a[cdefgilmnoqrstuwxz])|(b[abdefghijlmnorstvwyz])|(c[acdfghiklmnoruvxyz])|(d[ejkmoz])|(e[ceghrstu])|\ 0039 (f[ijkmor])|(g[abdefghilmnpqrstuwy])|(h[kmnrtu])|(i[delmnoqrst])|(j[emop])|(k[eghimnprwyz])|(l[abcikrstuvy])|\ 0040 (m[acdefghklmnopqrstuvwxyz])|(n[acefgilopruz])|(om)|(p[aefghklnrstwy])|(qa)|(r[eosuw])|(s[abcdeghijklmnortuvyz])|\ 0041 (t[cdfghjkmnoprtvwz])|(u[agksyz])|(v[aceginu])|(w[fs])|(ye)|(z[amrw])\ 0042 |(asia|com|info|net|org|biz|name|pro|aero|cat|coop|edu|jobs|mobi|museum|tel|travel|gov|int|mil|local)|(中国)|(公司)|(网络)|(صر)|(امارات)|(рф))"); 0043 const QString domain = QLatin1Char('(') + subdomains + dname + zone + QLatin1Char(')'); 0044 const QRegExp GNUSocialApiPostWidget::mStatusNetUserRegExp(QLatin1String("([\\s\\W]|^)@(([a-z0-9]+){1,64}@") + domain + QLatin1Char(')'), Qt::CaseInsensitive); 0045 0046 class GNUSocialApiPostWidget::Private 0047 { 0048 public: 0049 Private(Choqok::Account *theAccount) 0050 { 0051 account = qobject_cast<GNUSocialApiAccount *>(theAccount); 0052 mBlog = qobject_cast<GNUSocialApiMicroBlog *>(account->microblog()); 0053 } 0054 GNUSocialApiAccount *account; 0055 GNUSocialApiMicroBlog *mBlog; 0056 QString tmpUsername; 0057 }; 0058 0059 GNUSocialApiPostWidget::GNUSocialApiPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) 0060 : TwitterApiPostWidget(account, post, parent), d(new Private(account)) 0061 { 0062 0063 } 0064 0065 void GNUSocialApiPostWidget::initUi() 0066 { 0067 TwitterApiPostWidget::initUi(); 0068 0069 QPushButton *btn = buttons().value(QLatin1String("btnResend")); 0070 0071 if (btn) { 0072 QMenu *menu = new QMenu(btn); 0073 QAction *resend = new QAction(i18n("Manual ReSend"), menu); 0074 connect(resend, &QAction::triggered, this, &GNUSocialApiPostWidget::slotResendPost); 0075 QAction *repeat = new QAction(i18n("Repeat"), menu); 0076 repeat->setToolTip(i18n("Repeat post using API")); 0077 connect(repeat, &QAction::triggered, this, &GNUSocialApiPostWidget::repeatPost); 0078 menu->addAction(repeat); 0079 menu->addAction(resend); 0080 btn->setMenu(menu); 0081 } 0082 } 0083 0084 GNUSocialApiPostWidget::~GNUSocialApiPostWidget() 0085 { 0086 delete d; 0087 } 0088 0089 void GNUSocialApiPostWidget::slotReplyToAll() 0090 { 0091 QStringList nicks; 0092 nicks.append(currentPost()->author.userName); 0093 0094 QString txt = QStringLiteral("@%1 ").arg(currentPost()->author.userName); 0095 0096 int pos = 0; 0097 while ((pos = mGNUSocialApiUserRegExp.indexIn(currentPost()->content, pos)) != -1) { 0098 if (mGNUSocialApiUserRegExp.cap(2).toLower() != currentAccount()->username() && 0099 mGNUSocialApiUserRegExp.cap(2).toLower() != currentPost()->author.userName && 0100 !nicks.contains(mGNUSocialApiUserRegExp.cap(2).toLower())) { 0101 nicks.append(mGNUSocialApiUserRegExp.cap(2)); 0102 txt += QStringLiteral("@%1 ").arg(mGNUSocialApiUserRegExp.cap(2)); 0103 } 0104 pos += mGNUSocialApiUserRegExp.matchedLength(); 0105 } 0106 0107 txt.chop(1); 0108 0109 Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName); 0110 } 0111 0112 QString GNUSocialApiPostWidget::prepareStatus(const QString &text) 0113 { 0114 QString res = TwitterApiPostWidget::prepareStatus(text); 0115 res.replace(mStatusNetUserRegExp, QLatin1String("\\1@<a href='user://\\2'>\\2</a>")); 0116 res.replace(mGNUSocialApiUserRegExp, QLatin1String("\\1@<a href='user://\\2'>\\2</a>")); 0117 res.replace(mGroupRegExp, QLatin1String("\\1!<a href='group://\\2'>\\2</a>")); 0118 res.replace(mGNUSocialApiHashRegExp, QLatin1String("\\1#<a href='tag://\\2'>\\2</a>")); 0119 0120 return res; 0121 } 0122 0123 QString GNUSocialApiPostWidget::generateSign() 0124 { 0125 return TwitterApiPostWidget::generateSign(); 0126 } 0127 0128 void GNUSocialApiPostWidget::checkAnchor(const QUrl &url) 0129 { 0130 QString scheme = url.scheme(); 0131 QAction *ret; 0132 if (scheme == QLatin1String("tag")) { 0133 QString unpcode = QUrl::fromAce(url.host().toUtf8()); 0134 unpcode.remove(QLatin1Char('.')); 0135 unpcode.remove(QLatin1Char('-')); 0136 unpcode.remove(QLatin1Char('_')); 0137 0138 QMenu menu; 0139 QAction *search = new QAction(QIcon::fromTheme(QLatin1String("system-search")), 0140 i18n("Search for %1", unpcode), &menu); 0141 QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("internet-services")), 0142 i18n("Open tag page in browser"), &menu); 0143 menu.addAction(search); 0144 menu.addAction(openInBrowser); 0145 menu.setDefaultAction(search); 0146 ret = menu.exec(QCursor::pos()); 0147 if (ret == search) { 0148 d->mBlog->searchBackend()->requestSearchResults(currentAccount(), 0149 unpcode, 0150 GNUSocialApiSearch::ReferenceHashtag); 0151 } else if (ret == openInBrowser) { 0152 Choqok::openUrl(QUrl(d->account->homepageUrl().toDisplayString() + 0153 QLatin1String("/tag/") + unpcode)); 0154 } 0155 } else if (scheme == QLatin1String("group")) { 0156 QMenu menu; 0157 QAction *search = new QAction(QIcon::fromTheme(QLatin1String("system-search")), 0158 i18n("Show latest group posts"), &menu); 0159 QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")), 0160 i18n("Open group page in browser"), &menu); 0161 menu.addAction(search); 0162 menu.addAction(openInBrowser); 0163 menu.setDefaultAction(search); 0164 ret = menu.exec(QCursor::pos()); 0165 if (ret == search) { 0166 d->mBlog->searchBackend()->requestSearchResults(currentAccount(), 0167 url.host(), 0168 GNUSocialApiSearch::ReferenceGroup); 0169 } else if (ret == openInBrowser) { 0170 Choqok::openUrl(QUrl(d->account->homepageUrl().toDisplayString() + 0171 QLatin1String("/group/") + url.host())); 0172 } 0173 } else if (scheme == QLatin1String("user")) { 0174 QString username = (url.userName().isEmpty() ? QString() : QStringLiteral("%1@").arg(url.userName())) + 0175 url.host(); 0176 QMenu menu; 0177 QAction *info = new QAction(QIcon::fromTheme(QLatin1String("user-identity")), i18nc("Who is user", "Who is %1", 0178 username), &menu); 0179 QAction *from = new QAction(QIcon::fromTheme(QLatin1String("edit-find-user")), i18nc("Posts from user", "Posts from %1", 0180 username), &menu); 0181 QAction *to = new QAction(QIcon::fromTheme(QLatin1String("meeting-attending")), i18nc("Replies to user", "Replies to %1", 0182 username), &menu); 0183 QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")), 0184 i18nc("Open profile page in browser", 0185 "Open profile in browser"), &menu); 0186 menu.addAction(info); 0187 if (currentPost()->source != QLatin1String("ostatus")) { 0188 menu.addAction(from); 0189 menu.addAction(to); 0190 from->setData(GNUSocialApiSearch::FromUser); 0191 to->setData(GNUSocialApiSearch::ToUser); 0192 } 0193 menu.addAction(openInBrowser); 0194 0195 //Subscribe/UnSubscribe/Block 0196 bool isSubscribe = false; 0197 QString accountUsername = d->account->username().toLower(); 0198 QString postUsername = username.toLower(); 0199 QAction *subscribe = nullptr, *block = nullptr, *replyTo = nullptr, *dMessage = nullptr; 0200 if (accountUsername != postUsername) { 0201 menu.addSeparator(); 0202 QMenu *actionsMenu = menu.addMenu(QIcon::fromTheme(QLatin1String("applications-system")), i18n("Actions")); 0203 replyTo = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18nc("Write a message to user attention", "Write to %1", 0204 username), actionsMenu); 0205 actionsMenu->addAction(replyTo); 0206 if (d->account->friendsList().contains(username)) { 0207 dMessage = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18nc("Send direct message to user", 0208 "Send private message to %1", 0209 username), actionsMenu); 0210 actionsMenu->addAction(dMessage); 0211 isSubscribe = false;//It's UnSubscribe 0212 subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-remove-user")), 0213 i18nc("Unsubscribe from user", 0214 "Unsubscribe from %1", username), actionsMenu); 0215 } else { 0216 isSubscribe = true; 0217 subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), 0218 i18nc("Subscribe to user", 0219 "Subscribe to %1", username), actionsMenu); 0220 } 0221 block = new QAction(QIcon::fromTheme(QLatin1String("dialog-cancel")), 0222 i18nc("Block user", 0223 "Block %1", username), actionsMenu); 0224 if (currentPost()->source != QLatin1String("ostatus")) { 0225 actionsMenu->addAction(subscribe); 0226 actionsMenu->addAction(block); 0227 } 0228 } 0229 ret = menu.exec(QCursor::pos()); 0230 if (ret == nullptr) { 0231 return; 0232 } 0233 if (ret == info) { 0234 TwitterApiWhoisWidget *wd = new TwitterApiWhoisWidget(d->account, username, *currentPost(), this); 0235 wd->show(QCursor::pos()); 0236 return; 0237 } else if (ret == subscribe) { 0238 if (isSubscribe) { 0239 d->mBlog->createFriendship(d->account, username); 0240 } else { 0241 d->mBlog->destroyFriendship(d->account, username); 0242 } 0243 return; 0244 } else if (ret == block) { 0245 d->mBlog->blockUser(d->account, username); 0246 return; 0247 } else if (ret == openInBrowser) { 0248 Choqok::openUrl(currentAccount()->microblog()->profileUrl(currentAccount(), username)); 0249 return; 0250 } else if (ret == replyTo) { 0251 Q_EMIT reply(QStringLiteral("@%1").arg(username), QString(), username); 0252 return; 0253 } else if (ret == dMessage) { 0254 d->mBlog->showDirectMessageDialog(d->account, username); 0255 return; 0256 } 0257 int type = ret->data().toInt(); 0258 d->mBlog->searchBackend()->requestSearchResults(currentAccount(), 0259 url.host(), 0260 type); 0261 } else if (scheme == QLatin1String("conversation")) { 0262 GNUSocialApiConversationTimelineWidget *tm = new GNUSocialApiConversationTimelineWidget(currentAccount(), 0263 url.host()); 0264 connect(tm, &GNUSocialApiConversationTimelineWidget::forwardReply, this, &GNUSocialApiPostWidget::reply); 0265 connect(tm, &GNUSocialApiConversationTimelineWidget::forwardResendPost, this, &GNUSocialApiPostWidget::resendPost); 0266 tm->show(); 0267 } else { 0268 TwitterApiPostWidget::checkAnchor(url); 0269 } 0270 } 0271 0272 void GNUSocialApiPostWidget::slotResendPost() 0273 { 0274 QString text = generateResendText(); 0275 0276 if (d->account->isChangeExclamationMark()) { 0277 int index = 0; 0278 while (true) { 0279 index = mGroupRegExp.indexIn(text, index); 0280 if (index != -1) { 0281 text.replace(index + 1, 1, d->account->changeExclamationMarkToText()); 0282 } else { 0283 break; 0284 } 0285 } 0286 } 0287 0288 if ((Choqok::BehaviorSettings::resendWithQuickPost() || currentAccount()->isReadOnly()) && 0289 Choqok::UI::Global::quickPostWidget()) { 0290 Choqok::UI::Global::quickPostWidget()->setText(text); 0291 } else { 0292 Q_EMIT resendPost(text); 0293 } 0294 }