3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
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.
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.
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/>.
21 #include "channelview.h"
22 #include "ytchannel.h"
24 #include "searchparams.h"
25 #include "channelmodel.h"
26 #include "channelitemdelegate.h"
29 #include "channelaggregator.h"
30 #include "aggregatevideosource.h"
31 #include "mainwindow.h"
32 #include "iconutils.h"
36 #include "channellistview.h"
38 static const char *sortByKey = "subscriptionsSortBy";
39 static const char *showUpdatedKey = "subscriptionsShowUpdated";
41 ChannelView::ChannelView(QWidget *parent) : View(parent),
45 QBoxLayout *layout = new QVBoxLayout(this);
47 layout->setSpacing(0);
49 listView = new ChannelListView();
50 listView->setItemDelegate(new ChannelItemDelegate(this));
52 channelsModel = new ChannelModel(this);
53 listView->setModel(channelsModel);
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()));
59 layout->addWidget(listView);
63 connect(ChannelAggregator::instance(), SIGNAL(channelChanged(YTChannel*)),
64 channelsModel, SLOT(updateChannel(YTChannel*)));
65 connect(ChannelAggregator::instance(), SIGNAL(unwatchedCountChanged(int)),
66 SLOT(unwatchedCountChanged(int)));
68 unwatchedCountChanged(ChannelAggregator::instance()->getUnwatchedCount());
71 void ChannelView::setupActions() {
74 sortBy = static_cast<SortBy>(settings.value(sortByKey, SortByName).toInt());
76 QMenu *sortMenu = new QMenu(this);
77 QActionGroup *sortGroup = new QActionGroup(this);
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);
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);
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);
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);
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);
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;
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;
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;
142 foreach (QAction *action, statusActions) {
143 window()->addAction(action);
144 IconUtils::setupAction(action);
148 void ChannelView::appear() {
150 foreach (QAction* action, statusActions)
151 MainWindow::instance()->showActionInStatusBar(action, true);
153 ChannelAggregator::instance()->start();
156 void ChannelView::disappear() {
157 foreach (QAction* action, statusActions)
158 MainWindow::instance()->showActionInStatusBar(action, false);
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);
185 void ChannelView::showContextMenu(const QPoint &point) {
186 const QModelIndex index = listView->indexAt(point);
187 if (!index.isValid()) return;
189 YTChannel *channel = channelsModel->channelForIndex(index);
190 if (!channel) return;
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()));
205 QAction *notificationsAction = menu.addAction(tr("Receive Notifications"), user, SLOT(unsubscribe()));
206 notificationsAction->setCheckable(true);
207 notificationsAction->setChecked(true);
210 QAction *unsubscribeAction = menu.addAction(tr("Unsubscribe"), channel, SLOT(unsubscribe()));
211 connect(unsubscribeAction, SIGNAL(triggered()),
212 ChannelAggregator::instance(), SLOT(updateUnwatchedCount()));
214 menu.exec(mapToGlobal(point));
217 void ChannelView::toggleShowUpdated(bool enable) {
218 showUpdated = enable;
221 settings.setValue(showUpdatedKey, showUpdated);
224 void ChannelView::updateQuery(bool transition) {
225 Q_UNUSED(transition);
226 listView->clearErrorMessage();
227 if (!Database::exists()) return;
229 QString sql = "select user_id from subscriptions";
231 sql += " where notify_count>0";
235 sql += " order by updated desc";
238 sql += " order by added desc";
240 case SortByLastWatched:
241 sql += " order by watched desc";
243 case SortByMostWatched:
244 sql += " order by views desc";
247 sql += " order by name collate nocase";
253 Extra::fadeInWidget(this, this);
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) {
263 msg = tr("There are no updated subscriptions at this time.");
265 msg = tr("You have no subscriptions. "
266 "Use the star symbol to subscribe to channels.");
267 listView->setErrorMessage(msg);
271 void ChannelView::setSortBy(SortBy sortBy) {
272 this->sortBy = sortBy;
275 settings.setValue(sortByKey, (int)sortBy);
278 void ChannelView::markAllAsWatched() {
279 ChannelAggregator::instance()->markAllAsWatched();
281 markAsWatchedAction->setEnabled(false);
284 void ChannelView::unwatchedCountChanged(int count) {
285 markAsWatchedAction->setEnabled(count > 0);
286 channelsModel->updateUnwatched();