]> git.sur5r.net Git - minitube/blob - src/channelview.cpp
Upload 3.9.3-2 to unstable
[minitube] / src / channelview.cpp
1 /* $BEGIN_LICENSE
2
3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
5
6 Minitube is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Minitube is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Minitube.  If not, see <http://www.gnu.org/licenses/>.
18
19 $END_LICENSE */
20
21 #include "channelview.h"
22 #include "aggregatevideosource.h"
23 #include "channelaggregator.h"
24 #include "channelitemdelegate.h"
25 #include "channelmodel.h"
26 #include "database.h"
27 #include "iconutils.h"
28 #include "mainwindow.h"
29 #include "searchparams.h"
30 #include "ytchannel.h"
31 #include "ytsearch.h"
32 #ifdef APP_EXTRA
33 #include "extra.h"
34 #endif
35 #include "channellistview.h"
36
37 namespace {
38 const QString sortByKey = "subscriptionsSortBy";
39 const QString showUpdatedKey = "subscriptionsShowUpdated";
40 } // namespace
41
42 ChannelView::ChannelView(QWidget *parent) : View(parent), showUpdated(false), sortBy(SortByName) {
43     QBoxLayout *layout = new QVBoxLayout(this);
44     layout->setMargin(0);
45     layout->setSpacing(0);
46
47     listView = new ChannelListView();
48     listView->setItemDelegate(new ChannelItemDelegate(this));
49
50     channelsModel = new ChannelModel(this);
51     listView->setModel(channelsModel);
52
53     connect(listView, SIGNAL(clicked(const QModelIndex &)),
54             SLOT(itemActivated(const QModelIndex &)));
55     connect(listView, SIGNAL(contextMenu(QPoint)), SLOT(showContextMenu(QPoint)));
56     connect(listView, SIGNAL(viewportEntered()), channelsModel, SLOT(clearHover()));
57
58     layout->addWidget(listView);
59
60     setupActions();
61
62     connect(ChannelAggregator::instance(), SIGNAL(channelChanged(YTChannel *)), channelsModel,
63             SLOT(updateChannel(YTChannel *)));
64     connect(ChannelAggregator::instance(), SIGNAL(unwatchedCountChanged(int)),
65             SLOT(unwatchedCountChanged(int)));
66
67     unwatchedCountChanged(ChannelAggregator::instance()->getUnwatchedCount());
68 }
69
70 void ChannelView::setupActions() {
71     QSettings settings;
72
73     sortBy = static_cast<SortBy>(settings.value(sortByKey, SortByName).toInt());
74
75     QMenu *sortMenu = new QMenu(this);
76     QActionGroup *sortGroup = new QActionGroup(this);
77
78     QAction *sortByNameAction = new QAction(tr("Name"), this);
79     sortByNameAction->setActionGroup(sortGroup);
80     sortByNameAction->setCheckable(true);
81     if (sortBy == SortByName) sortByNameAction->setChecked(true);
82     connect(sortByNameAction, SIGNAL(triggered()), SLOT(setSortByName()));
83     sortMenu->addAction(sortByNameAction);
84
85     QAction *sortByUpdatedAction = new QAction(tr("Last Updated"), this);
86     sortByUpdatedAction->setActionGroup(sortGroup);
87     sortByUpdatedAction->setCheckable(true);
88     if (sortBy == SortByUpdated) sortByUpdatedAction->setChecked(true);
89     connect(sortByUpdatedAction, SIGNAL(triggered()), SLOT(setSortByUpdated()));
90     sortMenu->addAction(sortByUpdatedAction);
91
92     QAction *sortByAddedAction = new QAction(tr("Last Added"), this);
93     sortByAddedAction->setActionGroup(sortGroup);
94     sortByAddedAction->setCheckable(true);
95     if (sortBy == SortByAdded) sortByAddedAction->setChecked(true);
96     connect(sortByAddedAction, SIGNAL(triggered()), SLOT(setSortByAdded()));
97     sortMenu->addAction(sortByAddedAction);
98
99     QAction *sortByLastWatched = new QAction(tr("Last Watched"), this);
100     sortByLastWatched->setActionGroup(sortGroup);
101     sortByLastWatched->setCheckable(true);
102     if (sortBy == SortByLastWatched) sortByLastWatched->setChecked(true);
103     connect(sortByLastWatched, SIGNAL(triggered()), SLOT(setSortByLastWatched()));
104     sortMenu->addAction(sortByLastWatched);
105
106     QAction *sortByMostWatched = new QAction(tr("Most Watched"), this);
107     sortByMostWatched->setActionGroup(sortGroup);
108     sortByMostWatched->setCheckable(true);
109     if (sortBy == SortByMostWatched) sortByMostWatched->setChecked(true);
110     connect(sortByMostWatched, SIGNAL(triggered()), SLOT(setSortByMostWatched()));
111     sortMenu->addAction(sortByMostWatched);
112
113     QToolButton *sortButton = new QToolButton(this);
114     sortButton->setText(tr("Sort by"));
115     IconUtils::setIcon(sortButton, "sort");
116     sortButton->setIconSize(QSize(16, 16));
117     sortButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
118     sortButton->setPopupMode(QToolButton::InstantPopup);
119     sortButton->setMenu(sortMenu);
120     QWidgetAction *widgetAction = new QWidgetAction(this);
121     widgetAction->setDefaultWidget(sortButton);
122     widgetAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_O));
123     statusActions << widgetAction;
124
125     markAsWatchedAction = new QAction(tr("Mark all as watched"), this);
126     IconUtils::setIcon(markAsWatchedAction, "mark-watched");
127     markAsWatchedAction->setEnabled(false);
128     markAsWatchedAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_W));
129     connect(markAsWatchedAction, SIGNAL(triggered()), SLOT(markAllAsWatched()));
130     statusActions << markAsWatchedAction;
131
132     showUpdated = settings.value(showUpdatedKey, false).toBool();
133     QAction *showUpdatedAction = new QAction(tr("Show Updated"), this);
134     IconUtils::setIcon(showUpdatedAction, "show-updated");
135     showUpdatedAction->setCheckable(true);
136     showUpdatedAction->setChecked(showUpdated);
137     showUpdatedAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_U));
138     connect(showUpdatedAction, SIGNAL(toggled(bool)), SLOT(toggleShowUpdated(bool)));
139     statusActions << showUpdatedAction;
140
141     for (QAction *action : statusActions) {
142         window()->addAction(action);
143         MainWindow::instance()->setupAction(action);
144     }
145 }
146
147 QString ChannelView::noSubscriptionsMessage() {
148     return tr("You have no subscriptions. "
149               "Use the star symbol to subscribe to channels.");
150 }
151
152 void ChannelView::appear() {
153     updateQuery();
154     MainWindow::instance()->showActionsInStatusBar(statusActions, true);
155     setFocus();
156     ChannelAggregator::instance()->start();
157 }
158
159 void ChannelView::disappear() {
160     MainWindow::instance()->showActionsInStatusBar(statusActions, false);
161 }
162
163 void ChannelView::itemActivated(const QModelIndex &index) {
164     ChannelModel::ItemTypes itemType = channelsModel->typeForIndex(index);
165     if (itemType == ChannelModel::ItemChannel) {
166         YTChannel *channel = channelsModel->channelForIndex(index);
167         SearchParams *params = new SearchParams();
168         params->setChannelId(channel->getChannelId());
169         params->setSortBy(SearchParams::SortByNewest);
170         params->setTransient(true);
171         YTSearch *videoSource = new YTSearch(params);
172         videoSource->setAsyncDetails(true);
173         emit activated(videoSource);
174         channel->updateWatched();
175     } else if (itemType == ChannelModel::ItemAggregate) {
176         AggregateVideoSource *videoSource = new AggregateVideoSource();
177         videoSource->setName(tr("All Videos"));
178         emit activated(videoSource);
179     } else if (itemType == ChannelModel::ItemUnwatched) {
180         AggregateVideoSource *videoSource = new AggregateVideoSource();
181         videoSource->setName(tr("Unwatched Videos"));
182         videoSource->setUnwatched(true);
183         emit activated(videoSource);
184     }
185 }
186
187 void ChannelView::showContextMenu(const QPoint &point) {
188     const QModelIndex index = listView->indexAt(point);
189     if (!index.isValid()) return;
190
191     YTChannel *channel = channelsModel->channelForIndex(index);
192     if (!channel) return;
193
194     unsetCursor();
195
196     QMenu menu;
197
198     if (channel->getNotifyCount() > 0) {
199         QAction *markAsWatchedAction =
200                 menu.addAction(tr("Mark as Watched"), channel, SLOT(updateWatched()));
201         connect(markAsWatchedAction, SIGNAL(triggered()), ChannelAggregator::instance(),
202                 SLOT(updateUnwatchedCount()));
203         menu.addSeparator();
204     }
205
206     /*
207     // TODO
208     QAction *notificationsAction = menu.addAction(tr("Receive Notifications"), user,
209     SLOT(unsubscribe())); notificationsAction->setCheckable(true);
210     notificationsAction->setChecked(true);
211     */
212
213     QAction *unsubscribeAction = menu.addAction(tr("Unsubscribe"), channel, SLOT(unsubscribe()));
214     connect(unsubscribeAction, SIGNAL(triggered()), ChannelAggregator::instance(),
215             SLOT(updateUnwatchedCount()));
216
217     menu.exec(mapToGlobal(point));
218 }
219
220 void ChannelView::toggleShowUpdated(bool enable) {
221     showUpdated = enable;
222     updateQuery(true);
223     QSettings settings;
224     settings.setValue(showUpdatedKey, showUpdated);
225 }
226
227 void ChannelView::updateQuery(bool transition) {
228     Q_UNUSED(transition);
229     listView->clearErrorMessage();
230
231     if (!Database::exists()) {
232         listView->setErrorMessage(noSubscriptionsMessage());
233         return;
234     }
235
236     QString sql = "select user_id from subscriptions";
237     if (showUpdated) sql += " where notify_count>0";
238
239     switch (sortBy) {
240     case SortByUpdated:
241         sql += " order by updated desc";
242         break;
243     case SortByAdded:
244         sql += " order by added desc";
245         break;
246     case SortByLastWatched:
247         sql += " order by watched desc";
248         break;
249     case SortByMostWatched:
250         sql += " order by views desc";
251         break;
252     default:
253         sql += " order by name collate nocase";
254         break;
255     }
256
257 #ifdef APP_EXTRA
258     if (transition) Extra::fadeInWidget(this, this);
259 #endif
260
261     channelsModel->setQuery(sql, Database::instance().getConnection());
262     if (channelsModel->lastError().isValid()) {
263         qWarning() << channelsModel->lastError().text();
264         listView->setErrorMessage(channelsModel->lastError().text());
265     } else if (channelsModel->rowCount() < 3) {
266         QString msg;
267         if (showUpdated)
268             msg = tr("There are no updated subscriptions at this time.");
269         else
270             msg = noSubscriptionsMessage();
271         listView->setErrorMessage(msg);
272     }
273 }
274
275 void ChannelView::setSortBy(SortBy sortBy) {
276     this->sortBy = sortBy;
277     updateQuery(true);
278     QSettings settings;
279     settings.setValue(sortByKey, (int)sortBy);
280 }
281
282 void ChannelView::markAllAsWatched() {
283     ChannelAggregator::instance()->markAllAsWatched();
284     updateQuery();
285     markAsWatchedAction->setEnabled(false);
286 }
287
288 void ChannelView::unwatchedCountChanged(int count) {
289     markAsWatchedAction->setEnabled(count > 0);
290     channelsModel->updateUnwatched();
291     updateQuery();
292 }