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