1 /*
2     SPDX-FileCopyrightText: 2008 Joris Guisson <joris.guisson@gmail.com>
3     SPDX-FileCopyrightText: 2008 Ivan Vasic <ivasic@gmail.com>
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include <QApplication>
8 #include <QColor>
9 #include <QHeaderView>
10 #include <QInputDialog>
11 #include <QLocale>
12 #include <QPalette>
13 
14 #include <KRun>
15 
16 #include "feedwidget.h"
17 #include "feedwidgetmodel.h"
18 #include "filterlist.h"
19 #include "ktfeed.h"
20 #include "managefiltersdlg.h"
21 #include "syndicationplugin.h"
22 #include <util/log.h>
23 
24 using namespace bt;
25 
26 namespace kt
27 {
28 QString FeedWidget::item_template = i18n(
29     "\
30     <html>\
31     <body style=\"color:%4\">\
32     <div style=\"border-style:solid; border-width:1px; border-color:%4; margin:5px; padding:5px\">\
33     <b>Title:</b> %1<br/>\
34     <b>Date:</b> %2<br/>\
35     </div>\
36     <p>%3</p>\
37     </body>\
38     </html>\
39     ");
40 
FeedWidget(FilterList * filters,SyndicationActivity * act,QWidget * parent)41 FeedWidget::FeedWidget(FilterList *filters, SyndicationActivity *act, QWidget *parent)
42     : QWidget(parent)
43     , feed(nullptr)
44     , filters(filters)
45     , act(act)
46 {
47     setupUi(this);
48     m_splitter->setStretchFactor(0, 3);
49     m_splitter->setStretchFactor(1, 1);
50 
51     connect(m_download, &QPushButton::clicked, this, &FeedWidget::downloadClicked);
52     connect(m_refresh, &QPushButton::clicked, this, &FeedWidget::refreshClicked);
53     connect(m_filters, &QPushButton::clicked, this, &FeedWidget::filtersClicked);
54     connect(m_refresh_rate, qOverload<int>(&QSpinBox::valueChanged), this, &FeedWidget::refreshRateChanged);
55     connect(m_cookies, &QPushButton::clicked, this, &FeedWidget::cookiesClicked);
56 
57     m_refresh->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
58     m_filters->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
59     m_cookies->setIcon(QIcon::fromTheme(QStringLiteral("preferences-web-browser-cookies")));
60     m_download->setIcon(QIcon::fromTheme(QStringLiteral("ktorrent")));
61 
62     model = new FeedWidgetModel(this);
63     m_item_list->setModel(model);
64     m_item_list->setAlternatingRowColors(true);
65     m_item_list->setSelectionMode(QAbstractItemView::ExtendedSelection);
66 
67     QHeaderView *hv = m_item_list->header();
68     hv->setSectionResizeMode(QHeaderView::Interactive);
69     connect(m_item_list->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FeedWidget::selectionChanged);
70 
71     m_download->setEnabled(false);
72     m_url->clear();
73     m_refresh_rate->clear();
74     m_active_filters->clear();
75 
76     m_item_view->setEnabled(false);
77 
78     setEnabled(false);
79 }
80 
~FeedWidget()81 FeedWidget::~FeedWidget()
82 {
83 }
84 
loadState(KConfigGroup & g)85 void FeedWidget::loadState(KConfigGroup &g)
86 {
87     m_splitter->restoreState(g.readEntry("feed_widget_splitter", QByteArray()));
88 
89     QHeaderView *hv = m_item_list->header();
90     QByteArray state = g.readEntry("feed_widget_list_header", QByteArray());
91     if (!state.isEmpty())
92         hv->restoreState(state);
93     else
94         QTimer::singleShot(3000, this, &FeedWidget::resizeColumns);
95 }
96 
saveState(KConfigGroup & g)97 void FeedWidget::saveState(KConfigGroup &g)
98 {
99     g.writeEntry("feed_widget_splitter", m_splitter->saveState());
100     QHeaderView *hv = m_item_list->header();
101     g.writeEntry("feed_widget_list_header", hv->saveState());
102 }
103 
resizeColumns()104 void FeedWidget::resizeColumns()
105 {
106     m_item_list->header()->resizeSections(QHeaderView::ResizeToContents);
107 }
108 
setFeed(Feed * f)109 void FeedWidget::setFeed(Feed *f)
110 {
111     if (feed) {
112         disconnect(feed, &Feed::updated, this, &FeedWidget::updated);
113         disconnect(feed, &Feed::feedRenamed, this, &FeedWidget::onFeedRenamed);
114         feed = nullptr;
115     }
116 
117     feed = f;
118     setEnabled(feed != nullptr);
119     model->setCurrentFeed(f);
120     if (feed) {
121         connect(feed, &Feed::updated, this, &FeedWidget::updated);
122         connect(feed, &Feed::feedRenamed, this, &FeedWidget::onFeedRenamed);
123 
124         m_url->setText(QStringLiteral("<b>%1</b>").arg(feed->feedUrl().toDisplayString()));
125         m_refresh_rate->setValue(feed->refreshRate());
126         updated();
127         selectionChanged(m_item_list->selectionModel()->selection(), QItemSelection());
128     }
129 }
130 
downloadClicked()131 void FeedWidget::downloadClicked()
132 {
133     if (!feed)
134         return;
135 
136     const QModelIndexList sel = m_item_list->selectionModel()->selectedRows();
137     for (const QModelIndex &idx : sel) {
138         Syndication::ItemPtr ptr = model->itemForIndex(idx);
139         if (ptr)
140             feed->downloadItem(ptr, QString(), QString(), QString(), false);
141     }
142 }
143 
refreshClicked()144 void FeedWidget::refreshClicked()
145 {
146     if (feed)
147         feed->refresh();
148 }
149 
refreshRateChanged(int v)150 void FeedWidget::refreshRateChanged(int v)
151 {
152     if (v > 0 && feed)
153         feed->setRefreshRate(v);
154 }
155 
filtersClicked()156 void FeedWidget::filtersClicked()
157 {
158     if (!feed)
159         return;
160 
161     ManageFiltersDlg dlg(feed, filters, act, this);
162     if (dlg.exec() == QDialog::Accepted) {
163         feed->save();
164         feed->runFilters();
165     }
166 }
167 
cookiesClicked()168 void FeedWidget::cookiesClicked()
169 {
170     if (!feed)
171         return;
172 
173     bool ok = false;
174     QString cookie = feed->authenticationCookie();
175     QString nc = QInputDialog::getText(nullptr, i18n("Authentication Cookie"), i18n("Enter the new authentication cookie"), QLineEdit::Normal, cookie, &ok);
176     if (ok) {
177         feed->setAuthenticationCookie(nc);
178         feed->save();
179     }
180 }
181 
selectionChanged(const QItemSelection & sel,const QItemSelection & prev)182 void FeedWidget::selectionChanged(const QItemSelection &sel, const QItemSelection &prev)
183 {
184     Q_UNUSED(prev);
185     m_download->setEnabled(sel.count() > 0);
186     m_item_view->setEnabled(sel.count() > 0);
187     if (sel.count() > 0 && feed) {
188         Syndication::ItemPtr item = model->itemForIndex(m_item_list->selectionModel()->selectedRows().front());
189         if (item) {
190             m_item_view->setHtml(item_template.arg(item->title())
191                                      .arg(QLocale().toString(QDateTime::fromTime_t(item->datePublished()), QLocale::ShortFormat))
192                                      .arg(item->description())
193                                      .arg(QApplication::palette().text().color().name(QColor::NameFormat::HexRgb)),
194                                  QUrl(feed->feedData()->link()));
195         }
196     }
197 }
198 
updated()199 void FeedWidget::updated()
200 {
201     if (!feed)
202         return;
203 
204     switch (feed->feedStatus()) {
205     case Feed::OK:
206         m_status->setText(i18n("<b>OK</b>"));
207         break;
208     case Feed::UNLOADED:
209         m_status->setText(i18n("<b>Not Loaded</b>"));
210         break;
211     case Feed::FAILED_TO_DOWNLOAD:
212         m_status->setText(i18n("<b>Download Failed: %1</b>", feed->errorString()));
213         break;
214     case Feed::DOWNLOADING:
215         m_status->setText(i18n("<b>Downloading</b>"));
216         break;
217     }
218     updateCaption(this, feed->title());
219     m_active_filters->setText(QStringLiteral("<b>") + feed->filterNamesString() + QStringLiteral("</b>"));
220 }
221 
onFeedRenamed(kt::Feed * f)222 void FeedWidget::onFeedRenamed(kt::Feed *f)
223 {
224     updateCaption(this, f->displayName());
225 }
226 
227 }
228