]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
Polish translation by Grzegorz Gibas
[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     // lazily initialized views
25     aboutView = 0;
26     settingsView = 0;
27
28     toolbarSearch = new SearchLineEdit(this);
29     toolbarSearch->setFont(qApp->font());
30     connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
31
32     // build ui
33     createActions();
34     createMenus();
35     createToolBars();
36     createStatusBar();
37
38     // remove that useless menu/toolbar context menu
39     this->setContextMenuPolicy(Qt::NoContextMenu);
40
41     // mediaView init stuff thats needs actions
42     mediaView->initialize();
43
44     // restore window position
45     readSettings();
46
47     // show the initial view
48     showWidget(searchView);
49
50     setCentralWidget(views);
51
52 }
53
54 MainWindow::~MainWindow() {
55     delete history;
56 }
57
58 void MainWindow::createActions() {
59
60     QMap<QString, QAction*> *actions = The::globalActions();
61
62     /*
63     settingsAct = new QAction(tr("&Preferences..."), this);
64     settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
65     // Mac integration
66     settingsAct->setMenuRole(QAction::PreferencesRole);
67     actions->insert("settings", settingsAct);
68     connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
69     */
70     
71     backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
72     backAct->setEnabled(false);
73     backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
74     backAct->setStatusTip(tr("Go to the previous view"));
75     actions->insert("back", backAct);
76     connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
77
78     stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
79     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
80     stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
81     actions->insert("stop", stopAct);
82     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
83
84     skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
85     skipAct->setStatusTip(tr("Skip to the next video"));
86     skipAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right));
87     skipAct->setEnabled(false);
88     actions->insert("skip", skipAct);
89     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
90
91     pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
92     pauseAct->setStatusTip(tr("Pause playback"));
93     pauseAct->setShortcut(QKeySequence(Qt::Key_Space));
94     pauseAct->setEnabled(false);
95     actions->insert("pause", pauseAct);
96     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
97
98     fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
99     fullscreenAct->setStatusTip(tr("Go full screen"));
100     fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
101     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
102     actions->insert("fullscreen", fullscreenAct);
103     connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
104
105     compactViewAct = new QAction(tr("&Compact mode"), this);
106     compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
107     compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
108     compactViewAct->setCheckable(true);
109     compactViewAct->setChecked(false);
110     compactViewAct->setEnabled(false);
111     actions->insert("compactView", compactViewAct);
112     connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
113
114     /*
115     // icon should be document-save but it is ugly
116     downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
117     downloadAct->setStatusTip(tr("Download this video"));
118     downloadAct->setShortcut(tr("Ctrl+S"));
119     actions.insert("download", downloadAct);
120     connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
121     */
122
123     webPageAct = new QAction(QtIconLoader::icon("internet-web-browser", QIcon(":/images/internet-web-browser.png")), tr("&YouTube"), this);
124     webPageAct->setStatusTip(tr("Open the YouTube video page"));
125     webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
126     webPageAct->setEnabled(false);
127     actions->insert("webpage", webPageAct);
128     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
129
130     removeAct = new QAction(tr("&Remove"), this);
131     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
132     QList<QKeySequence> shortcuts;
133     shortcuts << QKeySequence("Del") << QKeySequence("Backspace");
134     removeAct->setShortcuts(shortcuts);
135     removeAct->setEnabled(false);
136     actions->insert("remove", removeAct);
137     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
138
139     moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
140     moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
141     moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
142     moveUpAct->setEnabled(false);
143     actions->insert("moveUp", moveUpAct);
144     connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
145
146     moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
147     moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
148     moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
149     moveDownAct->setEnabled(false);
150     actions->insert("moveDown", moveDownAct);
151     connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
152
153     quitAct = new QAction(tr("&Quit"), this);
154     quitAct->setMenuRole(QAction::QuitRole);
155     quitAct->setShortcut(tr("Ctrl+Q"));
156     quitAct->setStatusTip(tr("Bye"));
157     actions->insert("quit", quitAct);
158     connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
159
160     siteAct = new QAction(tr("&Website"), this);
161     siteAct->setShortcut(QKeySequence::HelpContents);
162     siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
163     actions->insert("site", siteAct);
164     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
165
166     donateAct = new QAction(tr("&Donate via PayPal"), this);
167     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
168     actions->insert("donate", donateAct);
169     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
170
171     aboutAct = new QAction(tr("&About"), this);
172     aboutAct->setMenuRole(QAction::AboutRole);
173     aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
174     actions->insert("about", aboutAct);
175     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
176
177     searchFocusAct = new QAction(tr("&Search"), this);
178     searchFocusAct->setShortcut(QKeySequence::Find);
179     actions->insert("search", searchFocusAct);
180     connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
181     addAction(searchFocusAct);
182
183     // common action properties
184     foreach (QAction *action, actions->values()) {
185
186         // add actions to the MainWindow so that they work
187         // when the menu is hidden
188         addAction(action);
189
190         // never autorepeat.
191         // unexperienced users tend to keep keys pressed for a "long" time
192         action->setAutoRepeat(false);
193         action->setToolTip(action->statusTip());
194
195         // make the actions work when video is fullscreen
196         action->setShortcutContext(Qt::ApplicationShortcut);
197
198 #ifdef Q_WS_MAC
199         // OSX does not use icons in menus
200         action->setIconVisibleInMenu(false);
201 #endif
202
203     }
204
205 }
206
207 void MainWindow::createMenus() {
208
209     QMap<QString, QMenu*> *menus = The::globalMenus();
210
211     fileMenu = menuBar()->addMenu(tr("&Application"));
212     // menus->insert("file", fileMenu);
213     /*
214     fileMenu->addAction(settingsAct);
215     fileMenu->addSeparator();
216     */
217     fileMenu->addAction(quitAct);
218
219     playlistMenu = menuBar()->addMenu(tr("&Playlist"));
220     menus->insert("playlist", playlistMenu);
221     playlistMenu->addAction(removeAct);
222     playlistMenu->addSeparator();
223     playlistMenu->addAction(moveUpAct);
224     playlistMenu->addAction(moveDownAct);
225
226     viewMenu = menuBar()->addMenu(tr("&Video"));
227     menus->insert("video", viewMenu);
228     // viewMenu->addAction(backAct);
229     viewMenu->addAction(stopAct);
230     viewMenu->addAction(pauseAct);
231     viewMenu->addAction(skipAct);
232     viewMenu->addSeparator();
233     viewMenu->addAction(webPageAct);
234     viewMenu->addSeparator();
235     viewMenu->addAction(compactViewAct);
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     Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
266     seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
267     mainToolBar->addWidget(seekSliderSpacer);
268
269     volumeSlider = new Phonon::VolumeSlider(this);
270     // this makes the volume slider smaller
271     volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
272     mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
273
274     mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
275
276     addToolBar(mainToolBar);
277 }
278
279 void MainWindow::createStatusBar() {
280     currentTime = new QLabel(this);
281     statusBar()->addPermanentWidget(currentTime);
282
283     totalTime = new QLabel(this);
284     statusBar()->addPermanentWidget(totalTime);
285
286     // remove ugly borders on OSX
287     statusBar()->setStyleSheet("::item{border:0 solid}");
288
289     statusBar()->show();
290 }
291
292 void MainWindow::readSettings() {
293     QSettings settings;
294     restoreGeometry(settings.value("geometry").toByteArray());
295 }
296
297 void MainWindow::writeSettings() {
298     // do not save geometry when in full screen
299     if (m_fullscreen)
300         return;
301     QSettings settings;
302     settings.setValue("geometry", saveGeometry());
303 }
304
305 void MainWindow::goBack() {
306     if ( history->size() > 1 ) {
307         history->pop();
308         QWidget *widget = history->pop();
309         showWidget(widget);
310     }
311 }
312
313 void MainWindow::showWidget ( QWidget* widget ) {
314
315     setUpdatesEnabled(false);
316
317     // call hide method on the current view
318     View* oldView = dynamic_cast<View *> (views->currentWidget());
319     if (oldView != NULL) {
320         oldView->disappear();
321     }
322
323     // call show method on the new view
324     View* newView = dynamic_cast<View *> (widget);
325     if (newView != NULL) {
326         newView->appear();
327         QMap<QString,QVariant> metadata = newView->metadata();
328         QString windowTitle = metadata.value("title").toString();
329         if (windowTitle.length())
330             windowTitle += " - ";
331         setWindowTitle(windowTitle + Constants::APP_NAME);
332         statusBar()->showMessage((metadata.value("description").toString()));
333
334     }
335
336     // backAct->setEnabled(history->size() > 1);
337     // settingsAct->setEnabled(widget != settingsView);
338     stopAct->setEnabled(widget == mediaView);
339     fullscreenAct->setEnabled(widget == mediaView);
340     compactViewAct->setEnabled(widget == mediaView);
341     webPageAct->setEnabled(widget == mediaView);
342     aboutAct->setEnabled(widget != aboutView);
343
344     // cool toolbar on the Mac
345     // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
346
347     // toolbar only for the mediaView
348     mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
349
350     history->push(widget);
351     fadeInWidget(views->currentWidget(), widget);
352     views->setCurrentWidget(widget);
353
354     setUpdatesEnabled(true);
355 }
356
357 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
358     if (faderWidget) faderWidget->close();
359     if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
360     QPixmap frozenView = QPixmap::grabWidget(oldWidget);
361     faderWidget = new FaderWidget(newWidget);
362     faderWidget->start(frozenView);
363 }
364
365 void MainWindow::about() {
366     if (!aboutView) {
367         aboutView = new AboutView(this);
368         views->addWidget(aboutView);
369     }
370     showWidget(aboutView);
371 }
372
373 void MainWindow::visitSite() {
374     QUrl url(Constants::WEBSITE);
375     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
376     QDesktopServices::openUrl(url);
377 }
378
379 void MainWindow::donate() {
380     QUrl url(QString(Constants::WEBSITE) + "#donate");
381     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
382     QDesktopServices::openUrl(url);
383 }
384
385 void MainWindow::quit() {
386     writeSettings();
387     qApp->quit();
388 }
389
390 void MainWindow::closeEvent(QCloseEvent *event) {
391     quit();
392     QWidget::closeEvent(event);
393 }
394
395 void MainWindow::showSettings() {
396     if (!settingsView) {
397         settingsView = new SettingsView(this);
398         views->addWidget(settingsView);
399     }
400     showWidget(settingsView);
401 }
402
403 void MainWindow::showSearch() {
404     showWidget(searchView);
405     currentTime->clear();
406     totalTime->clear();
407 }
408
409 void MainWindow::showMedia(QString query) {
410     initPhonon();
411     mediaView->setMediaObject(mediaObject);
412     SearchParams *searchParams = new SearchParams();
413     searchParams->setKeywords(query);
414     mediaView->search(searchParams);
415     showWidget(mediaView);
416 }
417
418 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
419
420     // qDebug() << "Phonon state: " << newState;
421
422     switch (newState) {
423
424          case Phonon::ErrorState:
425         if (mediaObject->errorType() == Phonon::FatalError) {
426             statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
427         } else {
428             statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
429         }
430         break;
431
432          case Phonon::PlayingState:
433         pauseAct->setEnabled(true);
434         pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
435         pauseAct->setText(tr("&Pause"));
436         pauseAct->setStatusTip(tr("Pause playback"));
437         skipAct->setEnabled(true);
438         break;
439
440          case Phonon::StoppedState:
441         pauseAct->setEnabled(false);
442         skipAct->setEnabled(false);
443         break;
444
445          case Phonon::PausedState:
446         skipAct->setEnabled(true);
447         pauseAct->setEnabled(true);
448         pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
449         pauseAct->setText(tr("&Play"));
450         pauseAct->setStatusTip(tr("Resume playback"));
451         break;
452
453          case Phonon::BufferingState:
454          case Phonon::LoadingState:
455         skipAct->setEnabled(true);
456         pauseAct->setEnabled(false);
457         currentTime->clear();
458         totalTime->clear();
459         break;
460
461          default:
462         ;
463     }
464 }
465
466 void MainWindow::stop() {
467     mediaView->stop();
468     showSearch();
469 }
470
471 void MainWindow::fullscreen() {
472
473     setUpdatesEnabled(false);
474
475     if (m_fullscreen) {
476         // use setShortucs instead of setShortcut
477         // the latter seems not to work
478         QList<QKeySequence> shortcuts;
479         shortcuts << QKeySequence(Qt::ALT + Qt::Key_Return);
480         fullscreenAct->setShortcuts(shortcuts);
481         fullscreenAct->setText(tr("&Full Screen"));
482         stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
483         if (m_maximized) showMaximized();
484         else showNormal();
485     } else {
486         stopAct->setShortcut(QString(""));
487         QList<QKeySequence> shortcuts;
488         // for some reason it is important that ESC comes first
489         shortcuts << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return);
490         fullscreenAct->setShortcuts(shortcuts);
491         fullscreenAct->setText(tr("Exit &Full Screen"));
492         m_maximized = isMaximized();
493
494         // save geometry now, if the user quits when in full screen
495         // geometry won't be saved
496         writeSettings();
497
498         showFullScreen();
499     }
500
501     // No compact view action when in full screen
502     compactViewAct->setVisible(m_fullscreen);
503
504     // Hide anything but the video
505     mediaView->setPlaylistVisible(m_fullscreen);
506     mainToolBar->setVisible(m_fullscreen);
507     statusBar()->setVisible(m_fullscreen);
508     menuBar()->setVisible(m_fullscreen);
509
510     m_fullscreen = !m_fullscreen;
511
512     setUpdatesEnabled(true);
513 }
514
515 void MainWindow::compactView(bool enable) {
516
517     setUpdatesEnabled(false);
518
519     // setUnifiedTitleAndToolBarOnMac(!enable);
520     mediaView->setPlaylistVisible(!enable);
521     mainToolBar->setVisible(!enable);
522     statusBar()->setVisible(!enable);
523
524     // ensure focus does not end up to the search box
525     // as it would steal the Space shortcut
526     toolbarSearch->setEnabled(!enable);
527
528     if (enable) {
529         stopAct->setShortcut(QString(""));
530         QList<QKeySequence> shortcuts;
531         // for some reason it is important that ESC comes first
532         shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
533         compactViewAct->setShortcuts(shortcuts);
534     } else {
535         compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
536         stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
537     }
538
539     setUpdatesEnabled(true);
540 }
541
542 void MainWindow::searchFocus() {
543     QWidget *view = views->currentWidget();
544     if (view == mediaView) {
545         toolbarSearch->setFocus();
546     }
547 }
548
549 void MainWindow::initPhonon() {
550     // Phonon initialization
551     if (mediaObject) delete mediaObject;
552     if (audioOutput) delete audioOutput;
553     mediaObject = new Phonon::MediaObject(this);
554     mediaObject->setTickInterval(100);
555     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
556             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
557     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
558     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
559     seekSlider->setMediaObject(mediaObject);
560     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
561     volumeSlider->setAudioOutput(audioOutput);
562     Phonon::createPath(mediaObject, audioOutput);
563 }
564
565 void MainWindow::tick(qint64 time) {
566     QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
567     currentTime->setText(displayTime.toString("mm:ss"));
568     // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
569 }
570
571 void MainWindow::totalTimeChanged(qint64 time) {
572     if (time <= 0) {
573         totalTime->clear();
574         return;
575     }
576     QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
577     totalTime->setText(displayTime.toString("/ mm:ss"));
578     // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");
579 }
580