]> git.sur5r.net Git - minitube/blob - src/MediaView.cpp
video title in the statusbar
[minitube] / src / MediaView.cpp
1 #include "MediaView.h"
2 #include "playlist/PrettyItemDelegate.h"
3 #include "networkaccess.h"
4 #include "videowidget.h"
5 #include "minisplitter.h"
6
7 namespace The {
8     QMap<QString, QAction*>* globalActions();
9     QMap<QString, QMenu*>* globalMenus();
10     QNetworkAccessManager* networkAccessManager();
11 }
12
13 MediaView::MediaView(QWidget *parent) : QWidget(parent) {
14
15     QBoxLayout *layout = new QHBoxLayout();
16     layout->setMargin(0);
17
18     splitter = new MiniSplitter(this);
19     splitter->setChildrenCollapsible(false);
20
21     sortBar = new THBlackBar(this);
22     mostRelevantAction = new THAction(tr("Most relevant"), this);
23     connect(mostRelevantAction, SIGNAL(triggered()), this, SLOT(searchMostRelevant()), Qt::QueuedConnection);
24     sortBar->addAction(mostRelevantAction);
25     mostRecentAction = new THAction(tr("Most recent"), this);
26     connect(mostRecentAction, SIGNAL(triggered()), this, SLOT(searchMostRecent()), Qt::QueuedConnection);
27     sortBar->addAction(mostRecentAction);
28     mostViewedAction = new THAction(tr("Most viewed"), this);
29     connect(mostViewedAction, SIGNAL(triggered()), this, SLOT(searchMostViewed()), Qt::QueuedConnection);
30     sortBar->addAction(mostViewedAction);
31
32     listView = new QListView(this);
33     listView->setItemDelegate(new Playlist::PrettyItemDelegate(this));
34     listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
35
36     // dragndrop
37     listView->setDragEnabled(true);
38     listView->setAcceptDrops(true);
39     listView->setDropIndicatorShown(true);
40     listView->setDragDropMode(QAbstractItemView::InternalMove);
41
42     // cosmetics
43     listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
44     listView->setFrameShape( QFrame::NoFrame );
45     listView->setAttribute(Qt::WA_MacShowFocusRect, false);
46     listView->setMinimumSize(320,240);
47
48     // respond to the user doubleclicking a playlist item
49     connect(listView, SIGNAL(activated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &)));
50
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);
56
57     connect(listView->selectionModel(),
58             SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )),
59             this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & )));
60
61     playlistWidget = new PlaylistWidget(this, sortBar, listView);
62
63     splitter->addWidget(playlistWidget);
64
65     videoAreaWidget = new VideoAreaWidget(this);
66     videoAreaWidget->setMinimumSize(320,240);
67
68     videoWidget = new Phonon::VideoWidget(this);
69     videoAreaWidget->setVideoWidget(videoWidget);
70
71     loadingWidget = new LoadingWidget(this);
72     videoAreaWidget->setLoadingWidget(loadingWidget);
73
74     splitter->addWidget(videoAreaWidget);
75
76     layout->addWidget(splitter);
77     setLayout(layout);
78
79 }
80
81 MediaView::~MediaView() {
82
83 }
84
85 void MediaView::initialize() {
86     connect(videoAreaWidget, SIGNAL(doubleClicked()), The::globalActions()->value("fullscreen"), SLOT(trigger()));
87     videoAreaWidget->setContextMenuPolicy(Qt::CustomContextMenu);
88     connect(videoAreaWidget, SIGNAL(customContextMenuRequested(QPoint)),
89             this, SLOT(showVideoContextMenu(QPoint)));
90 }
91
92 void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
93     this->mediaObject = mediaObject;
94     Phonon::createPath(this->mediaObject, videoWidget);
95     // connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
96     connect(mediaObject, SIGNAL(finished()), this, SLOT(skip()));
97     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
98             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
99     connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
100             this, SLOT(currentSourceChanged(Phonon::MediaSource)));
101     connect(mediaObject, SIGNAL(bufferStatus(int)), loadingWidget, SLOT(bufferStatus(int)));
102 }
103
104 void MediaView::search(SearchParams *searchParams) {
105     this->searchParams = searchParams;
106
107     // this implies that the enum and the bar action order is the same
108     sortBar->setCheckedAction(searchParams->sortBy()-1);
109
110     listModel->search(searchParams);
111     listView->setFocus();
112 }
113
114 void MediaView::disappear() {
115     timerPlayFlag = true;
116 }
117
118 void MediaView::stateChanged(Phonon::State newState, Phonon::State oldState)
119 {
120
121     qDebug() << "Phonon state: " << newState << oldState;
122
123     switch (newState) {
124
125          case Phonon::ErrorState:
126         qDebug() << "Phonon error:" << mediaObject->errorString() << mediaObject->errorType();
127         // recover from errors by skipping to the next video
128         skip();
129         break;
130
131          case Phonon::PlayingState:
132         qDebug("playing");
133         videoAreaWidget->showVideo();
134         break;
135
136          case Phonon::StoppedState:
137         qDebug("stopped");
138         // play() has already been called when setting the source
139         // but Phonon on Linux needs a little more help to start playback
140         mediaObject->play();
141         if (!timerPlayFlag) {
142             QTimer::singleShot(1000, this, SLOT(timerPlay()));
143         }
144         break;
145
146          case Phonon::PausedState:
147         qDebug("paused");
148         break;
149
150          case Phonon::BufferingState:
151         qDebug("buffering");
152         break;
153
154          case Phonon::LoadingState:
155         qDebug("loading");
156         break;
157
158          default:
159         ;
160     }
161 }
162
163 void MediaView::pause() {
164     switch( mediaObject->state() ) {
165     case Phonon::PlayingState:
166         mediaObject->pause();
167         break;
168     default:
169         mediaObject->play();
170         break;
171     }
172 }
173
174 void MediaView::fullscreen() {
175     splitterState = splitter->saveState();
176     videoAreaWidget->setParent(0);
177     videoAreaWidget->showFullScreen();
178 }
179
180 void MediaView::exitFullscreen() {
181     // videoAreaWidget->setParent(this);
182     splitter->addWidget(videoAreaWidget);
183     // Just calling show() on the Mac won't work
184     videoAreaWidget->showNormal();
185     splitter->restoreState(splitterState);
186 }
187
188 void MediaView::stop() {
189     listModel->abortSearch();
190     mediaObject->stop();
191     mediaObject->clear();
192 }
193
194 void MediaView::activeRowChanged(int row) {
195     Video *video = listModel->videoAt(row);
196     if (!video) return;
197
198     // immediately show the loading widget
199     videoAreaWidget->showLoading(video);
200
201     // mediaObject->pause();
202
203     connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl)));
204     video->loadStreamUrl();
205
206     // reset the timer flag
207     timerPlayFlag = false;
208
209     // video title in the statusbar
210     QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(qApp->topLevelWidgets().first());
211     if (mainWindow) mainWindow->statusBar()->showMessage(video->title());
212
213     // see you in gotStreamUrl...
214
215 }
216
217 void MediaView::gotStreamUrl(QUrl streamUrl) {
218
219     // go!
220     mediaObject->setCurrentSource(streamUrl);
221     mediaObject->play();
222
223     // ensure we always have 10 videos ahead
224     listModel->searchNeeded();
225
226     // ensure active item is visible
227     int row = listModel->activeRow();
228     if (row != -1) {
229         QModelIndex index = listModel->index(row, 0, QModelIndex());
230         listView->scrollTo(index, QAbstractItemView::EnsureVisible);
231     }
232
233 }
234
235 void MediaView::itemActivated(const QModelIndex &index) {
236     if (listModel->rowExists(index.row()))
237         listModel->setActiveRow(index.row());
238     // the user doucleclicked on the "Search More" item
239     else listModel->searchMore();
240 }
241
242 void MediaView::aboutToFinish() {
243     /*
244     int nextRow = listModel->nextRow();
245     if (nextRow == -1) return;
246     Video* video = listModel->videoAt(nextRow);
247     QUrl streamUrl = video->streamUrl();
248     qDebug() << "Enqueing" << streamUrl;
249     mediaObject->enqueue(streamUrl);
250     */
251 }
252
253 void MediaView::currentSourceChanged(const Phonon::MediaSource source) {
254     qDebug() << "Source changed:" << source.url();
255 }
256
257 void MediaView::skip() {
258     int nextRow = listModel->nextRow();
259     if (nextRow == -1) return;
260     listModel->setActiveRow(nextRow);
261 }
262
263 void MediaView::openWebPage() {
264     Video* video = listModel->activeVideo();
265     if (!video) return;
266     mediaObject->pause();
267     QDesktopServices::openUrl(video->webpage());
268 }
269
270 void MediaView::removeSelected() {
271     if (!listView->selectionModel()->hasSelection()) return;
272     QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
273     listModel->removeIndexes(indexes);
274 }
275
276 void MediaView::selectVideos(QList<Video*> videos) {
277     foreach (Video *video, videos) {
278         QModelIndex index = listModel->indexForVideo(video);
279         listView->selectionModel()->select(index, QItemSelectionModel::Select);
280         listView->scrollTo(index, QAbstractItemView::EnsureVisible);
281     }
282 }
283
284 void MediaView::selectionChanged(const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/) {
285     const bool gotSelection = listView->selectionModel()->hasSelection();
286     The::globalActions()->value("remove")->setEnabled(gotSelection);
287     The::globalActions()->value("moveUp")->setEnabled(gotSelection);
288     The::globalActions()->value("moveDown")->setEnabled(gotSelection);
289 }
290
291 void MediaView::moveUpSelected() {
292     if (!listView->selectionModel()->hasSelection()) return;
293     QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
294     listModel->move(indexes, true);
295 }
296
297 void MediaView::moveDownSelected() {
298     if (!listView->selectionModel()->hasSelection()) return;
299     QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
300     listModel->move(indexes, false);
301 }
302
303 void MediaView::showVideoContextMenu(QPoint point) {
304     The::globalMenus()->value("video")->popup(videoWidget->mapToGlobal(point));
305 }
306
307 void MediaView::searchMostRelevant() {
308     searchParams->setSortBy(SearchParams::SortByRelevance);
309     search(searchParams);
310 }
311
312 void MediaView::searchMostRecent() {
313     searchParams->setSortBy(SearchParams::SortByNewest);
314     search(searchParams);
315 }
316
317 void MediaView::searchMostViewed() {
318     searchParams->setSortBy(SearchParams::SortByViewCount);
319     search(searchParams);
320 }
321
322 void MediaView::setPlaylistVisible(bool visible) {
323     playlistWidget->setVisible(visible);
324 }
325
326 void MediaView::timerPlay() {
327     qDebug() << mediaObject->currentTime();
328     // Workaround Phonon bug on Mac OSX
329     if (mediaObject->currentTime() <= 0 && mediaObject->state() == Phonon::PlayingState) {
330         mediaObject->pause();
331         mediaObject->play();
332     }
333 }