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

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 "twitterapimicroblogwidget.h"
0010 
0011 #include <QAction>
0012 #include <QFont>
0013 #include <QIcon>
0014 #include <QMenu>
0015 #include <QPainter>
0016 #include <QRect>
0017 #include <QToolButton>
0018 
0019 #include <KLocalizedString>
0020 
0021 #include "account.h"
0022 #include "composerwidget.h"
0023 
0024 #include "twitterapiaccount.h"
0025 #include "twitterapidebug.h"
0026 #include "twitterapimicroblog.h"
0027 #include "twitterapisearchtimelinewidget.h"
0028 
0029 class TwitterApiMicroBlogWidget::Private
0030 {
0031 public:
0032     Private(Choqok::Account *acc)
0033         : btnCloseSearch(nullptr)
0034     {
0035         qCDebug(CHOQOK);
0036         mBlog = qobject_cast<TwitterApiMicroBlog *>(acc->microblog());
0037         this->account = qobject_cast<TwitterApiAccount *>(acc);
0038     }
0039     TwitterApiMicroBlog *mBlog;
0040     TwitterApiAccount *account;
0041     QToolButton *btnCloseSearch;
0042 };
0043 
0044 QIcon addTextToIcon(const QIcon &icon, const QString &text, const QSize &result_size , const QPalette &palette)
0045 {
0046     QIcon result;
0047 
0048     QPixmap pixmap = icon.pixmap(result_size);
0049     QPainter painter(&pixmap);
0050     QFont font;
0051     font.setWeight(result_size.height() / 3);
0052     font.setBold(true);
0053     painter.setFont(font);
0054 
0055     int textWidth = painter.fontMetrics().horizontalAdvance(text);
0056     QRect rct(0 , 0 , textWidth , result_size.height() / 2);
0057 
0058     painter.setRenderHint(QPainter::Antialiasing);
0059     painter.setPen(palette.color(QPalette::Active , QPalette::HighlightedText));
0060     painter.drawText(rct , Qt::AlignTop | Qt::AlignLeft , text);
0061 
0062     result.addPixmap(pixmap , QIcon::Active);
0063 
0064     return result;
0065 }
0066 
0067 TwitterApiMicroBlogWidget::TwitterApiMicroBlogWidget(Choqok::Account *account, QWidget *parent)
0068     : MicroBlogWidget(account, parent), d(new Private(account))
0069 {
0070     qCDebug(CHOQOK);
0071     connect(account, &Choqok::Account::modified, this, &TwitterApiMicroBlogWidget::slotAccountModified);
0072     connect(d->mBlog->searchBackend(), &TwitterApiSearch::searchResultsReceived,
0073             this, &TwitterApiMicroBlogWidget::slotSearchResultsReceived);
0074     connect(d->mBlog, &TwitterApiMicroBlog::saveTimelines, this,
0075             &TwitterApiMicroBlogWidget::saveSearchTimelinesState);
0076     loadSearchTimelinesState();
0077 }
0078 
0079 void TwitterApiMicroBlogWidget::initUi()
0080 {
0081     qCDebug(CHOQOK);
0082     Choqok::UI::MicroBlogWidget::initUi();
0083     connect(timelinesTabWidget(), (void (Choqok::UI::ChoqokTabBar::*)(QWidget*,const QPoint&))&Choqok::UI::ChoqokTabBar::contextMenu,
0084             this, &TwitterApiMicroBlogWidget::slotContextMenu);
0085 //     connect(timelinesTabWidget(), SIGNAL(currentChanged(int)), SLOT(slotCurrentTimelineChanged(int)) );
0086 //     d->btnCloseSearch->setIcon(QIcon::fromTheme("tab-close"));
0087 //     d->btnCloseSearch->setAutoRaise(true);
0088 //     d->btnCloseSearch->setToolTip(i18nc("Close a timeline", "Close Timeline"));
0089 //     d->btnCloseSearch->setFixedWidth( 32 );
0090 //     timelinesTabWidget()->setTabAlongsideWidget( d->btnCloseSearch );
0091 
0092 //     connect(d->btnCloseSearch, SIGNAL(clicked(bool)), SLOT(slotCloseCurrentSearch()) );
0093 //     slotCurrentTimelineChanged(timelinesTabWidget()->currentIndex());
0094 }
0095 
0096 TwitterApiMicroBlogWidget::~TwitterApiMicroBlogWidget()
0097 {
0098     delete d;
0099 }
0100 
0101 void TwitterApiMicroBlogWidget::slotSearchResultsReceived(const SearchInfo &info,
0102         QList< Choqok::Post * > &postsList)
0103 {
0104     qCDebug(CHOQOK);
0105     if (info.account == currentAccount()) {
0106         qCDebug(CHOQOK) << postsList.count();
0107         QString name = QStringLiteral("%1%2").arg(d->mBlog->searchBackend()->optionCode(info.option)).arg(info.query);
0108         if (mSearchTimelines.contains(name)) {
0109             mSearchTimelines.value(name)->addNewPosts(postsList);
0110         } else {
0111             if (postsList.isEmpty()) {
0112                 addSearchTimelineWidgetToUi(name, info)->addPlaceholderMessage(i18n("(The search result is empty.)"));
0113             } else {
0114                 addSearchTimelineWidgetToUi(name, info)->addNewPosts(postsList);
0115             }
0116         }
0117     }
0118 }
0119 
0120 TwitterApiSearchTimelineWidget *TwitterApiMicroBlogWidget::addSearchTimelineWidgetToUi(const QString &name,
0121         const SearchInfo &info)
0122 {
0123     qCDebug(CHOQOK);
0124     TwitterApiSearchTimelineWidget *mbw = d->mBlog->createSearchTimelineWidget(currentAccount(), name,
0125                                           info, this);
0126     if (mbw) {
0127         mbw->setObjectName(name);
0128         mSearchTimelines.insert(name, mbw);
0129         timelines().insert(name, mbw);
0130         timelinesTabWidget()->addTab(mbw, name);
0131         QString textToAdd = name;
0132         if (textToAdd.contains(QLatin1Char(':'))) {
0133             QStringList splitted = textToAdd.split(QLatin1Char(':'));
0134             textToAdd = splitted.first().at(0) + QLatin1Char(':') + splitted[1].left(3);
0135         } else {
0136             textToAdd = textToAdd.left(4);
0137         }
0138         QIcon icon = addTextToIcon(QIcon::fromTheme(QLatin1String("edit-find")), textToAdd, QSize(40, 40), palette());
0139         mbw->setTimelineIcon(icon);
0140         timelinesTabWidget()->setTabIcon(timelinesTabWidget()->indexOf(mbw), icon);
0141         connect(mbw, SIGNAL(updateUnreadCount(int)), this, SLOT(slotUpdateUnreadCount(int)));
0142         connect(mbw, &TwitterApiSearchTimelineWidget::closeMe, this, &TwitterApiMicroBlogWidget::slotCloseCurrentSearch);
0143         if (composer()) {
0144             connect(mbw, SIGNAL(forwardResendPost(QString)), composer(), SLOT(setText(QString)));
0145             connect(mbw, &TwitterApiSearchTimelineWidget::forwardReply, composer(), &Choqok::UI::ComposerWidget::setText);
0146         }
0147         timelinesTabWidget()->setCurrentWidget(mbw);
0148     } else {
0149         qCDebug(CHOQOK) << "Cannot Create a new TimelineWidget for timeline " << name;
0150         return nullptr;
0151     }
0152     if (timelinesTabWidget()->count() == 1) {
0153         timelinesTabWidget()->setTabBarHidden(true);
0154     } else {
0155         timelinesTabWidget()->setTabBarHidden(false);
0156     }
0157     return mbw;
0158 }
0159 
0160 void TwitterApiMicroBlogWidget::slotCloseCurrentSearch()
0161 {
0162     Choqok::UI::TimelineWidget *stw = qobject_cast<Choqok::UI::TimelineWidget *>(sender());
0163     if (!stw) {
0164         stw = qobject_cast<Choqok::UI::TimelineWidget *>(timelinesTabWidget()->currentWidget());
0165     }
0166     closeSearch(stw);
0167 }
0168 
0169 void TwitterApiMicroBlogWidget::slotAccountModified(Choqok::Account *account)
0170 {
0171     for (const QString &timeline: account->microblog()->timelineNames()) {
0172         if (account->timelineNames().contains(timeline)) {
0173             if (!timelines().contains(timeline)) {
0174                 addTimelineWidgetToUi(timeline);
0175             }
0176         } else if (timelines().contains(timeline)) {
0177             Choqok::UI::TimelineWidget *tm = timelines().take(timeline);
0178             tm->deleteLater();
0179         }
0180     }
0181 }
0182 
0183 void TwitterApiMicroBlogWidget::saveSearchTimelinesState()
0184 {
0185     qCDebug(CHOQOK);
0186     int count = currentAccount()->configGroup()->readEntry("SearchCount", 0);
0187     int i = 0;
0188     while (i < count) {
0189         currentAccount()->configGroup()->deleteEntry(QLatin1String("Search") + QString::number(i));
0190         ++i;
0191     }
0192     i = 0;
0193     for (TwitterApiSearchTimelineWidget *tm: mSearchTimelines.values()) {
0194         currentAccount()->configGroup()->writeEntry(QLatin1String("Search") + QString::number(i), tm->searchInfo().toString());
0195         ++i;
0196     }
0197     currentAccount()->configGroup()->writeEntry("SearchCount", i);
0198 }
0199 
0200 void TwitterApiMicroBlogWidget::loadSearchTimelinesState()
0201 {
0202     qCDebug(CHOQOK);
0203     int count = currentAccount()->configGroup()->readEntry(QLatin1String("SearchCount"), 0);
0204     int i = 0;
0205     while (i < count) {
0206         SearchInfo info;
0207         if (info.fromString(currentAccount()->configGroup()->readEntry(QLatin1String("Search") + QString::number(i), QString()))) {
0208             qobject_cast<TwitterApiMicroBlog *>(currentAccount()->microblog())->searchBackend()->requestSearchResults(info);
0209         }
0210         ++i;
0211     }
0212 }
0213 
0214 void TwitterApiMicroBlogWidget::slotContextMenu(QWidget *w, const QPoint &pt)
0215 {
0216     qCDebug(CHOQOK);
0217     Choqok::UI::TimelineWidget *sWidget = qobject_cast<Choqok::UI::TimelineWidget *>(w);
0218     QMenu menu;
0219     QAction *mar = nullptr;
0220     QAction *ac = nullptr;
0221     if (sWidget->unreadCount() > 0) {
0222         mar = new QAction(QIcon::fromTheme(QLatin1String("mail-mark-read")), i18n("Mark timeline as read"), &menu);
0223         menu.addAction(mar);
0224     }
0225     if (sWidget->isClosable()) {
0226         ac = new QAction(QIcon::fromTheme(QLatin1String("tab-close")), i18n("Close Timeline"), &menu);
0227         QAction *closeAll = new QAction(QIcon::fromTheme(QLatin1String("tab-close")), i18n("Close All"), &menu);
0228         connect(closeAll, &QAction::triggered, this, &TwitterApiMicroBlogWidget::closeAllSearches);
0229         menu.addAction(ac);
0230         menu.addAction(closeAll);
0231     }
0232     QAction *res = menu.exec(pt);
0233     if (ac && res == ac) {
0234         closeSearch(sWidget);
0235     } else if (res == mar) {
0236         sWidget->markAllAsRead();
0237     }
0238 }
0239 
0240 void TwitterApiMicroBlogWidget::closeSearch(Choqok::UI::TimelineWidget *searchWidget)
0241 {
0242     if (!searchWidget) {
0243         return;
0244     }
0245     searchWidget->markAllAsRead();
0246     TwitterApiSearchTimelineWidget *tst = qobject_cast<TwitterApiSearchTimelineWidget *>(searchWidget);
0247     timelinesTabWidget()->removePage(searchWidget);
0248     if (tst) {
0249         QString name = mSearchTimelines.key(tst);
0250         mSearchTimelines.value(name)->close();
0251         mSearchTimelines.remove(name);
0252         timelines().remove(name);
0253     } else {
0254         QStringList lst = d->account->timelineNames();
0255         lst.removeOne(searchWidget->timelineName());
0256         d->account->setTimelineNames(lst);
0257         d->account->writeConfig();
0258         timelines().remove(timelines().key(searchWidget));
0259         searchWidget->close();
0260     }
0261 }
0262 
0263 void TwitterApiMicroBlogWidget::closeAllSearches()
0264 {
0265     for (TwitterApiSearchTimelineWidget *searchWidget: mSearchTimelines.values()) {
0266         closeSearch(searchWidget);
0267     }
0268     for (Choqok::UI::TimelineWidget *widget: timelines().values()) {
0269         if (widget->isClosable()) {
0270             closeSearch(widget);
0271         }
0272     }
0273 }
0274 
0275 #include "moc_twitterapimicroblogwidget.cpp"