]> git.sur5r.net Git - minitube/blob - src/MediaView.cpp
Removed THAction class, use plain QAction
[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 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);
31
32     listView = new QListView(this);
33     listView->setItemDelegate(new 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::DragDrop);
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     videoAreaWidget->setListModel(listModel);
71
72     loadingWidget = new LoadingWidget(this);
73     videoAreaWidget->setLoadingWidget(loadingWidget);
74
75     splitter->addWidget(videoAreaWidget);
76
77     layout->addWidget(splitter);
78     setLayout(layout);
79
80 }
81
82 MediaView::~MediaView() {
83
84 }
85
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)));
91 }
92
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)));
103 }
104
105 void MediaView::search(SearchParams *searchParams) {
106     this->searchParams = searchParams;
107
108     // start serching for videos
109     listModel->search(searchParams);
110
111     // this implies that the enum and the bar action order is the same
112     sortBar->setCheckedAction(searchParams->sortBy()-1);
113
114     listView->setFocus();
115
116     loadingWidget->clear();
117 }
118
119 void MediaView::disappear() {
120     timerPlayFlag = true;
121 }
122
123 void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/)
124 {
125
126     // qDebug() << "Phonon state: " << newState << oldState;
127
128     switch (newState) {
129
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
134         skip();
135         break;
136
137          case Phonon::PlayingState:
138         qDebug("playing");
139         videoAreaWidget->showVideo();
140         break;
141
142          case Phonon::StoppedState:
143         qDebug("stopped");
144         // play() has already been called when setting the source
145         // but Phonon on Linux needs a little more help to start playback
146         mediaObject->play();
147
148         // Workaround for Mac playback start problem
149         if (!timerPlayFlag) {
150             QTimer::singleShot(1000, this, SLOT(timerPlay()));
151         }
152
153         break;
154
155          case Phonon::PausedState:
156         qDebug("paused");
157         break;
158
159          case Phonon::BufferingState:
160         qDebug("buffering");
161         break;
162
163          case Phonon::LoadingState:
164         qDebug("loading");
165         break;
166
167          default:
168         ;
169     }
170 }
171
172 void MediaView::pause() {
173     // qDebug() << "pause() called" << mediaObject->state();
174     switch( mediaObject->state() ) {
175     case Phonon::PlayingState:
176         mediaObject->pause();
177         break;
178     default:
179         mediaObject->play();
180         break;
181     }
182 }
183
184 void MediaView::stop() {
185     listModel->abortSearch();
186     mediaObject->stop();
187     mediaObject->clear();
188 }
189
190 void MediaView::activeRowChanged(int row) {
191     Video *video = listModel->videoAt(row);
192     if (!video) return;
193
194     // immediately show the loading widget
195     videoAreaWidget->showLoading(video);
196
197     // mediaObject->pause();
198
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();
203
204     // reset the timer flag
205     timerPlayFlag = false;
206
207     // video title in the statusbar
208     QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(qApp->topLevelWidgets().first());
209     if (mainWindow) mainWindow->statusBar()->showMessage(video->title());
210
211     // see you in gotStreamUrl...
212
213 }
214
215 void MediaView::gotStreamUrl(QUrl streamUrl) {
216
217     // go!
218     mediaObject->setCurrentSource(streamUrl);
219     mediaObject->play();
220
221     // ensure we always have 10 videos ahead
222     listModel->searchNeeded();
223
224     // ensure active item is visible
225     int row = listModel->activeRow();
226     if (row != -1) {
227         QModelIndex index = listModel->index(row, 0, QModelIndex());
228         listView->scrollTo(index, QAbstractItemView::EnsureVisible);
229     }
230
231 }
232
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();
238 }
239
240 void MediaView::aboutToFinish() {
241     /*
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);
248     */
249 }
250
251 void MediaView::currentSourceChanged(const Phonon::MediaSource source) {
252     qDebug() << "Source changed:" << source.url();
253 }
254
255 void MediaView::skip() {
256     int nextRow = listModel->nextRow();
257     if (nextRow == -1) return;
258     listModel->setActiveRow(nextRow);
259 }
260
261 void MediaView::openWebPage() {
262     Video* video = listModel->activeVideo();
263     if (!video) return;
264     mediaObject->pause();
265     QDesktopServices::openUrl(video->webpage());
266 }
267
268 void MediaView::removeSelected() {
269     if (!listView->selectionModel()->hasSelection()) return;
270     QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
271     listModel->removeIndexes(indexes);
272 }
273
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);
279     }
280 }
281
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);
287 }
288
289 void MediaView::moveUpSelected() {
290     if (!listView->selectionModel()->hasSelection()) return;
291     QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
292     listModel->move(indexes, true);
293 }
294
295 void MediaView::moveDownSelected() {
296     if (!listView->selectionModel()->hasSelection()) return;
297     QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
298     listModel->move(indexes, false);
299 }
300
301 void MediaView::showVideoContextMenu(QPoint point) {
302     The::globalMenus()->value("video")->popup(videoWidget->mapToGlobal(point));
303 }
304
305 void MediaView::searchMostRelevant() {
306     searchParams->setSortBy(SearchParams::SortByRelevance);
307     search(searchParams);
308 }
309
310 void MediaView::searchMostRecent() {
311     searchParams->setSortBy(SearchParams::SortByNewest);
312     search(searchParams);
313 }
314
315 void MediaView::searchMostViewed() {
316     searchParams->setSortBy(SearchParams::SortByViewCount);
317     search(searchParams);
318 }
319
320 void MediaView::setPlaylistVisible(bool visible) {
321     playlistWidget->setVisible(visible);
322 }
323
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();
329         mediaObject->play();
330     }
331 }