2 #include "playlist/PrettyItemDelegate.h"
3 #include "networkaccess.h"
4 #include "videowidget.h"
5 #include "minisplitter.h"
8 QMap<QString, QAction*>* globalActions();
9 QMap<QString, QMenu*>* globalMenus();
10 QNetworkAccessManager* networkAccessManager();
13 MediaView::MediaView(QWidget *parent) : QWidget(parent) {
15 QBoxLayout *layout = new QHBoxLayout();
18 splitter = new MiniSplitter(this);
19 splitter->setChildrenCollapsible(false);
21 sortBar = new THBlackBar(this);
22 mostRelevantAction = new QAction(tr("Most relevant"), this);
23 connect(mostRelevantAction, SIGNAL(triggered()), this, SLOT(searchMostRelevant()), Qt::QueuedConnection);
24 sortBar->addAction(mostRelevantAction);
25 mostRecentAction = new QAction(tr("Most recent"), this);
26 connect(mostRecentAction, SIGNAL(triggered()), this, SLOT(searchMostRecent()), Qt::QueuedConnection);
27 sortBar->addAction(mostRecentAction);
28 mostViewedAction = new QAction(tr("Most viewed"), this);
29 connect(mostViewedAction, SIGNAL(triggered()), this, SLOT(searchMostViewed()), Qt::QueuedConnection);
30 sortBar->addAction(mostViewedAction);
32 listView = new QListView(this);
33 listView->setItemDelegate(new PrettyItemDelegate(this));
34 listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
37 listView->setDragEnabled(true);
38 listView->setAcceptDrops(true);
39 listView->setDropIndicatorShown(true);
40 listView->setDragDropMode(QAbstractItemView::DragDrop);
43 listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
44 listView->setFrameShape( QFrame::NoFrame );
45 listView->setAttribute(Qt::WA_MacShowFocusRect, false);
46 listView->setMinimumSize(320,240);
48 // respond to the user doubleclicking a playlist item
49 connect(listView, SIGNAL(activated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &)));
51 listModel = new ListModel(this);
52 connect(listModel, SIGNAL(activeRowChanged(int)), this, SLOT(activeRowChanged(int)));
53 // needed to restore the selection after dragndrop
54 connect(listModel, SIGNAL(needSelectionFor(QList<Video*>)), this, SLOT(selectVideos(QList<Video*>)));
55 listView->setModel(listModel);
57 connect(listView->selectionModel(),
58 SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )),
59 this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & )));
61 playlistWidget = new PlaylistWidget(this, sortBar, listView);
63 splitter->addWidget(playlistWidget);
65 videoAreaWidget = new VideoAreaWidget(this);
66 videoAreaWidget->setMinimumSize(320,240);
68 videoWidget = new Phonon::VideoWidget(this);
69 videoAreaWidget->setVideoWidget(videoWidget);
70 videoAreaWidget->setListModel(listModel);
72 loadingWidget = new LoadingWidget(this);
73 videoAreaWidget->setLoadingWidget(loadingWidget);
75 splitter->addWidget(videoAreaWidget);
77 layout->addWidget(splitter);
82 MediaView::~MediaView() {
86 void MediaView::initialize() {
87 connect(videoAreaWidget, SIGNAL(doubleClicked()), The::globalActions()->value("fullscreen"), SLOT(trigger()));
88 videoAreaWidget->setContextMenuPolicy(Qt::CustomContextMenu);
89 connect(videoAreaWidget, SIGNAL(customContextMenuRequested(QPoint)),
90 this, SLOT(showVideoContextMenu(QPoint)));
93 void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
94 this->mediaObject = mediaObject;
95 Phonon::createPath(this->mediaObject, videoWidget);
96 // connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
97 connect(mediaObject, SIGNAL(finished()), this, SLOT(skip()));
98 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
99 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
100 connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
101 this, SLOT(currentSourceChanged(Phonon::MediaSource)));
102 connect(mediaObject, SIGNAL(bufferStatus(int)), loadingWidget, SLOT(bufferStatus(int)));
105 void MediaView::search(SearchParams *searchParams) {
106 this->searchParams = searchParams;
108 // start serching for videos
109 listModel->search(searchParams);
111 // this implies that the enum and the bar action order is the same
112 sortBar->setCheckedAction(searchParams->sortBy()-1);
114 listView->setFocus();
116 loadingWidget->clear();
119 void MediaView::disappear() {
120 timerPlayFlag = true;
123 void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/)
126 // qDebug() << "Phonon state: " << newState << oldState;
130 case Phonon::ErrorState:
131 qDebug() << "Phonon error:" << mediaObject->errorString() << mediaObject->errorType();
132 videoAreaWidget->showError(mediaObject->errorString());
133 // recover from errors by skipping to the next video
137 case Phonon::PlayingState:
139 videoAreaWidget->showVideo();
142 case Phonon::StoppedState:
144 // play() has already been called when setting the source
145 // but Phonon on Linux needs a little more help to start playback
148 // Workaround for Mac playback start problem
149 if (!timerPlayFlag) {
150 QTimer::singleShot(1000, this, SLOT(timerPlay()));
155 case Phonon::PausedState:
159 case Phonon::BufferingState:
163 case Phonon::LoadingState:
172 void MediaView::pause() {
173 // qDebug() << "pause() called" << mediaObject->state();
174 switch( mediaObject->state() ) {
175 case Phonon::PlayingState:
176 mediaObject->pause();
184 void MediaView::stop() {
185 listModel->abortSearch();
187 mediaObject->clear();
190 void MediaView::activeRowChanged(int row) {
191 Video *video = listModel->videoAt(row);
194 // immediately show the loading widget
195 videoAreaWidget->showLoading(video);
197 // mediaObject->pause();
199 connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl)));
200 // TODO handle signal in a proper slot and impl item error status
201 connect(video, SIGNAL(errorStreamUrl()), SLOT(skip()));
202 video->loadStreamUrl();
204 // reset the timer flag
205 timerPlayFlag = false;
207 // video title in the statusbar
208 QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(qApp->topLevelWidgets().first());
209 if (mainWindow) mainWindow->statusBar()->showMessage(video->title());
211 // see you in gotStreamUrl...
215 void MediaView::gotStreamUrl(QUrl streamUrl) {
218 mediaObject->setCurrentSource(streamUrl);
221 // ensure we always have 10 videos ahead
222 listModel->searchNeeded();
224 // ensure active item is visible
225 int row = listModel->activeRow();
227 QModelIndex index = listModel->index(row, 0, QModelIndex());
228 listView->scrollTo(index, QAbstractItemView::EnsureVisible);
233 void MediaView::itemActivated(const QModelIndex &index) {
234 if (listModel->rowExists(index.row()))
235 listModel->setActiveRow(index.row());
236 // the user doucleclicked on the "Search More" item
237 else listModel->searchMore();
240 void MediaView::aboutToFinish() {
242 int nextRow = listModel->nextRow();
243 if (nextRow == -1) return;
244 Video* video = listModel->videoAt(nextRow);
245 QUrl streamUrl = video->streamUrl();
246 qDebug() << "Enqueing" << streamUrl;
247 mediaObject->enqueue(streamUrl);
251 void MediaView::currentSourceChanged(const Phonon::MediaSource source) {
252 qDebug() << "Source changed:" << source.url();
255 void MediaView::skip() {
256 int nextRow = listModel->nextRow();
257 if (nextRow == -1) return;
258 listModel->setActiveRow(nextRow);
261 void MediaView::openWebPage() {
262 Video* video = listModel->activeVideo();
264 mediaObject->pause();
265 QDesktopServices::openUrl(video->webpage());
268 void MediaView::removeSelected() {
269 if (!listView->selectionModel()->hasSelection()) return;
270 QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
271 listModel->removeIndexes(indexes);
274 void MediaView::selectVideos(QList<Video*> videos) {
275 foreach (Video *video, videos) {
276 QModelIndex index = listModel->indexForVideo(video);
277 listView->selectionModel()->select(index, QItemSelectionModel::Select);
278 listView->scrollTo(index, QAbstractItemView::EnsureVisible);
282 void MediaView::selectionChanged(const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/) {
283 const bool gotSelection = listView->selectionModel()->hasSelection();
284 The::globalActions()->value("remove")->setEnabled(gotSelection);
285 The::globalActions()->value("moveUp")->setEnabled(gotSelection);
286 The::globalActions()->value("moveDown")->setEnabled(gotSelection);
289 void MediaView::moveUpSelected() {
290 if (!listView->selectionModel()->hasSelection()) return;
291 QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
292 listModel->move(indexes, true);
295 void MediaView::moveDownSelected() {
296 if (!listView->selectionModel()->hasSelection()) return;
297 QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
298 listModel->move(indexes, false);
301 void MediaView::showVideoContextMenu(QPoint point) {
302 The::globalMenus()->value("video")->popup(videoWidget->mapToGlobal(point));
305 void MediaView::searchMostRelevant() {
306 searchParams->setSortBy(SearchParams::SortByRelevance);
307 search(searchParams);
310 void MediaView::searchMostRecent() {
311 searchParams->setSortBy(SearchParams::SortByNewest);
312 search(searchParams);
315 void MediaView::searchMostViewed() {
316 searchParams->setSortBy(SearchParams::SortByViewCount);
317 search(searchParams);
320 void MediaView::setPlaylistVisible(bool visible) {
321 playlistWidget->setVisible(visible);
324 void MediaView::timerPlay() {
325 // qDebug() << mediaObject->currentTime();
326 // Workaround Phonon bug on Mac OSX
327 if (mediaObject->currentTime() <= 0 && mediaObject->state() == Phonon::PlayingState) {
328 mediaObject->pause();