]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
Initial import
[minitube] / src / MainWindow.cpp
1 #include "MainWindow.h"
2 #include "spacer.h"
3 #include "Constants.h"
4 #include "iconloader/qticonloader.h"
5 #include "global.h"
6
7 MainWindow::MainWindow() {
8
9     m_fullscreen = false;
10     mediaObject = 0;
11     audioOutput = 0;
12
13     // views mechanism
14     history = new QStack<QWidget*>();
15     views = new QStackedWidget(this);
16
17     // views
18     searchView = new SearchView(this);
19     connect(searchView, SIGNAL(search(QString)), this, SLOT(showMedia(QString)));
20     views->addWidget(searchView);
21     mediaView = new MediaView(this);
22     views->addWidget(mediaView);
23
24     // lazy initialized views
25     aboutView = 0;
26     settingsView = 0;
27
28     toolbarSearch = new SearchLineEdit(this);
29     toolbarSearch->setFont(qApp->font());
30     // toolbarSearch->setMinimumWidth(200);
31     connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
32
33     // build ui
34     createActions();
35     createMenus();
36     createToolBars();
37     createStatusBar();
38
39     // remove that useless menu/toolbar context menu
40     this->setContextMenuPolicy(Qt::NoContextMenu);
41
42     // mediaView init stuff thats needs actions
43     mediaView->initialize();
44
45     // restore window position
46     readSettings();
47
48     // show the initial view
49     showWidget(searchView);
50
51     setCentralWidget(views);
52
53     // top dock widget
54     /*
55     QLabel* message = new QLabel(this);
56     message->setText(QString("A new version of %1 is available.").arg(Constants::APP_NAME));
57     message->setMargin(10);
58     message->setAlignment(Qt::AlignCenter);
59     QPalette palette;
60     message->setBackgroundRole(QPalette::ToolTipBase);
61     message->setForegroundRole(QPalette::ToolTipText);
62     message->setAutoFillBackground(true);
63     QDockWidget *dockWidget = new QDockWidget("", this, 0);
64     dockWidget->setTitleBarWidget(0);
65     dockWidget->setWidget(message);
66     dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
67     addDockWidget(Qt::TopDockWidgetArea, dockWidget);
68     */
69
70 }
71
72 MainWindow::~MainWindow() {
73     delete history;
74 }
75
76 void MainWindow::createActions() {
77
78     QMap<QString, QAction*> *actions = The::globalActions();
79
80     /*
81     settingsAct = new QAction(tr("&Preferences..."), this);
82     settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
83     // Mac integration
84     settingsAct->setMenuRole(QAction::PreferencesRole);
85     actions->insert("settings", settingsAct);
86     connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
87     */
88     
89     backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
90     backAct->setEnabled(false);
91     backAct->setShortcut(tr("Alt+Left"));
92     backAct->setStatusTip(tr("Go to the previous view"));
93     actions->insert("back", backAct);
94     connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
95
96     stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
97     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
98     stopAct->setShortcut(tr("Esc"));
99     actions->insert("stop", stopAct);
100     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
101
102     skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
103     skipAct->setStatusTip(tr("Skip to the next video"));
104     skipAct->setShortcut(tr("Ctrl+Right"));
105     skipAct->setEnabled(false);
106     actions->insert("skip", skipAct);
107     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
108
109     pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
110     pauseAct->setStatusTip(tr("Pause playback"));
111     pauseAct->setShortcut(tr("Space"));
112     pauseAct->setEnabled(false);
113     actions->insert("pause", pauseAct);
114     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
115
116     fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
117     fullscreenAct->setStatusTip(tr("Go full screen"));
118     fullscreenAct->setShortcut(tr("Alt+Return"));
119     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
120     actions->insert("fullscreen", fullscreenAct);
121     connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
122
123     /*
124     // icon should be document-save but it is ugly
125     downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
126     downloadAct->setStatusTip(tr("Download this video"));
127     downloadAct->setShortcut(tr("Ctrl+S"));
128     actions.insert("download", downloadAct);
129     connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
130     */
131
132     webPageAct = new QAction(QtIconLoader::icon("internet-web-browser", QIcon(":/images/internet-web-browser.png")), tr("&YouTube"), this);
133     webPageAct->setStatusTip(tr("Open the YouTube video page"));
134     webPageAct->setShortcut(tr("Ctrl+Y"));
135     webPageAct->setEnabled(false);
136     actions->insert("webpage", webPageAct);
137     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
138
139     removeAct = new QAction(tr("&Remove"), this);
140     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
141     QList<QKeySequence> shortcuts;
142     shortcuts << QKeySequence("Del") << QKeySequence("Backspace");
143     removeAct->setShortcuts(shortcuts);
144     removeAct->setEnabled(false);
145     actions->insert("remove", removeAct);
146     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
147
148     moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
149     moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
150     moveUpAct->setShortcut(tr("Ctrl+Up"));
151     moveUpAct->setEnabled(false);
152     actions->insert("moveUp", moveUpAct);
153     connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
154
155     moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
156     moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
157     moveDownAct->setShortcut(tr("Ctrl+Down"));
158     moveDownAct->setEnabled(false);
159     actions->insert("moveDown", moveDownAct);
160     connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
161
162     quitAct = new QAction(tr("&Quit"), this);
163     quitAct->setMenuRole(QAction::QuitRole);
164     quitAct->setShortcut(tr("Ctrl+Q"));
165     quitAct->setStatusTip(tr("Bye"));
166     actions->insert("quit", quitAct);
167     connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
168
169     siteAct = new QAction(tr("&Website"), this);
170     siteAct->setShortcut(QKeySequence::HelpContents);
171     siteAct->setStatusTip(tr("Minitube on the Web"));
172     actions->insert("site", siteAct);
173     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
174
175     donateAct = new QAction(tr("&Donate via PayPal"), this);
176     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
177     actions->insert("donate", donateAct);
178     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
179
180     aboutAct = new QAction(tr("&About"), this);
181     aboutAct->setMenuRole(QAction::AboutRole);
182     aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
183     actions->insert("about", aboutAct);
184     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
185
186     searchFocusAct = new QAction(tr("&Search"), this);
187     searchFocusAct->setShortcut(QKeySequence::Find);
188     actions->insert("search", searchFocusAct);
189     connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
190     addAction(searchFocusAct);
191
192     // common action properties
193     foreach (QAction *action, actions->values()) {
194         // never autorepeat.
195         // unexperienced users tend to keep keys pressed for a "long" time
196         action->setAutoRepeat(false);
197         action->setToolTip(action->statusTip());
198
199 #ifdef Q_WS_MAC
200         // OSX does not use icons in menus
201         action->setIconVisibleInMenu(false);
202 #endif
203
204     }
205
206 }
207
208 void MainWindow::createMenus() {
209
210     QMap<QString, QMenu*> *menus = The::globalMenus();
211
212     fileMenu = menuBar()->addMenu(tr("&Application"));
213     // menus->insert("file", fileMenu);
214     /*
215     fileMenu->addAction(settingsAct);
216     fileMenu->addSeparator();
217     */
218     fileMenu->addAction(quitAct);
219
220     playlistMenu = menuBar()->addMenu(tr("&Playlist"));
221     menus->insert("playlist", playlistMenu);
222     playlistMenu->addAction(removeAct);
223     playlistMenu->addSeparator();
224     playlistMenu->addAction(moveUpAct);
225     playlistMenu->addAction(moveDownAct);
226
227     viewMenu = menuBar()->addMenu(tr("&Video"));
228     menus->insert("video", viewMenu);
229     // viewMenu->addAction(backAct);
230     viewMenu->addAction(stopAct);
231     viewMenu->addAction(pauseAct);
232     viewMenu->addAction(skipAct);
233     viewMenu->addSeparator();
234     viewMenu->addAction(webPageAct);
235     viewMenu->addSeparator();
236     viewMenu->addAction(fullscreenAct);
237
238     helpMenu = menuBar()->addMenu(tr("&Help"));
239     helpMenu->addAction(siteAct);
240     helpMenu->addAction(donateAct);
241     helpMenu->addAction(aboutAct);
242 }
243
244 void MainWindow::createToolBars() {
245
246     setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
247
248     mainToolBar = new QToolBar(this);
249     mainToolBar->setFloatable(false);
250     mainToolBar->setMovable(false);
251
252     QFont smallerFont;
253     smallerFont.setPointSize(smallerFont.pointSize()*.85);
254     mainToolBar->setFont(smallerFont);
255
256     mainToolBar->setIconSize(QSize(32,32));
257     // mainToolBar->addAction(backAct);
258     mainToolBar->addAction(stopAct);
259     mainToolBar->addAction(pauseAct);
260     mainToolBar->addAction(skipAct);
261     mainToolBar->addAction(fullscreenAct);
262
263     seekSlider = new Phonon::SeekSlider(this);
264     seekSlider->setIconVisible(false);
265     // seekSlider->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
266     mainToolBar->addWidget(new Spacer(mainToolBar, seekSlider));
267
268     volumeSlider = new Phonon::VolumeSlider(this);
269     // this makes the volume slider smaller...
270     volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
271     mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
272
273     // mainToolBar->addSeparator();
274     // mainToolBar->addAction(downloadAct);
275     // mainToolBar->addAction(webPageAct);
276
277     // toolbarSearch->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
278     mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
279
280     addToolBar(mainToolBar);
281 }
282
283 void MainWindow::createStatusBar() {
284     statusBar()->show();
285     statusBar()->setBackgroundRole(QPalette::Dark);
286     // statusBar()->setAutoFillBackground(true);
287 }
288
289 void MainWindow::readSettings() {
290     QSettings settings;
291     restoreGeometry(settings.value("geometry").toByteArray());
292 }
293
294 void MainWindow::writeSettings() {
295     QSettings settings;
296     settings.setValue("geometry", saveGeometry());
297 }
298
299 void MainWindow::goBack() {
300     if ( history->size() > 1 ) {
301         history->pop();
302         QWidget *widget = history->pop();
303         showWidget(widget);
304     }
305 }
306
307 void MainWindow::showWidget ( QWidget* widget ) {
308
309     // call hide method on the current view
310     View* oldView = dynamic_cast<View *> (views->currentWidget());
311     if (oldView != NULL) {
312         oldView->disappear();
313     }
314
315     // call show method on the new view
316     View* newView = dynamic_cast<View *> (widget);
317     if (newView != NULL) {
318         newView->appear();
319         QMap<QString,QVariant> metadata = newView->metadata();
320         QString windowTitle = metadata.value("title").toString();
321         if (windowTitle.length())
322             windowTitle += " - ";
323         setWindowTitle(windowTitle + Constants::APP_NAME);
324         setStatusTip(metadata.value("description").toString());
325     }
326
327     // backAct->setEnabled(history->size() > 1);
328     stopAct->setEnabled(widget == mediaView);
329     fullscreenAct->setEnabled(widget == mediaView);
330     webPageAct->setEnabled(widget == mediaView);
331     // settingsAct->setEnabled(widget != settingsView);
332     aboutAct->setEnabled(widget != aboutView);
333     // toolbar only for the mediaView
334
335     // This is cool on the Mac
336     // But does not respect layouts, maybe it's a Qt bug
337     // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
338
339     mainToolBar->setVisible(widget == mediaView);
340
341     history->push(widget);
342     fadeInWidget(views->currentWidget(), widget);
343     views->setCurrentWidget(widget);
344
345 }
346
347 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
348     if (faderWidget) faderWidget->close();
349     if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
350     QPixmap frozenView = QPixmap::grabWidget(oldWidget);
351     faderWidget = new FaderWidget(newWidget);
352     faderWidget->start(frozenView);
353 }
354
355 void MainWindow::about() {
356     if (!aboutView) {
357         aboutView = new AboutView(this);
358         views->addWidget(aboutView);
359     }
360     showWidget(aboutView);
361 }
362
363 void MainWindow::visitSite() {
364     QUrl url(Constants::WEBSITE);
365     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
366     QDesktopServices::openUrl(url);
367 }
368
369 void MainWindow::donate() {
370     QUrl url(QString(Constants::WEBSITE) + "#donate");
371     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
372     QDesktopServices::openUrl(url);
373 }
374
375 void MainWindow::quit() {
376     writeSettings();
377     qApp->quit();
378 }
379
380 void MainWindow::closeEvent(QCloseEvent *event) {
381     quit();
382     QWidget::closeEvent(event);
383 }
384
385 void MainWindow::showSettings() {
386     if (!settingsView) {
387         settingsView = new SettingsView(this);
388         views->addWidget(settingsView);
389     }
390     showWidget(settingsView);
391 }
392
393 void MainWindow::showSearch() {
394     showWidget(searchView);
395 }
396
397 void MainWindow::showMedia(QString query) {
398     initPhonon();
399     mediaView->setMediaObject(mediaObject);
400     SearchParams *searchParams = new SearchParams();
401     searchParams->setKeywords(query);
402     mediaView->search(searchParams);
403     showWidget(mediaView);
404 }
405
406 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
407
408     // qDebug() << "Phonon state: " << newState;
409
410     switch (newState) {
411
412          case Phonon::ErrorState:
413         if (mediaObject->errorType() == Phonon::FatalError) {
414             setStatusTip("Something went REALLY wrong: " + mediaObject->errorString());
415         } else {
416             setStatusTip("Something went wrong: " + mediaObject->errorString());
417         }
418         break;
419
420          case Phonon::PlayingState:
421         pauseAct->setEnabled(true);
422         pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
423         pauseAct->setText(tr("&Pause"));
424         pauseAct->setStatusTip(tr("Pause playback"));
425         skipAct->setEnabled(true);
426         break;
427
428          case Phonon::StoppedState:
429         pauseAct->setEnabled(false);
430         skipAct->setEnabled(false);
431         break;
432
433          case Phonon::PausedState:
434         skipAct->setEnabled(true);
435         pauseAct->setEnabled(true);
436         pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
437         pauseAct->setText(tr("&Play"));
438         pauseAct->setStatusTip(tr("Resume playback"));
439         break;
440
441          case Phonon::BufferingState:
442          case Phonon::LoadingState:
443         skipAct->setEnabled(true);
444         pauseAct->setEnabled(false);
445         break;
446
447          default:
448         ;
449     }
450 }
451
452 void MainWindow::stop() {
453     mediaView->stop();
454     showSearch();
455 }
456
457 void MainWindow::fullscreen() {
458     if (m_fullscreen) {
459         mediaView->exitFullscreen();
460         fullscreenAct->setShortcut(tr("Alt+Return"));
461         fullscreenAct->setText(tr("&Full Screen"));
462         stopAct->setShortcut(tr("Esc"));
463     } else {
464         mediaView->fullscreen();
465         stopAct->setShortcut(tr(""));
466         fullscreenAct->setShortcut(tr("Esc"));
467         fullscreenAct->setText(tr("Exit &Full Screen"));
468     }
469     m_fullscreen = !m_fullscreen;
470 }
471
472 void MainWindow::searchFocus() {
473     QWidget *view = views->currentWidget();
474     if (view == mediaView) {
475         toolbarSearch->setFocus();
476     }
477 }
478
479 void MainWindow::initPhonon() {
480     // Phonon initialization
481     if (mediaObject) delete mediaObject;
482     if (audioOutput) delete audioOutput;
483     mediaObject = new Phonon::MediaObject(this);
484     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
485             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
486     seekSlider->setMediaObject(mediaObject);
487     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
488     volumeSlider->setAudioOutput(audioOutput);
489     Phonon::createPath(mediaObject, audioOutput);
490 }