File indexing completed on 2025-02-16 10:49:23
0001 /* 0002 This file is part of Choqok, the KDE micro-blogging client 0003 0004 SPDX-FileCopyrightText: 2010-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 "filtermanager.h" 0010 0011 #include <QAction> 0012 #include <QTimer> 0013 0014 #include <KActionCollection> 0015 #include <KLocalizedString> 0016 #include <KMessageBox> 0017 #include <KPluginFactory> 0018 0019 #include "choqokuiglobal.h" 0020 #include "postwidget.h" 0021 #include "quickpost.h" 0022 #include "timelinewidget.h" 0023 0024 #include "twitterapiaccount.h" 0025 0026 #include "configurefilters.h" 0027 #include "filter.h" 0028 #include "filtersettings.h" 0029 0030 K_PLUGIN_CLASS_WITH_JSON(FilterManager, "choqok_filter.json") 0031 0032 FilterManager::FilterManager(QObject *parent, const QList<QVariant> &) 0033 : Choqok::Plugin(QLatin1String("choqok_filter"), parent), state(Stopped) 0034 { 0035 QAction *action = new QAction(i18n("Configure Filters..."), this); 0036 actionCollection()->addAction(QLatin1String("configureFilters"), action); 0037 connect(action, &QAction::triggered, this, &FilterManager::slotConfigureFilters); 0038 setXMLFile(QLatin1String("filterui.rc")); 0039 connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, 0040 this, &FilterManager::slotAddNewPostWidget); 0041 0042 hidePost = new QAction(i18n("Hide Post"), this); 0043 Choqok::UI::PostWidget::addAction(hidePost); 0044 connect(hidePost, &QAction::triggered, this, &FilterManager::slotHidePost); 0045 } 0046 0047 FilterManager::~FilterManager() 0048 { 0049 0050 } 0051 0052 void FilterManager::slotAddNewPostWidget(Choqok::UI::PostWidget *newWidget) 0053 { 0054 postsQueue.enqueue(newWidget); 0055 if (state == Stopped) { 0056 state = Running; 0057 QTimer::singleShot(1000, this, SLOT(startParsing())); 0058 } 0059 } 0060 0061 void FilterManager::startParsing() 0062 { 0063 int i = 8; 0064 while (!postsQueue.isEmpty() && i > 0) { 0065 parse(postsQueue.dequeue()); 0066 --i; 0067 } 0068 0069 if (postsQueue.isEmpty()) { 0070 state = Stopped; 0071 } else { 0072 QTimer::singleShot(500, this, SLOT(startParsing())); 0073 } 0074 } 0075 0076 void FilterManager::parse(Choqok::UI::PostWidget *postToParse) 0077 { 0078 if (!postToParse || 0079 postToParse->currentPost()->author.userName == postToParse->currentAccount()->username() || 0080 postToParse->isRead()) { 0081 return; 0082 } 0083 0084 if (parseSpecialRules(postToParse)) { 0085 return; 0086 } 0087 0088 if (!postToParse) { 0089 return; 0090 } 0091 //qDebug() << "Processing: "<<postToParse->content(); 0092 for (Filter *filter: FilterSettings::self()->filters()) { 0093 if (filter->filterText().isEmpty()) { 0094 return; 0095 } 0096 if (filter->filterAction() == Filter::Remove && filter->dontHideReplies() && 0097 (postToParse->currentPost()->replyToUser.userName.compare(postToParse->currentAccount()->username(), 0098 Qt::CaseInsensitive) == 0 || 0099 postToParse->currentPost()->content.contains(QStringLiteral("@%1").arg(postToParse->currentAccount()->username()))) 0100 ) { 0101 continue; 0102 } 0103 switch (filter->filterField()) { 0104 case Filter::Content: 0105 doFiltering(postToParse, filterText(postToParse->currentPost()->content, filter)); 0106 break; 0107 case Filter::AuthorUsername: 0108 doFiltering(postToParse, filterText(postToParse->currentPost()->author.userName, filter)); 0109 break; 0110 case Filter::ReplyToUsername: 0111 doFiltering(postToParse, filterText(postToParse->currentPost()->replyToUser.userName, filter)); 0112 break; 0113 case Filter::Source: 0114 doFiltering(postToParse, filterText(postToParse->currentPost()->source, filter)); 0115 break; 0116 default: 0117 break; 0118 }; 0119 } 0120 } 0121 0122 Filter::FilterAction FilterManager::filterText(const QString &textToCheck, Filter *filter) 0123 { 0124 bool filtered = false; 0125 switch (filter->filterType()) { 0126 case Filter::ExactMatch: 0127 if (textToCheck.compare(filter->filterText(), Qt::CaseInsensitive) == 0) { 0128 //qDebug() << "ExactMatch:" << filter->filterText(); 0129 filtered = true; 0130 } 0131 break; 0132 case Filter::RegExp: 0133 if (textToCheck.contains(QRegExp(filter->filterText()))) { 0134 //qDebug() << "RegExp:" << filter->filterText(); 0135 filtered = true; 0136 } 0137 break; 0138 case Filter::Contain: 0139 if (textToCheck.contains(filter->filterText(), Qt::CaseInsensitive)) { 0140 //qDebug() << "Contain:" << filter->filterText(); 0141 filtered = true; 0142 } 0143 break; 0144 case Filter::DoesNotContain: 0145 if (!textToCheck.contains(filter->filterText(), Qt::CaseInsensitive)) { 0146 //qDebug() << "DoesNotContain:" << filter->filterText(); 0147 filtered = true; 0148 } 0149 break; 0150 default: 0151 break; 0152 } 0153 if (filtered) { 0154 return filter->filterAction(); 0155 } else { 0156 return Filter::None; 0157 } 0158 } 0159 0160 void FilterManager::doFiltering(Choqok::UI::PostWidget *postToFilter, Filter::FilterAction action) 0161 { 0162 QString css; 0163 switch (action) { 0164 case Filter::Remove: 0165 //qDebug() << "Post removed:" << postToFilter->currentPost()->content; 0166 postToFilter->close(); 0167 break; 0168 case Filter::Highlight: 0169 css = postToFilter->styleSheet(); 0170 css.replace(QLatin1String("border: 1px solid rgb(150,150,150)"), QLatin1String("border: 2px solid rgb(255,0,0)")); 0171 postToFilter->setStyleSheet(css); 0172 break; 0173 case Filter::None: 0174 default: 0175 //Do nothing 0176 break; 0177 } 0178 } 0179 0180 void FilterManager::slotConfigureFilters() 0181 { 0182 QPointer<ConfigureFilters> dlg = new ConfigureFilters(Choqok::UI::Global::mainWindow()); 0183 dlg->show(); 0184 } 0185 0186 bool FilterManager::parseSpecialRules(Choqok::UI::PostWidget *postToParse) 0187 { 0188 if (FilterSettings::hideRepliesNotRelatedToMe()) { 0189 if (!postToParse->currentPost()->replyToUser.userName.isEmpty() && 0190 postToParse->currentPost()->replyToUser.userName != postToParse->currentAccount()->username()) { 0191 if (!postToParse->currentPost()->content.contains(postToParse->currentAccount()->username())) { 0192 postToParse->close(); 0193 // qDebug() << "NOT RELATE TO ME FILTERING......"; 0194 return true; 0195 } 0196 } 0197 } 0198 0199 if (FilterSettings::hideNoneFriendsReplies()) { 0200 TwitterApiAccount *acc = qobject_cast<TwitterApiAccount *>(postToParse->currentAccount()); 0201 if (!acc) { 0202 return false; 0203 } 0204 if (!postToParse->currentPost()->replyToUser.userName.isEmpty() && 0205 !acc->friendsList().contains(postToParse->currentPost()->replyToUser.userName)) { 0206 if (!postToParse->currentPost()->content.contains(postToParse->currentAccount()->username())) { 0207 postToParse->close(); 0208 // qDebug() << "NONE FRIEND FILTERING......"; 0209 return true; 0210 } 0211 } 0212 } 0213 0214 return false; 0215 } 0216 0217 void FilterManager::slotHidePost() 0218 { 0219 Choqok::UI::PostWidget *wd; 0220 wd = dynamic_cast<Choqok::UI::PostWidgetUserData *>(hidePost->userData(32))->postWidget(); 0221 QString username = wd->currentPost()->author.userName; 0222 int res = KMessageBox::questionYesNoCancel(choqokMainWindow, i18n("Hide all posts from <b>@%1</b>?", 0223 username)); 0224 if (res == KMessageBox::Cancel) { 0225 return; 0226 } else if (res == KMessageBox::Yes) { 0227 Filter *fil = new Filter(username, Filter::AuthorUsername, Filter::ExactMatch); 0228 fil->writeConfig(); 0229 QList<Filter *> filterList = FilterSettings::self()->filters(); 0230 filterList.append(fil); 0231 FilterSettings::self()->setFilters(filterList); 0232 Choqok::UI::TimelineWidget *tm = wd->timelineWidget(); 0233 if (tm) { 0234 // qDebug() << "Closing all posts"; 0235 for (Choqok::UI::PostWidget *pw: tm->postWidgets()) { 0236 if (pw->currentPost()->author.userName == username) { 0237 pw->close(); 0238 } 0239 } 0240 } else { 0241 wd->close(); 0242 } 0243 } else { 0244 wd->close(); 0245 } 0246 } 0247 0248 #include "filtermanager.moc" 0249 #include "moc_filtermanager.cpp"