File indexing completed on 2024-06-09 04:25:09
0001 /* 0002 * SPDX-FileCopyrightText: 2018 boud <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "KisNewsWidget.h" 0007 0008 #include <QDesktopServices> 0009 #include <QUrl> 0010 #include <QPainter> 0011 #include <QStyleOptionViewItem> 0012 #include <QModelIndex> 0013 #include <QTextDocument> 0014 #include <QAbstractTextDocumentLayout> 0015 #include <QRegularExpression> 0016 #include <QScrollBar> 0017 0018 #include "kis_config.h" 0019 #include "KisMultiFeedRSSModel.h" 0020 #include <KisKineticScroller.h> 0021 0022 KisNewsDelegate::KisNewsDelegate(QObject *parent) 0023 : QStyledItemDelegate(parent) 0024 { 0025 } 0026 0027 void KisNewsDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 0028 { 0029 painter->save(); 0030 0031 QStyleOptionViewItem optionCopy = option; 0032 initStyleOption(&optionCopy, index); 0033 0034 QStyle *style = optionCopy.widget? optionCopy.widget->style() : QApplication::style(); 0035 0036 QTextDocument doc; 0037 doc.setDocumentMargin(6); 0038 doc.setHtml(optionCopy.text); 0039 doc.setTextWidth(optionCopy.rect.width()); 0040 0041 /// Painting item without text 0042 optionCopy.text = QString(); 0043 style->drawControl(QStyle::CE_ItemViewItem, &optionCopy, painter); 0044 0045 QAbstractTextDocumentLayout::PaintContext ctx; 0046 0047 // Highlighting text if item is selected 0048 QColor textColor; 0049 if (optionCopy.state & QStyle::State_Selected) { 0050 textColor = optionCopy.palette.color(QPalette::Active, QPalette::HighlightedText); 0051 } else { 0052 textColor = optionCopy.palette.color(QPalette::Text); 0053 } 0054 ctx.palette.setColor(QPalette::Text, textColor); 0055 0056 painter->translate(optionCopy.rect.left(), optionCopy.rect.top()); 0057 QRect clip(0, 0, optionCopy.rect.width(), optionCopy.rect.height()); 0058 ctx.clip = clip; 0059 doc.setPageSize(clip.size()); 0060 doc.documentLayout()->draw(painter, ctx); 0061 0062 painter->restore(); 0063 } 0064 0065 QSize KisNewsDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 0066 { 0067 QStyleOptionViewItem optionCopy = option; 0068 initStyleOption(&optionCopy, index); 0069 0070 QTextDocument doc; 0071 doc.setDocumentMargin(6); 0072 doc.setHtml(optionCopy.text); 0073 doc.setTextWidth(optionCopy.rect.width()); 0074 return QSize(doc.idealWidth(), doc.size().height()); 0075 } 0076 0077 KisNewsWidget::KisNewsWidget(QWidget *parent) 0078 : QWidget(parent) 0079 , m_getNews(false) 0080 , m_rssModel(0) 0081 { 0082 setupUi(this); 0083 listNews->viewport()->setAutoFillBackground(false); 0084 listNews->installEventFilter(this); 0085 listNews->setVerticalScrollMode(QListView::ScrollPerPixel); 0086 listNews->verticalScrollBar()->setSingleStep(50); 0087 { 0088 QScroller* scroller = KisKineticScroller::createPreconfiguredScroller(listNews); 0089 if (scroller) { 0090 connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); 0091 } 0092 } 0093 0094 m_rssModel = new MultiFeedRssModel(this); 0095 connect(m_rssModel, SIGNAL(feedDataChanged()), this, SLOT(rssDataChanged()), Qt::UniqueConnection); 0096 0097 listNews->setModel(m_rssModel); 0098 listNews->setItemDelegate(new KisNewsDelegate(listNews)); 0099 connect(listNews, SIGNAL(clicked(QModelIndex)), this, SLOT(itemSelected(QModelIndex))); 0100 } 0101 0102 void KisNewsWidget::setAnalyticsTracking(QString text) 0103 { 0104 m_analyticsTrackingParameters = text; 0105 } 0106 0107 bool KisNewsWidget::eventFilter(QObject *watched, QEvent *event) 0108 { 0109 if (watched == listNews && event->type() == QEvent::Leave) { 0110 listNews->clearSelection(); 0111 listNews->setCurrentIndex(QModelIndex()); 0112 } 0113 return QWidget::eventFilter(watched, event); 0114 } 0115 0116 void KisNewsWidget::toggleNewsLanguage(QString langCode, bool enabled) 0117 { 0118 // Sanity check: Since the code is adding the language code directly into 0119 // the URL, this prevents any nasty surprises with malformed URLs. 0120 Q_FOREACH(const char &ch, langCode.toLatin1()) { 0121 bool isValidChar = (ch >= 'a' && ch <= 'z') || ch == '-'; 0122 if (!isValidChar) { 0123 warnUI << "Ignoring attempt to toggle malformed news lang:" << langCode; 0124 return; 0125 } 0126 } 0127 0128 QString feed = QStringLiteral("https://krita.org/%1/feed/").arg(langCode); 0129 if (enabled) { 0130 m_enabledFeeds.insert(feed); 0131 if (m_getNews) { 0132 m_rssModel->addFeed(feed); 0133 } 0134 } else { 0135 m_enabledFeeds.remove(feed); 0136 if (m_getNews) { 0137 m_rssModel->removeFeed(feed); 0138 } 0139 } 0140 } 0141 0142 void KisNewsWidget::toggleNews(bool toggle) 0143 { 0144 m_getNews = toggle; 0145 0146 KisConfig cfg(false); 0147 cfg.writeEntry<bool>("FetchNews", toggle); 0148 0149 Q_FOREACH(const QString &feed, m_enabledFeeds) { 0150 if (toggle) { 0151 m_rssModel->addFeed(feed); 0152 } else { 0153 m_rssModel->removeFeed(feed); 0154 } 0155 } 0156 } 0157 0158 void KisNewsWidget::itemSelected(const QModelIndex &idx) 0159 { 0160 if (idx.isValid()) { 0161 QString link = idx.data(KisRssReader::RssRoles::LinkRole).toString(); 0162 0163 // append query string for analytics tracking if we set it 0164 if (m_analyticsTrackingParameters != "") { 0165 0166 // use title in analytics query string 0167 QString linkTitle = idx.data(KisRssReader::RssRoles::TitleRole).toString(); 0168 linkTitle = linkTitle.simplified(); // trims and makes 1 white space 0169 linkTitle = linkTitle.replace(" ", ""); 0170 0171 m_analyticsTrackingParameters = m_analyticsTrackingParameters.append(linkTitle); 0172 QDesktopServices::openUrl(QUrl(link.append(m_analyticsTrackingParameters))); 0173 0174 } else { 0175 QDesktopServices::openUrl(QUrl(link)); 0176 } 0177 0178 0179 } 0180 } 0181 0182 void KisNewsWidget::rssDataChanged() 0183 { 0184 emit newsDataChanged(); 0185 } 0186