]> git.sur5r.net Git - minitube/commitdiff
Lots of changes, sorry I'm doing a bad work with git lately...
authorFlavio <flavio@odisseo.local>
Sat, 3 Dec 2011 13:49:23 +0000 (14:49 +0100)
committerFlavio <flavio@odisseo.local>
Sat, 3 Dec 2011 13:49:23 +0000 (14:49 +0100)
27 files changed:
minitube.pro
src/AboutView.h
src/ListModel.cpp
src/ListModel.h
src/MainWindow.cpp
src/MainWindow.h
src/MediaView.cpp
src/MediaView.h
src/SearchView.cpp
src/SearchView.h
src/autocomplete.cpp
src/autocomplete.h
src/downloaditem.cpp
src/downloadlistview.cpp
src/downloadlistview.h
src/downloadview.cpp
src/downloadview.h
src/main.cpp
src/playlist/PrettyItemDelegate.cpp
src/playlist/PrettyItemDelegate.h
src/playlistview.cpp [new file with mode: 0644]
src/playlistview.h [new file with mode: 0644]
src/playlistwidget.cpp
src/playlistwidget.h
src/searchlineedit.h
src/segmentedcontrol.cpp [new file with mode: 0644]
src/segmentedcontrol.h [new file with mode: 0644]

index 75dda4e2dec03d255859381fa7f0cd55ee5da474..89d67fb0df04e7851beadd53548dae2668e60e26 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG += release
 TEMPLATE = app
-VERSION = 1.6
+VERSION = 1.7
 DEFINES += APP_VERSION="$$VERSION"
 INCLUDEPATH += /usr/include/phonon
 
@@ -48,7 +48,6 @@ HEADERS += src/MainWindow.h \
     src/videowidget.h \
     src/videodefinition.h \
     src/fontutils.h \
-    src/thlibrary/thblackbar.h \
     src/globalshortcuts.h \
     src/globalshortcutbackend.h \
     src/downloadmanager.h \
@@ -60,7 +59,9 @@ HEADERS += src/MainWindow.h \
     src/youtubesuggest.h \
     src/suggester.h \
     src/channelsuggest.h \
-    src/temporary.h
+    src/temporary.h \
+    src/segmentedcontrol.h \
+    src/playlistview.h
 SOURCES += src/main.cpp \
     src/MainWindow.cpp \
     src/SearchView.cpp \
@@ -88,7 +89,6 @@ SOURCES += src/main.cpp \
     src/videodefinition.cpp \
     src/constants.cpp \
     src/fontutils.cpp \
-    src/thlibrary/thblackbar.cpp \
     src/globalshortcuts.cpp \
     src/globalshortcutbackend.cpp \
     src/downloadmanager.cpp \
@@ -99,7 +99,9 @@ SOURCES += src/main.cpp \
     src/downloadsettings.cpp \
     src/youtubesuggest.cpp \
     src/channelsuggest.cpp \
-    src/temporary.cpp
+    src/temporary.cpp \
+    src/segmentedcontrol.cpp \
+    src/playlistview.cpp
 RESOURCES += resources.qrc
 DESTDIR = build/target/
 OBJECTS_DIR = build/obj/
@@ -162,3 +164,7 @@ unix:!mac {
 }
 mac|win32:include(local/local.pri)
 
+
+
+
+
index 9d6a443258490765e6dff2d3532c6a954e97824b..2d3e0c4dc394341f1fbc1fa88f308e9b98c71dbb 100644 (file)
@@ -4,6 +4,9 @@
 #include <QtGui>
 #include "View.h"
 #include "constants.h"
+#ifdef APP_MAC
+#include "macutils.h"
+#endif
 
 class AboutView : public QWidget, public View {
 
@@ -11,7 +14,11 @@ class AboutView : public QWidget, public View {
 
 public:
     AboutView(QWidget *parent);
-    void appear() {}
+    void appear() {
+#ifdef APP_MAC
+        mac::uncloseWindow(window()->winId());
+#endif
+    }
     void disappear() {}
     QMap<QString, QVariant> metadata() {
         QMap<QString, QVariant> metadata;
index 644e512fc12f941e43969ddee55fd17f28db254c..2662e146a0364b2c3ffaf3418c71d37238b51cb9 100644 (file)
@@ -12,6 +12,10 @@ ListModel::ListModel(QWidget *parent) : QAbstractListModel(parent) {
     m_activeVideo = 0;
     m_activeRow = -1;
     skip = 1;
+
+    hoveredRow = -1;
+    authorHovered = false;
+    authorPressed = false;
 }
 
 ListModel::~ListModel() {
@@ -80,6 +84,12 @@ QVariant ListModel::data(const QModelIndex &index, int role) const {
         return video == m_activeVideo;
     case Qt::DisplayRole:
         return video->title();
+    case HoveredItemRole:
+        return hoveredRow == index.row();
+    case AuthorHoveredRole:
+        return authorHovered;
+    case AuthorPressedRole:
+        return authorPressed;
     }
     
     return QVariant();
@@ -113,6 +123,13 @@ int ListModel::nextRow() const {
     return -1;
 }
 
+int ListModel::previousRow() const {
+    int prevRow = m_activeRow - 1;
+    if (rowExists(prevRow))
+        return prevRow;
+    return -1;
+}
+
 Video* ListModel::videoAt( int row ) const {
     if ( rowExists( row ) )
         return videos.at( row );
@@ -404,3 +421,48 @@ void ListModel::move(QModelIndexList &indexes, bool up) {
     emit needSelectionFor(movedVideos);
 
 }
+
+/* row hovering */
+
+void ListModel::setHoveredRow(int row) {
+    int oldRow = hoveredRow;
+    hoveredRow = row;
+    emit dataChanged( createIndex( oldRow, 0 ), createIndex( oldRow, columnCount() - 1 ) );
+    emit dataChanged( createIndex( hoveredRow, 0 ), createIndex( hoveredRow, columnCount() - 1 ) );
+}
+
+void ListModel::clearHover() {
+    emit dataChanged( createIndex( hoveredRow, 0 ), createIndex( hoveredRow, columnCount() - 1 ) );
+    hoveredRow = -1;
+}
+
+/* clickable author */
+
+void ListModel::enterAuthorHover() {
+    if (authorHovered) return;
+    authorHovered = true;
+    updateAuthor();
+}
+
+void ListModel::exitAuthorHover() {
+    if (!authorHovered) return;
+    authorHovered = false;
+    updateAuthor();
+    setHoveredRow(hoveredRow);
+}
+
+void ListModel::enterAuthorPressed() {
+    if (authorPressed) return;
+    authorPressed = true;
+    updateAuthor();
+}
+
+void ListModel::exitAuthorPressed() {
+    if (!authorPressed) return;
+    authorPressed = false;
+    updateAuthor();
+}
+
+void ListModel::updateAuthor() {
+    emit dataChanged( createIndex( hoveredRow, 0 ), createIndex( hoveredRow, columnCount() - 1 ) );
+}
index c84b6053a7ffd40de127b9b042c4809f8372a4ae..2752aab196229dd4b1c4e20d8d2e4adc84322d67 100644 (file)
@@ -12,7 +12,9 @@ enum DataRoles {
     DownloadItemRole,
     HoveredItemRole,
     DownloadButtonHoveredRole,
-    DownloadButtonPressedRole
+    DownloadButtonPressedRole,
+    AuthorHoveredRole,
+    AuthorPressedRole
 };
 
 enum ItemTypes {
@@ -49,6 +51,7 @@ public:
     bool rowExists( int row ) const { return (( row >= 0 ) && ( row < videos.size() ) ); }
     int activeRow() const { return m_activeRow; } // returns -1 if there is no active row
     int nextRow() const;
+    int previousRow() const;
     void removeIndexes(QModelIndexList &indexes);
     int rowForVideo(Video* video);
     QModelIndex indexForVideo(Video* video);
@@ -70,6 +73,14 @@ public slots:
     void searchError(QString message);
     void updateThumbnail();
 
+    void setHoveredRow(int row);
+    void clearHover();
+    void enterAuthorHover();
+    void exitAuthorHover();
+    void enterAuthorPressed();
+    void exitAuthorPressed();
+    void updateAuthor();
+
 signals:
     void activeRowChanged(int);
     void needSelectionFor(QList<Video*>);
@@ -90,6 +101,10 @@ private:
     Video *m_activeVideo;
 
     QString errorMessage;
+
+    int hoveredRow;
+    bool authorHovered;
+    bool authorPressed;
 };
 
 #endif
index 137ee6f46550b0bb7c7c613402864e68119d7458..b7c9b1ba1e1b0ecd1792ee8fe3a41212d840ac52 100644 (file)
@@ -13,6 +13,7 @@
 #include "mac_startup.h"
 #include "macfullscreen.h"
 #include "macsupport.h"
+#include "macutils.h"
 #endif
 #ifndef Q_WS_X11
 #include "extra.h"
 #include "demostartupview.h"
 #endif
 #include "temporary.h"
+#ifdef APP_MAC
+#include "searchlineedit_mac.h"
+#else
+#include "searchlineedit.h"
+#endif
+
+static MainWindow *singleton = 0;
+
+MainWindow* MainWindow::instance() {
+    if (!singleton) singleton = new MainWindow();
+    return singleton;
+}
 
 MainWindow::MainWindow() :
         aboutView(0),
@@ -33,6 +46,8 @@ MainWindow::MainWindow() :
         m_fullscreen(false),
         updateChecker(0) {
 
+    singleton = this;
+
     // views mechanism
     history = new QStack<QWidget*>();
     views = new QStackedWidget(this);
@@ -46,11 +61,6 @@ MainWindow::MainWindow() :
     mediaView = new MediaView(this);
     views->addWidget(mediaView);
 
-    toolbarSearch = new SearchLineEdit(this);
-    toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
-    toolbarSearch->setSuggester(new YouTubeSuggest(this));
-    connect(toolbarSearch, SIGNAL(search(const QString&)), this, SLOT(startToolbarSearch(const QString&)));
-
     // build ui
     createActions();
     createMenus();
@@ -94,6 +104,7 @@ MainWindow::MainWindow() :
     connect(&shortcuts, SIGNAL(PlayPause()), pauseAct, SLOT(trigger()));
     connect(&shortcuts, SIGNAL(Stop()), this, SLOT(stop()));
     connect(&shortcuts, SIGNAL(Next()), skipAct, SLOT(trigger()));
+    connect(&shortcuts, SIGNAL(Previous()), skipBackwardAct, SLOT(trigger()));
 
     connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
             SLOT(updateDownloadMessage(QString)));
@@ -110,6 +121,15 @@ MainWindow::~MainWindow() {
     delete history;
 }
 
+void MainWindow::changeEvent(QEvent* event) {
+#ifdef APP_MAC
+    if (event->type() == QEvent::WindowStateChange) {
+        The::globalActions()->value("minimize")->setEnabled(!isMinimized());
+    }
+#endif
+    QMainWindow::changeEvent(event);
+}
+
 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
 #ifdef Q_WS_X11
     if (event->type() == QEvent::MouseMove && this->m_fullscreen) {
@@ -143,6 +163,18 @@ void MainWindow::createActions() {
     actions->insert("stop", stopAct);
     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
 
+    skipBackwardAct = new QAction(
+                QtIconLoader::icon("media-skip-backward"),
+                tr("P&revious"), this);
+    skipBackwardAct->setStatusTip(tr("Go back to the previous track"));
+    skipBackwardAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Left));
+#if QT_VERSION >= 0x040600
+    skipBackwardAct->setPriority(QAction::LowPriority);
+#endif
+    skipBackwardAct->setEnabled(false);
+    actions->insert("previous", skipBackwardAct);
+    connect(skipBackwardAct, SIGNAL(triggered()), mediaView, SLOT(skipBackward()));
+
     skipAct = new QAction(QtIconLoader::icon("media-skip-forward"), tr("S&kip"), this);
     skipAct->setStatusTip(tr("Skip to the next video"));
     skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
@@ -163,7 +195,7 @@ void MainWindow::createActions() {
 #ifdef APP_MAC
     fsShortcuts << QKeySequence(Qt::CTRL + Qt::META + Qt::Key_F);
 #else
-    fsShortcuts << QKeySequence(Qt::Key_F11);
+    fsShortcuts << QKeySequence(Qt::Key_F11) << QKeySequence(Qt::ALT + Qt::Key_Return);
 #endif
     fullscreenAct->setShortcuts(fsShortcuts);
     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
@@ -247,10 +279,10 @@ void MainWindow::createActions() {
 
     quitAct = new QAction(tr("&Quit"), this);
     quitAct->setMenuRole(QAction::QuitRole);
-    quitAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Q")) << QKeySequence(Qt::CTRL + Qt::Key_W));
+    quitAct->setShortcut(QKeySequence::Quit);
     quitAct->setStatusTip(tr("Bye"));
     actions->insert("quit", quitAct);
-    connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
+    connect(quitAct, SIGNAL(triggered()), SLOT(quit()));
 
     siteAct = new QAction(tr("&Website"), this);
     siteAct->setShortcut(QKeySequence::HelpContents);
@@ -281,13 +313,13 @@ void MainWindow::createActions() {
     addAction(searchFocusAct);
 
     volumeUpAct = new QAction(this);
-    volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus) << QKeySequence(Qt::Key_VolumeUp));
+    volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus));
     actions->insert("volume-up", volumeUpAct);
     connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
     addAction(volumeUpAct);
 
     volumeDownAct = new QAction(this);
-    volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus) << QKeySequence(Qt::Key_VolumeDown));
+    volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus));
     actions->insert("volume-down", volumeDownAct);
     connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
     addAction(volumeDownAct);
@@ -295,9 +327,7 @@ void MainWindow::createActions() {
     volumeMuteAct = new QAction(this);
     volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
     volumeMuteAct->setStatusTip(tr("Mute volume"));
-    volumeMuteAct->setShortcuts(QList<QKeySequence>()
-                                << QKeySequence(tr("Ctrl+M"))
-                                << QKeySequence(Qt::Key_VolumeMute));
+    volumeMuteAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_E));
     actions->insert("volume-mute", volumeMuteAct);
     connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
     addAction(volumeMuteAct);
@@ -366,6 +396,23 @@ void MainWindow::createActions() {
     actions->insert("email", action);
     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaEmail()));
 
+    action = new QAction(tr("&Close"), this);
+    action->setShortcut(QKeySequence(QKeySequence::Close));
+    actions->insert("close", action);
+    connect(action, SIGNAL(triggered()), SLOT(close()));
+
+    action = new QAction(QtIconLoader::icon("go-top"), tr("&Float on Top"), this);
+    action->setCheckable(true);
+    actions->insert("ontop", action);
+    connect(action, SIGNAL(toggled(bool)), SLOT(floatOnTop(bool)));
+
+    action = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop after this video"), this);
+    action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Escape));
+    action->setCheckable(true);
+    action->setEnabled(false);
+    actions->insert("stopafterthis", action);
+    connect(action, SIGNAL(toggled(bool)), SLOT(showStopAfterThisInStatusBar(bool)));
+
     // common action properties
     foreach (QAction *action, actions->values()) {
 
@@ -378,7 +425,6 @@ void MainWindow::createActions() {
         action->setAutoRepeat(false);
 
         // set to something more meaningful then the toolbar text
-        // HELP! how to remove tooltips altogether?!
         if (!action->statusTip().isEmpty())
             action->setToolTip(action->statusTip());
 
@@ -398,7 +444,12 @@ void MainWindow::createMenus() {
     QMap<QString, QMenu*> *menus = The::globalMenus();
 
     fileMenu = menuBar()->addMenu(tr("&Application"));
-    // menus->insert("file", fileMenu);
+#ifdef APP_DEMO
+    QAction* action = new QAction(tr("Buy %1...").arg(Constants::NAME), this);
+    action->setMenuRole(QAction::ApplicationSpecificRole);
+    connect(action, SIGNAL(triggered()), SLOT(buy()));
+    fileMenu->addAction(action);
+#endif
     fileMenu->addAction(clearAct);
 #ifndef APP_MAC
     fileMenu->addSeparator();
@@ -407,9 +458,12 @@ void MainWindow::createMenus() {
 
     QMenu* playbackMenu = menuBar()->addMenu(tr("&Playback"));
     menus->insert("playback", playbackMenu);
-    playbackMenu->addAction(stopAct);
     playbackMenu->addAction(pauseAct);
+    playbackMenu->addAction(stopAct);
+    playbackMenu->addAction(The::globalActions()->value("stopafterthis"));
+    playbackMenu->addSeparator();
     playbackMenu->addAction(skipAct);
+    playbackMenu->addAction(skipBackwardAct);
 #ifdef APP_MAC
     MacSupport::dockMenu(playbackMenu);
 #endif
@@ -436,6 +490,8 @@ void MainWindow::createMenus() {
     menus->insert("view", viewMenu);
     viewMenu->addAction(fullscreenAct);
     viewMenu->addAction(compactViewAct);
+    viewMenu->addSeparator();
+    viewMenu->addAction(The::globalActions()->value("ontop"));
 
     QMenu* shareMenu = menuBar()->addMenu(tr("&Share"));
     menus->insert("share", shareMenu);
@@ -445,6 +501,10 @@ void MainWindow::createMenus() {
     shareMenu->addAction(The::globalActions()->value("facebook"));
     shareMenu->addAction(The::globalActions()->value("email"));
 
+#ifdef APP_MAC
+    MacSupport::windowMenu(this);
+#endif
+
     helpMenu = menuBar()->addMenu(tr("&Help"));
     helpMenu->addAction(siteAct);
 #if !defined(APP_MAC) && !defined(APP_WIN)
@@ -530,16 +590,32 @@ void MainWindow::createToolBars() {
 
     mainToolBar->addWidget(new Spacer());
 
+#ifdef APP_MAC
+    SearchWrapper* searchWrapper = new SearchWrapper(this);
+    toolbarSearch = searchWrapper->getSearchLineEdit();
+#else
+    toolbarSearch = new SearchLineEdit(this);
+#endif
+    toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
+    toolbarSearch->setSuggester(new YouTubeSuggest(this));
+    connect(toolbarSearch, SIGNAL(search(const QString&)), this, SLOT(startToolbarSearch(const QString&)));
+    connect(toolbarSearch, SIGNAL(suggestionAccepted(const QString&)), SLOT(startToolbarSearch(const QString&)));
     toolbarSearch->setStatusTip(searchFocusAct->statusTip());
+#ifdef APP_MAC
+    mainToolBar->addWidget(searchWrapper);
+#else
     mainToolBar->addWidget(toolbarSearch);
-
-    mainToolBar->addWidget(new Spacer());
+    Spacer* spacer = new Spacer();
+    spacer->setWidth(4);
+    mainToolBar->addWidget(spacer);
+#endif
 
     addToolBar(mainToolBar);
 }
 
 void MainWindow::createStatusBar() {
-    QToolBar *toolBar = new QToolBar(this);
+    QToolBar* toolBar = new QToolBar(this);
+    statusToolBar = toolBar;
     toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
     toolBar->setIconSize(QSize(16, 16));
     toolBar->addAction(The::globalActions()->value("downloads"));
@@ -549,6 +625,24 @@ void MainWindow::createStatusBar() {
     statusBar()->show();
 }
 
+void MainWindow::showStopAfterThisInStatusBar(bool show) {
+    QAction* action = The::globalActions()->value("stopafterthis");
+    if (show) {
+        statusToolBar->insertAction(statusToolBar->actions().first(), action);
+    } else {
+        statusToolBar->removeAction(action);
+    }
+}
+
+void MainWindow::showFloatOnTopInStatusBar(bool show) {
+    QAction* action = The::globalActions()->value("ontop");
+    if (show) {
+        statusToolBar->insertAction(statusToolBar->actions().first(), action);
+    } else {
+        statusToolBar->removeAction(action);
+    }
+}
+
 void MainWindow::readSettings() {
     QSettings settings;
     restoreGeometry(settings.value("geometry").toByteArray());
@@ -612,12 +706,18 @@ void MainWindow::showWidget ( QWidget* widget ) {
     findVideoPartsAct->setEnabled(widget == mediaView);
     toolbarSearch->setEnabled(widget == searchView || widget == mediaView || widget == downloadView);
 
+    if (widget == searchView) {
+        skipAct->setEnabled(false);
+        The::globalActions()->value("previous")->setEnabled(false);
+        The::globalActions()->value("download")->setEnabled(false);
+        The::globalActions()->value("stopafterthis")->setEnabled(false);
+    }
+
     The::globalActions()->value("twitter")->setEnabled(widget == mediaView);
     The::globalActions()->value("facebook")->setEnabled(widget == mediaView);
     The::globalActions()->value("email")->setEnabled(widget == mediaView);
 
     aboutAct->setEnabled(widget != aboutView);
-    The::globalActions()->value("download")->setEnabled(widget == mediaView);
     The::globalActions()->value("downloads")->setChecked(widget == downloadView);
 
     // toolbar only for the mediaView
@@ -659,18 +759,39 @@ void MainWindow::donate() {
 }
 
 void MainWindow::quit() {
+#ifdef APP_MAC
+    if (!confirmQuit()) {
+        return;
+    }
+#endif
     writeSettings();
     Temporary::deleteAll();
     qApp->quit();
 }
 
 void MainWindow::closeEvent(QCloseEvent *event) {
+#ifdef APP_MAC
+    mac::closeWindow(winId());
+    event->ignore();
+#else
+    if (!confirmQuit()) {
+        event->ignore();
+        return;
+    }
+    quit();
+    QWidget::closeEvent(event);
+#endif
+}
+
+bool MainWindow::confirmQuit() {
     if (DownloadManager::instance()->activeItems() > 0) {
-        QMessageBox msgBox;
+        QMessageBox msgBox(this);
         msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
         msgBox.setText(tr("Do you want to exit %1 with a download in progress?").arg(Constants::NAME));
         msgBox.setInformativeText(tr("If you close %1 now, this download will be cancelled.").arg(Constants::NAME));
         msgBox.setModal(true);
+        // make it a "sheet" on the Mac
+        msgBox.setWindowModality(Qt::WindowModal);
 
         msgBox.addButton(tr("Close and cancel download"), QMessageBox::RejectRole);
         QPushButton *waitButton = msgBox.addButton(tr("Wait for download to finish"), QMessageBox::ActionRole);
@@ -678,13 +799,10 @@ void MainWindow::closeEvent(QCloseEvent *event) {
         msgBox.exec();
 
         if (msgBox.clickedButton() == waitButton) {
-            event->ignore();
-            return;
+            return false;
         }
-
     }
-    quit();
-    QWidget::closeEvent(event);
+    return true;
 }
 
 void MainWindow::showSearch() {
@@ -694,9 +812,6 @@ void MainWindow::showSearch() {
 }
 
 void MainWindow::showMedia(SearchParams *searchParams) {
-    if (toolbarSearch->text().isEmpty() && !searchParams->keywords().isEmpty()) {
-        toolbarSearch->lineEdit()->setText(searchParams->keywords());
-    }
     mediaView->search(searchParams);
     showWidget(mediaView);
 }
@@ -722,18 +837,15 @@ void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState
         pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
         pauseAct->setText(tr("&Pause"));
         pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
-        skipAct->setEnabled(true);
         // stopAct->setEnabled(true);
         break;
 
          case Phonon::StoppedState:
         pauseAct->setEnabled(false);
-        skipAct->setEnabled(false);
         // stopAct->setEnabled(false);
         break;
 
          case Phonon::PausedState:
-        skipAct->setEnabled(true);
         pauseAct->setEnabled(true);
         pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
         pauseAct->setText(tr("&Play"));
@@ -743,7 +855,6 @@ void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState
 
          case Phonon::BufferingState:
          case Phonon::LoadingState:
-        skipAct->setEnabled(true);
         pauseAct->setEnabled(false);
         currentTime->clear();
         totalTime->clear();
@@ -1205,3 +1316,24 @@ void MainWindow::gotNewVersion(QString version) {
     }
 
 }
+
+void MainWindow::floatOnTop(bool onTop) {
+    showFloatOnTopInStatusBar(onTop);
+#ifdef APP_MAC
+    mac::floatOnTop(winId(), onTop);
+    return;
+#endif
+    if (onTop) {
+        setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
+    } else {
+        setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
+    }
+}
+
+void MainWindow::messageReceived(const QString &message) {
+    if (!message.isEmpty()) {
+        SearchParams *searchParams = new SearchParams();
+        searchParams->setKeywords(message);
+        showMedia(searchParams);
+    }
+}
index b0c71b0ab45eabd2e9a961533ae8522c4341bdac..776afb0195042bde0a54cc0ae1debabaca1a8f82 100644 (file)
@@ -2,7 +2,6 @@
 #define MAINWINDOW_H
 
 #include <QtGui>
-#include "searchlineedit.h"
 #include <phonon/audiooutput.h>
 #include <phonon/volumeslider.h>
 #include <phonon/mediaobject.h>
@@ -13,6 +12,7 @@
 #include "AboutView.h"
 #include "downloadview.h"
 
+class SearchLineEdit;
 class UpdateChecker;
 
 class MainWindow : public QMainWindow {
@@ -20,14 +20,19 @@ class MainWindow : public QMainWindow {
     Q_OBJECT
 
 public:
+    static MainWindow* instance();
     MainWindow();
     ~MainWindow();
     Phonon::SeekSlider* getSeekSlider() { return seekSlider; }
+    void readSettings();
+    void writeSettings();
 
 public slots:
     void showMedia(SearchParams *params);
+    void messageReceived(const QString &message);
 
 protected:
+    void changeEvent(QEvent *);
     void closeEvent(QCloseEvent *);
     bool eventFilter(QObject *obj, QEvent *event);
     void dragEnterEvent(QDragEnterEvent *event);
@@ -72,6 +77,9 @@ private slots:
     void toggleDownloads(bool show);
 
     void startToolbarSearch(QString query);
+    void floatOnTop(bool);
+    void showFloatOnTopInStatusBar(bool show);
+    void showStopAfterThisInStatusBar(bool show);
 
 private:
     void initPhonon();
@@ -79,10 +87,9 @@ private:
     void createMenus();
     void createToolBars();
     void createStatusBar();
-    void readSettings();
-    void writeSettings();
     void showWidget(QWidget*);
     static QString formatTime(qint64 time);
+    bool confirmQuit();
 
     UpdateChecker *updateChecker;
 
@@ -106,6 +113,7 @@ private:
     QAction *searchFocusAct;
 
     // media actions
+    QAction *skipBackwardAct;
     QAction *skipAct;
     QAction *pauseAct;
     QAction *stopAct;
@@ -135,6 +143,7 @@ private:
     // toolbar
     QToolBar *mainToolBar;
     SearchLineEdit *toolbarSearch;
+    QToolBar *statusToolBar;
 
     // phonon
     Phonon::SeekSlider *seekSlider;
index 324adfcabef2086fef94a9691fb13ceaf2fed66a..1edc22b0cdc826339e262dd4cefe3eac726395b4 100644 (file)
@@ -1,4 +1,5 @@
 #include "MediaView.h"
+#include "playlistview.h"
 #include "playlist/PrettyItemDelegate.h"
 #include "networkaccess.h"
 #include "videowidget.h"
@@ -30,7 +31,7 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) {
     splitter = new MiniSplitter(this);
     splitter->setChildrenCollapsible(false);
 
-    sortBar = new THBlackBar(this);
+    sortBar = new SegmentedControl(this);
     mostRelevantAction = new QAction(tr("Most relevant"), this);
     QKeySequence keySequence(Qt::CTRL + Qt::Key_1);
     mostRelevantAction->setShortcut(keySequence);
@@ -53,7 +54,7 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) {
     connect(mostViewedAction, SIGNAL(triggered()), this, SLOT(searchMostViewed()), Qt::QueuedConnection);
     sortBar->addAction(mostViewedAction);
 
-    listView = new QListView(this);
+    listView = new PlaylistView(this);
     listView->setItemDelegate(new PrettyItemDelegate(this));
     listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
 
@@ -83,6 +84,8 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) {
             SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )),
             this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & )));
 
+    connect(listView, SIGNAL(authorPushed(QModelIndex)), SLOT(authorPushed(QModelIndex)));
+
     playlistWidget = new PlaylistWidget(this, sortBar, listView);
 
     splitter->addWidget(playlistWidget);
@@ -197,6 +200,10 @@ void MediaView::search(SearchParams *searchParams) {
 
 }
 
+void MediaView::appear() {
+    listView->setFocus();
+}
+
 void MediaView::disappear() {
     timerPlayFlag = true;
 }
@@ -259,8 +266,6 @@ void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/)
         qDebug("loading");
         break;
 
-    default:
-        ;
     }
 }
 
@@ -332,7 +337,6 @@ void MediaView::activeRowChanged(int row) {
     QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
     if (mainWindow) mainWindow->statusBar()->showMessage(video->title());
 
-    The::globalActions()->value("download")->setEnabled(DownloadManager::instance()->itemForVideo(video) == 0);
 
     // ensure active item is visible
     // int row = listModel->activeRow();
@@ -341,6 +345,12 @@ void MediaView::activeRowChanged(int row) {
         listView->scrollTo(index, QAbstractItemView::EnsureVisible);
     }
 
+    // enable/disable actions
+    The::globalActions()->value("download")->setEnabled(DownloadManager::instance()->itemForVideo(video) == 0);
+    The::globalActions()->value("skip")->setEnabled(true);
+    The::globalActions()->value("previous")->setEnabled(row > 0);
+    The::globalActions()->value("stopafterthis")->setEnabled(true);
+
     // see you in gotStreamUrl...
 
 }
@@ -483,13 +493,24 @@ void MediaView::skip() {
     listModel->setActiveRow(nextRow);
 }
 
+void MediaView::skipBackward() {
+    int prevRow = listModel->previousRow();
+    if (prevRow == -1) return;
+    listModel->setActiveRow(prevRow);
+}
+
 void MediaView::playbackFinished() {
     // qDebug() << "finished" << mediaObject->currentTime() << mediaObject->totalTime();
     // add 10 secs for imprecise Phonon backends (VLC, Xine)
     if (mediaObject->currentTime() + 10000 < mediaObject->totalTime()) {
         // mediaObject->seek(mediaObject->currentTime());
         QTimer::singleShot(3000, this, SLOT(playbackResume()));
-    } else skip();
+    } else {
+        QAction* stopAfterThisAction = The::globalActions()->value("stopafterthis");
+        if (stopAfterThisAction->isChecked()) {
+            stopAfterThisAction->setChecked(false);
+        } else skip();
+    }
 }
 
 void MediaView::playbackResume() {
@@ -815,3 +836,18 @@ void MediaView::shareViaEmail() {
     url.addQueryItem("body", body);
     QDesktopServices::openUrl(url);
 }
+
+void MediaView::authorPushed(QModelIndex index) {
+    Video* video = listModel->videoAt(index.row());
+    if (!video) return;
+
+    QString channel = video->author();
+    if (channel.isEmpty()) return;
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setAuthor(channel);
+    searchParams->setSortBy(SearchParams::SortByNewest);
+
+    // go!
+    search(searchParams);
+}
index acfa6a6189f557b619040e5d8b7330673bb91370..c6deee181e4aef8f9e919eb26a1e294fa36e8ccb 100644 (file)
@@ -7,13 +7,14 @@
 #include <phonon/videowidget.h>
 #include "View.h"
 #include "ListModel.h"
-#include "thlibrary/thblackbar.h"
+#include "segmentedcontrol.h"
 #include "searchparams.h"
 #include "playlistwidget.h"
 #include "loadingwidget.h"
 #include "videoareawidget.h"
 
 class DownloadItem;
+class PlaylistView;
 
 namespace The {
     QMap<QString, QAction*>* globalActions();
@@ -27,9 +28,7 @@ public:
     void initialize();
 
     // View
-    void appear() {
-        listView->setFocus();
-    }
+    void appear();
     void disappear();
     QMap<QString, QVariant> metadata() {
         QMap<QString, QVariant> metadata;
@@ -48,6 +47,7 @@ public slots:
     void pause();
     void stop();
     void skip();
+    void skipBackward();
     void skipVideo();
     void openWebPage();
     void copyWebPage();
@@ -90,6 +90,7 @@ private slots:
     void downloadStatusChanged();
     void playbackFinished();
     void playbackResume();
+    void authorPushed(QModelIndex);
 
     /*
     void downloadProgress(int percent);
@@ -105,11 +106,11 @@ private:
     QSplitter *splitter;
 
     PlaylistWidget *playlistWidget;
-    QListView *listView;
+    PlaylistView *listView;
     ListModel *listModel;
 
     // sortBar
-    THBlackBar *sortBar;
+    SegmentedControl *sortBar;
     QAction *mostRelevantAction;
     QAction *mostRecentAction;
     QAction *mostViewedAction;
@@ -134,7 +135,6 @@ private:
 #endif
 
     DownloadItem *downloadItem;
-    // QSlider *slider;
 
 };
 
index 4bfd3fda944c59b703e67d3f5e0f104e860c73a0..411d952cb36af912ee3762f38c14280c292c78d8 100644 (file)
@@ -4,6 +4,11 @@
 #include "searchparams.h"
 #include "youtubesuggest.h"
 #include "channelsuggest.h"
+#ifdef APP_MAC
+#include "searchlineedit_mac.h"
+#else
+#include "searchlineedit.h"
+#endif
 
 namespace The {
     QMap<QString, QAction*>* globalActions();
@@ -109,10 +114,9 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
     queryEdit = new SearchLineEdit(this);
     queryEdit->setFont(biggerFont);
     queryEdit->setMinimumWidth(queryEdit->fontInfo().pixelSize()*15);
-    queryEdit->sizeHint();
-    queryEdit->setFocus(Qt::OtherFocusReason);
-    connect(queryEdit, SIGNAL(search(const QString&)), this, SLOT(watch(const QString&)));
-    connect(queryEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &)));
+    connect(queryEdit, SIGNAL(search(const QString&)), SLOT(watch(const QString&)));
+    connect(queryEdit, SIGNAL(textChanged(const QString &)), SLOT(textChanged(const QString &)));
+    connect(queryEdit, SIGNAL(suggestionAccepted(const QString&)), SLOT(watch(const QString&)));
 
     youtubeSuggest = new YouTubeSuggest(this);
     channelSuggest = new ChannelSuggest(this);
@@ -140,13 +144,8 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
     recentKeywordsLayout->setSpacing(5);
     recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
     recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
-#if defined(APP_MAC) | defined(APP_WIN)
-    QPalette palette = recentKeywordsLabel->palette();
-    palette.setColor(QPalette::WindowText, QColor(0x65, 0x71, 0x80));
-    recentKeywordsLabel->setPalette(palette);
-#else
+    recentKeywordsLabel->setProperty("recentHeader", true);
     recentKeywordsLabel->setForegroundRole(QPalette::Dark);
-#endif
     recentKeywordsLabel->hide();
     recentKeywordsLabel->setFont(smallerFont);
     recentKeywordsLayout->addWidget(recentKeywordsLabel);
@@ -158,13 +157,8 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
     recentChannelsLayout->setSpacing(5);
     recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
     recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
-#if defined(APP_MAC) | defined(APP_WIN)
-    palette = recentChannelsLabel->palette();
-    palette.setColor(QPalette::WindowText, QColor(0x65, 0x71, 0x80));
-    recentChannelsLabel->setPalette(palette);
-#else
+    recentChannelsLabel->setProperty("recentHeader", true);
     recentChannelsLabel->setForegroundRole(QPalette::Dark);
-#endif
     recentChannelsLabel->hide();
     recentChannelsLabel->setFont(smallerFont);
     recentChannelsLayout->addWidget(recentChannelsLabel);
@@ -180,6 +174,14 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
 
 }
 
+void SearchView::appear() {
+    updateRecentKeywords();
+    updateRecentChannels();
+    queryEdit->selectAll();
+    queryEdit->enableSuggest();
+    QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
+}
+
 void SearchView::updateRecentKeywords() {
 
     // cleanup
@@ -215,6 +217,7 @@ void SearchView::updateRecentKeywords() {
                                        + "\" style=\"color:palette(text); text-decoration:none\">"
                                        + display + "</a>", this);
         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
+        itemLabel->setProperty("recentItem", true);
         itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
         // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
         // Make links navigable with the keyboard too
@@ -256,6 +259,7 @@ void SearchView::updateRecentChannels() {
                                        + "\" style=\"color:palette(text); text-decoration:none\">"
                                        + display + "</a>", this);
         itemLabel->setAttribute(Qt::WA_DeleteOnClose);
+        itemLabel->setProperty("recentItem", true);
         itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
         // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
         // Make links navigable with the keyboard too
@@ -311,7 +315,7 @@ void SearchView::watchChannel(QString channel) {
     }
 
     // remove spaces from channel name
-    channel = channel.replace(" ", "");
+    channel = channel.remove(" ");
 
     SearchParams *searchParams = new SearchParams();
     searchParams->setAuthor(channel);
index 30888d3f9bbb471f92e3f6bc304b52b7d448dd59..b6be2755c2f5f15dbc24970618dec22a5081e230 100644 (file)
@@ -3,8 +3,8 @@
 
 #include <QtGui>
 #include "View.h"
-#include "searchlineedit.h"
 
+class SearchLineEdit;
 class SearchParams;
 class YouTubeSuggest;
 class ChannelSuggest;
@@ -17,15 +17,7 @@ public:
     SearchView(QWidget *parent);
     void updateRecentKeywords();
     void updateRecentChannels();
-
-    void appear() {
-        updateRecentKeywords();
-        updateRecentChannels();
-        queryEdit->clear();
-        queryEdit->enableSuggest();
-        QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
-    }
-
+    void appear();
     void disappear() {}
 
     QMap<QString, QVariant> metadata() {
index 1db03ee648084d95578ee4f65fb64730bb8e597f..a50fe38419da06b338d44297919da693f5dc0bad 100644 (file)
@@ -2,18 +2,20 @@
 #include "suggester.h"
 
 AutoComplete::AutoComplete(QWidget *parent, QLineEdit *editor):
-        QObject(parent), buddy(parent), editor(editor), suggester(0) {
+    QObject(parent), buddy(parent), editor(editor), suggester(0) {
 
     enabled = true;
 
     popup = new QListWidget;
     popup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-    popup->installEventFilter(this);
     popup->setMouseTracking(true);
     popup->setWindowOpacity(.9);
+    popup->installEventFilter(this);
+    popup->setWindowFlags(Qt::Popup);
+    popup->setFocusPolicy(Qt::NoFocus);
+    popup->setFocusProxy(parent);
 
-    connect(popup, SIGNAL(itemClicked(QListWidgetItem*)),
-            SLOT(doneCompletion()));
+    connect(popup, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(doneCompletion()));
 
     // connect(popup, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
     //    SLOT(currentItemChanged(QListWidgetItem *)));
@@ -22,15 +24,11 @@ AutoComplete::AutoComplete(QWidget *parent, QLineEdit *editor):
     // connect(popup, SIGNAL(itemEntered(QListWidgetItem*)),
     //    SLOT(currentItemChanged(QListWidgetItem *)));
 
-    popup->setWindowFlags(Qt::Popup);
-    popup->setFocusPolicy(Qt::NoFocus);
-    popup->setFocusProxy(parent);
-
     timer = new QTimer(this);
     timer->setSingleShot(true);
     timer->setInterval(300);
     connect(timer, SIGNAL(timeout()), SLOT(autoSuggest()));
-    connect(editor, SIGNAL(textEdited(QString)), timer, SLOT(start()));
+    connect(parent, SIGNAL(textChanged(QString)), timer, SLOT(start()));
 
 }
 
@@ -114,7 +112,7 @@ void AutoComplete::showCompletion(const QStringList &choices) {
     popup->adjustSize();
     popup->setUpdatesEnabled(true);
 
-    int h = popup->sizeHintForRow(0) * choices.count() + 4;
+    int h = popup->sizeHintForRow(0) * choices.count();
     popup->resize(buddy->width(), h);
 
     popup->move(buddy->mapToGlobal(QPoint(0, buddy->height())));
@@ -130,11 +128,7 @@ void AutoComplete::doneCompletion() {
     QListWidgetItem *item = popup->currentItem();
     if (item) {
         editor->setText(item->text());
-        QKeyEvent *e;
-        e = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
-        QApplication::postEvent(editor, e);
-        e = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier);
-        QApplication::postEvent(editor, e);
+        emit suggestionAccepted(item->text());
     }
 }
 
@@ -162,7 +156,10 @@ void AutoComplete::autoSuggest() {
     QString query = editor->text();
     originalText = query;
     // qDebug() << "originalText" << originalText;
-    if (query.isEmpty()) return;
+    if (query.isEmpty()) {
+        popup->hide();
+        return;
+    }
 
     if (suggester)
         suggester->suggest(query);
index 9a6e8b31c5b2a871d5cb6e05e2cfc23ef7c0d5de..46e45253bd56c7810948a05d89a6ddb6e3f225bb 100644 (file)
@@ -14,6 +14,7 @@ public:
     bool eventFilter(QObject *obj, QEvent *ev);
     void showCompletion(const QStringList &choices);
     void setSuggester(Suggester* suggester);
+    QListWidget* getPopup() { return popup; }
 
 public slots:
     void doneCompletion();
@@ -23,6 +24,9 @@ public slots:
     void currentItemChanged(QListWidgetItem *current);
     void suggestionsReady(QStringList suggestions);
 
+signals:
+    void suggestionAccepted(QString suggestion);
+
 private:
     QWidget *buddy;
     QLineEdit *editor;
index c919e2aaa74a041ad6aa09eb4680c5b945282a5a..8e66e294926764ef765cc46199bb090cc5dbc832 100644 (file)
@@ -5,6 +5,10 @@
 #include <QDesktopServices>
 #include <QDebug>
 
+#ifdef APP_MAC
+#include "macutils.h"
+#endif
+
 namespace The {
     NetworkAccess* http();
 }
@@ -86,8 +90,12 @@ void DownloadItem::open() {
 
 void DownloadItem::openFolder() {
     QFileInfo info(m_file);
+#ifdef APP_MAC
+    mac::showInFinder(info.absoluteFilePath());
+#else
     QUrl url = QUrl::fromLocalFile(info.absolutePath());
     QDesktopServices::openUrl(url);
+#endif
 }
 
 void DownloadItem::tryAgain() {
index 3a87956ffcc4c7f4c93d5c7f9286e4c74722a0bf..25ddf2feb56ad3e6668c90dc259a7b70b412b6bc 100644 (file)
@@ -1,13 +1,9 @@
 #include "downloadlistview.h"
 #include "downloadmodel.h"
 #include "playlist/PrettyItemDelegate.h"
-#include <QtGui>
 
 DownloadListView::DownloadListView(QWidget *parent) : QListView(parent) {
 
-    // playIconHovered = false;
-    // setMouseTracking(true);
-
 }
 
 void DownloadListView::leaveEvent(QEvent * /* event */) {
@@ -21,9 +17,9 @@ void DownloadListView::mouseMoveEvent(QMouseEvent *event) {
     QListView::mouseMoveEvent(event);
 
     if (isHoveringPlayIcon(event)) {
-        QMetaObject::invokeMethod(model(), "enterPlayIconHover", Qt::DirectConnection);
+        QMetaObject::invokeMethod(model(), "enterPlayIconHover");
     } else {
-        QMetaObject::invokeMethod(model(), "exitPlayIconHover", Qt::DirectConnection);
+        QMetaObject::invokeMethod(model(), "exitPlayIconHover");
     }
 
 }
@@ -31,7 +27,7 @@ void DownloadListView::mouseMoveEvent(QMouseEvent *event) {
 void DownloadListView::mousePressEvent(QMouseEvent *event) {
     if (event->button() == Qt::LeftButton
         && isHoveringPlayIcon(event)) {
-        QMetaObject::invokeMethod(model(), "enterPlayIconPressed", Qt::DirectConnection);
+        QMetaObject::invokeMethod(model(), "enterPlayIconPressed");
     } else {
         QListView::mousePressEvent(event);
     }
@@ -39,7 +35,7 @@ void DownloadListView::mousePressEvent(QMouseEvent *event) {
 
 void DownloadListView::mouseReleaseEvent(QMouseEvent *event) {
     if (event->button() == Qt::LeftButton) {
-        QMetaObject::invokeMethod(model(), "exitPlayIconPressed", Qt::DirectConnection);
+        QMetaObject::invokeMethod(model(), "exitPlayIconPressed");
         if (isHoveringPlayIcon(event))
             emit downloadButtonPushed(indexAt(event->pos()));
     } else {
index 2aae0ffb1e6645acb242eb27746c50f9f4a17505..72f457ae73be65a82dd49a29db2e58c6eabe6036 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef DOWNLOADLISTVIEW_H
 #define DOWNLOADLISTVIEW_H
 
-#include <QListView>
-#include <QModelIndex>
+#include <QtGui>
 
 class DownloadListView : public QListView {
 
index 9ab12a9ee2182229fe7b3e7ea966906c322f935c..3ed343b7e30f32d3a25519d44b904a912346de0b 100644 (file)
@@ -6,7 +6,7 @@
 #include "downloadsettings.h"
 #include "ListModel.h"
 #include "playlist/PrettyItemDelegate.h"
-#include "thlibrary/thblackbar.h"
+#include "segmentedcontrol.h"
 
 DownloadView::DownloadView(QWidget *parent) : QWidget(parent) {
 
@@ -14,7 +14,7 @@ DownloadView::DownloadView(QWidget *parent) : QWidget(parent) {
     layout->setMargin(0);
     layout->setSpacing(0);
 
-    bar = new THBlackBar(this);
+    bar = new SegmentedControl(this);
     QAction *action = new QAction(tr("Downloads"), this);
     bar->addAction(action);
     layout->addWidget(bar);
index 10f558908c48e18497dbd8a60dc8274ed85ab3b7..fdbbb54ba841b689e32ebcb600e19535b31af10e 100644 (file)
@@ -4,7 +4,7 @@
 #include <QtGui>
 #include "View.h"
 
-class THBlackBar;
+class SegmentedControl;
 class DownloadModel;
 class DownloadListView;
 class DownloadSettings;
@@ -29,7 +29,7 @@ public slots:
     void buttonPushed(QModelIndex index);
 
 private:
-    THBlackBar *bar;
+    SegmentedControl *bar;
     DownloadListView *listView;
     DownloadModel *listModel;
     QTimer *updateTimer;
index b2df305140a7de4aa178a08c48cfb2b953497109..c114f7c1dd34639ad9eabda3cc28c1a77ef07307 100644 (file)
@@ -19,7 +19,8 @@ int main(int argc, char **argv) {
 #endif
 
     QtSingleApplication app(argc, argv);
-    if (app.sendMessage("Wake up!"))
+    QString message = app.arguments().size() > 1 ? app.arguments().at(1) : "";
+    if (app.sendMessage(message))
         return 0;
 
     app.setApplicationName(Constants::NAME);
@@ -69,6 +70,7 @@ int main(int argc, char **argv) {
     mainWin.setWindowTitle(Constants::NAME);
 
 #ifdef Q_WS_MAC
+    app.setQuitOnLastWindowClosed(false);
     mac::SetupFullScreenWindow(mainWin.winId());
 #endif
 
@@ -102,6 +104,7 @@ int main(int argc, char **argv) {
 
     mainWin.show();
 
+    mainWin.connect(&app, SIGNAL(messageReceived(const QString &)), &mainWin, SLOT(messageReceived(const QString &)));
     app.setActivationWindow(&mainWin, true);
 
     // all string literals are UTF-8
index 8194771c84cef04a5cb0c1476372cbab90ad8a5d..6cdac51014805cdb6efc823740a9419996ee9f28 100644 (file)
@@ -6,11 +6,15 @@
 
 #include <QFontMetricsF>
 #include <QPainter>
+#include <QHash>
 
 const qreal PrettyItemDelegate::THUMB_HEIGHT = 90.0;
 const qreal PrettyItemDelegate::THUMB_WIDTH = 120.0;
 const qreal PrettyItemDelegate::PADDING = 10.0;
 
+QRect lastAuthorRect;
+QHash<int, QRect> authorRects;
+
 PrettyItemDelegate::PrettyItemDelegate(QObject* parent, bool downloadInfo)
     : QStyledItemDelegate(parent),
     downloadInfo(downloadInfo) {
@@ -135,14 +139,27 @@ void PrettyItemDelegate::paintBody( QPainter* painter,
     painter->drawText(publishedTextBox, Qt::AlignLeft | Qt::AlignTop, publishedString);
 
     // author
+    bool authorHovered = false;
+    bool authorPressed = false;
+    const bool isHovered = index.data(HoveredItemRole).toBool();
+    if (isHovered) {
+        authorHovered = index.data(AuthorHoveredRole).toBool();
+        authorPressed = index.data(AuthorPressedRole).toBool();
+    }
+
     painter->save();
     painter->setFont(smallerBoldFont);
-    if (!isSelected && !isActive)
-        painter->setPen(QPen(option.palette.brush(QPalette::Mid), 0));
+    if (!isSelected) {
+        if (authorHovered)
+            painter->setPen(QPen(option.palette.brush(QPalette::Highlight), 0));
+        else
+            painter->setPen(QPen(option.palette.brush(QPalette::Mid), 0));
+    }
     QString authorString = video->author();
     QSizeF authorStringSize(QFontMetrics(painter->font()).size( Qt::TextSingleLine, authorString ) );
     textLoc.setX(textLoc.x() + publishedStringSize.width() + PADDING);
     QRectF authorTextBox( textLoc , authorStringSize);
+    authorRects.insert(index.row(), authorTextBox.toRect());
     painter->drawText(authorTextBox, Qt::AlignLeft | Qt::AlignTop, authorString);
     painter->restore();
 
@@ -358,3 +375,7 @@ QRect PrettyItemDelegate::downloadButtonRect(QRect line) const {
             16,
             16);
 }
+
+QRect PrettyItemDelegate::authorRect(const QModelIndex& index) const {
+    return authorRects.value(index.row());
+}
index 42605587a1920ff347ec234698c2a7321c72af1d..8934f578a597361de6465c282a6f391c1e9bc557 100644 (file)
@@ -18,6 +18,7 @@ public:
     QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
     void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
     QRect downloadButtonRect(QRect line) const;
+    QRect authorRect(const QModelIndex& index) const;
 
 private:
     void createPlayIcon();
@@ -44,6 +45,7 @@ private:
 
     bool downloadInfo;
     QProgressBar *progressBar;
+
 };
 
 #endif
diff --git a/src/playlistview.cpp b/src/playlistview.cpp
new file mode 100644 (file)
index 0000000..52bdb63
--- /dev/null
@@ -0,0 +1,76 @@
+#include "playlistview.h"
+#include "ListModel.h"
+#include "playlist/PrettyItemDelegate.h"
+
+PlaylistView::PlaylistView(QWidget *parent) : QListView(parent) {
+    connect(this, SIGNAL(entered(const QModelIndex &)), SLOT(itemEntered(const QModelIndex &)));
+    setMouseTracking(true);
+}
+
+void PlaylistView::itemEntered(const QModelIndex &index) {
+    ListModel *listModel = dynamic_cast<ListModel *>(model());
+    if (listModel) listModel->setHoveredRow(index.row());
+}
+
+void PlaylistView::leaveEvent(QEvent * /* event */) {
+    ListModel *listModel = dynamic_cast<ListModel *>(model());
+    if (listModel) listModel->clearHover();
+}
+
+void PlaylistView::mouseMoveEvent(QMouseEvent *event) {
+    // qDebug() << "PlaylistView::mouseMoveEvent" << event->pos();
+
+    QListView::mouseMoveEvent(event);
+
+    if (isHoveringAuthor(event)) {
+
+        // check for special "message" item
+        ListModel *listModel = dynamic_cast<ListModel *>(model());
+        if (listModel && listModel->rowCount() == indexAt(event->pos()).row())
+            return;
+
+        QMetaObject::invokeMethod(model(), "enterAuthorHover");
+        setCursor(Qt::PointingHandCursor);
+    } else {
+        QMetaObject::invokeMethod(model(), "exitAuthorHover");
+        unsetCursor();
+    }
+
+}
+
+void PlaylistView::mousePressEvent(QMouseEvent *event) {
+    if (event->button() == Qt::LeftButton
+        && isHoveringAuthor(event)) {
+        QMetaObject::invokeMethod(model(), "enterAuthorPressed");
+        event->ignore();
+    } else {
+        QListView::mousePressEvent(event);
+    }
+}
+
+void PlaylistView::mouseReleaseEvent(QMouseEvent *event) {
+    if (event->button() == Qt::LeftButton) {
+        QMetaObject::invokeMethod(model(), "exitAuthorPressed");
+        if (isHoveringAuthor(event))
+            emit authorPushed(indexAt(event->pos()));
+    } else {
+        QListView::mousePressEvent(event);
+    }
+}
+
+bool PlaylistView::isHoveringAuthor(QMouseEvent *event) {
+    const QModelIndex itemIndex = indexAt(event->pos());
+    const QRect itemRect = visualRect(itemIndex);
+    // qDebug() << " itemRect.x()" <<  itemRect.x();
+
+    PrettyItemDelegate *delegate = dynamic_cast<PrettyItemDelegate *>(itemDelegate());
+    if (!delegate) return false;
+
+    QRect rect = delegate->authorRect(itemIndex);
+
+    const int x = event->x() - itemRect.x() - rect.x();
+    const int y = event->y() - itemRect.y() - rect.y();
+    bool ret = x > 0 && x < rect.width() && y > 0 && y < rect.height();
+
+    return ret;
+}
diff --git a/src/playlistview.h b/src/playlistview.h
new file mode 100644 (file)
index 0000000..b058e8b
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef PLAYLISTVIEW_H
+#define PLAYLISTVIEW_H
+
+#include <QtGui>
+
+class PlaylistView : public QListView {
+
+    Q_OBJECT
+
+public:
+    PlaylistView(QWidget *parent = 0);
+
+protected:
+    void leaveEvent(QEvent *event);
+    void mouseMoveEvent(QMouseEvent *event);
+    void mousePressEvent(QMouseEvent *event);
+    void mouseReleaseEvent(QMouseEvent *event);
+    bool isHoveringAuthor(QMouseEvent *event);
+
+signals:
+    void authorPushed(QModelIndex index);
+
+private slots:
+    void itemEntered(const QModelIndex &index);
+
+};
+
+#endif // PLAYLISTVIEW_H
index 61b1336604603a55eb259c7ac45e4a0305970307..58daf3e2291c470e3572dc97931c95c3562fb080 100644 (file)
@@ -1,6 +1,6 @@
 #include "playlistwidget.h"
 
-PlaylistWidget::PlaylistWidget (QWidget *parent, THBlackBar *tabBar, QListView *listView)
+PlaylistWidget::PlaylistWidget (QWidget *parent, SegmentedControl *tabBar, QListView *listView)
     : QWidget(parent) {
     QBoxLayout *layout = new QVBoxLayout();
     layout->setMargin(0);
index 71cb6874b4748257a5436a8a1195dddb349234ad..37208a0e92c51819c32d5e390d4a640f1e84ffc7 100644 (file)
@@ -2,12 +2,12 @@
 #define PLAYLISTWIDGET_H
 
 #include <QtGui>
-#include "thlibrary/thblackbar.h"
+#include "segmentedcontrol.h"
 
 class PlaylistWidget : public QWidget
 {
 public:
-    PlaylistWidget(QWidget *parent, THBlackBar *tabBar, QListView *listView);
+    PlaylistWidget(QWidget *parent, SegmentedControl *tabBar, QListView *listView);
 };
 
 #endif // PLAYLISTWIDGET_H
index f56ca8061b9b91ce0d9e96afd31c6b8c9b1b62d2..c5f53a8e5b12efe2fca2197315df007f2a7bacf3 100644 (file)
@@ -93,7 +93,7 @@ public:
     void updateGeometries();
     void enableSuggest();
     void preventSuggest();
-    void selectAll() { lineEdit()->selectAll(); };
+    void selectAll() { lineEdit()->selectAll(); }
     void setSuggester(Suggester *suggester) { completion->setSuggester(suggester); }
 
 protected:
diff --git a/src/segmentedcontrol.cpp b/src/segmentedcontrol.cpp
new file mode 100644 (file)
index 0000000..73b8a98
--- /dev/null
@@ -0,0 +1,243 @@
+#include "segmentedcontrol.h"
+#include "fontutils.h"
+
+static const QColor borderColor = QColor(0x26, 0x26, 0x26);
+
+class SegmentedControl::Private {
+public:
+    QList<QAction *> actionList;
+    QAction *checkedAction;
+    QAction *hoveredAction;
+    QAction *pressedAction;
+};
+
+SegmentedControl::SegmentedControl (QWidget *parent)
+    : QWidget(parent), d(new SegmentedControl::Private) {
+
+    setMouseTracking(true);
+
+    d->hoveredAction = 0;
+    d->checkedAction = 0;
+    d->pressedAction = 0;
+}
+
+SegmentedControl::~SegmentedControl() {
+    delete d;
+}
+
+QAction *SegmentedControl::addAction(QAction *action) {
+    QWidget::addAction(action);
+    action->setCheckable(true);
+    d->actionList.append(action);
+    return action;
+}
+
+bool SegmentedControl::setCheckedAction(int index) {
+    if (index < 0) {
+        d->checkedAction = 0;
+        return true;
+    }
+    QAction* newCheckedAction = d->actionList.at(index);
+    return setCheckedAction(newCheckedAction);
+}
+
+bool SegmentedControl::setCheckedAction(QAction *action) {
+    if (d->checkedAction == action) {
+        return false;
+    }
+    d->checkedAction = action;
+    update();
+    return true;
+}
+
+QSize SegmentedControl::minimumSizeHint (void) const {
+    int itemsWidth = calculateButtonWidth() * d->actionList.size() * 1.2;
+    return(QSize(itemsWidth, QFontMetrics(font()).height() * 1.9));
+}
+
+void SegmentedControl::paintEvent (QPaintEvent *event) {
+    int height = event->rect().height();
+    int width = event->rect().width();
+
+    QPainter p(this);
+
+    QLinearGradient linearGrad(rect().topLeft(), rect().bottomLeft());
+    linearGrad.setColorAt(0, borderColor);
+    linearGrad.setColorAt(1, QColor(0x3c, 0x3c, 0x3c));
+    p.fillRect(rect(), QBrush(linearGrad));
+
+    // Calculate Buttons Size & Location
+    const int buttonWidth = width / d->actionList.size();
+
+    // Draw Buttons
+    QRect rect(0, 0, buttonWidth, height);
+    const int actionCount = d->actionList.size();
+    for (int i = 0; i < actionCount; i++) {
+        QAction *action = d->actionList.at(i);
+
+        if (i + 1 == actionCount) {
+            rect.setWidth(width - buttonWidth * (actionCount-1));
+            drawButton(&p, rect, action);
+        } else {
+            drawButton(&p, rect, action);
+            rect.moveLeft(rect.x() + rect.width());
+        }
+
+    }
+
+}
+
+void SegmentedControl::mouseMoveEvent (QMouseEvent *event) {
+    QWidget::mouseMoveEvent(event);
+
+    QAction *action = hoveredAction(event->pos());
+
+    if (!action && d->hoveredAction) {
+        d->hoveredAction = 0;
+        update();
+    } else if (action && action != d->hoveredAction) {
+        d->hoveredAction = action;
+        action->hover();
+        update();
+
+        // status tip
+        QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
+        if (mainWindow) mainWindow->statusBar()->showMessage(action->statusTip());
+    }
+}
+
+void SegmentedControl::mousePressEvent(QMouseEvent *event) {
+    QWidget::mousePressEvent(event);
+    if (d->hoveredAction) {
+        d->pressedAction = d->hoveredAction;
+        update();
+    }
+}
+
+void SegmentedControl::mouseReleaseEvent(QMouseEvent *event) {
+    QWidget::mouseReleaseEvent(event);
+    d->pressedAction = 0;
+    if (d->hoveredAction) {
+        bool changed = setCheckedAction(d->hoveredAction);
+        if (changed) d->hoveredAction->trigger();
+    }
+}
+
+void SegmentedControl::leaveEvent(QEvent *event) {
+    QWidget::leaveEvent(event);
+    // status tip
+    QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
+    if (mainWindow) mainWindow->statusBar()->clearMessage();
+    d->hoveredAction = 0;
+    d->pressedAction = 0;
+    update();
+}
+
+QAction *SegmentedControl::hoveredAction(const QPoint& pos) const {
+    if (pos.y() <= 0 || pos.y() >= height())
+        return 0;
+
+    int buttonWidth = width() / d->actionList.size();
+    int buttonsWidth = width();
+    int buttonsX = 0;
+
+    if (pos.x() <= buttonsX || pos.x() >= (buttonsX + buttonsWidth))
+        return 0;
+
+    int buttonIndex = (pos.x() - buttonsX) / buttonWidth;
+
+    if (buttonIndex >= d->actionList.size())
+        return 0;
+    return(d->actionList[buttonIndex]);
+}
+
+int SegmentedControl::calculateButtonWidth (void) const {
+    QFont smallerBoldFont = FontUtils::smallBold();
+    QFontMetrics fontMetrics(smallerBoldFont);
+    int tmpItemWidth, itemWidth = 0;
+    foreach (QAction *action, d->actionList) {
+        tmpItemWidth = fontMetrics.width(action->text());
+        if (itemWidth < tmpItemWidth) itemWidth = tmpItemWidth;
+    }
+    return itemWidth;
+}
+
+void SegmentedControl::drawButton (QPainter *painter,
+                              const QRect& rect,
+                              const QAction *action) {
+    if (action == d->checkedAction)
+        drawSelectedButton(painter, rect, action);
+    else
+        drawUnselectedButton(painter, rect, action);
+}
+
+void SegmentedControl::drawUnselectedButton (QPainter *painter,
+                                        const QRect& rect,
+                                        const QAction *action) {
+    paintButton(painter, rect, action);
+}
+
+void SegmentedControl::drawSelectedButton (QPainter *painter,
+                                      const QRect& rect,
+                                      const QAction *action) {
+    painter->save();
+    painter->translate(rect.topLeft());
+
+    const int width = rect.width();
+    const int height = rect.height();
+    const int hCenter = width * .5;
+    QRadialGradient gradient(hCenter, 0,
+                             width,
+                             hCenter, 0);
+    gradient.setColorAt(1, Qt::black);
+    gradient.setColorAt(0, QColor(0x33, 0x33, 0x33));
+    painter->fillRect(0, 0, width, height, QBrush(gradient));
+
+    painter->restore();
+    paintButton(painter, rect, action);
+}
+
+void SegmentedControl::paintButton(QPainter *painter, const QRect& rect, const QAction *action) {
+    painter->save();
+    painter->translate(rect.topLeft());
+
+    const int height = rect.height();
+    const int width = rect.width();
+
+    if (action == d->pressedAction && action != d->checkedAction) {
+        const int hCenter = width * .5;
+        QRadialGradient gradient(hCenter, 0,
+                                 width,
+                                 hCenter, 0);
+        gradient.setColorAt(1, QColor(0x00, 0x00, 0x00, 0));
+        gradient.setColorAt(0, QColor(0x00, 0x00, 0x00, 16));
+        painter->fillRect(0, 0, width, height, QBrush(gradient));
+    } else if (action == d->hoveredAction && action != d->checkedAction) {
+        const int hCenter = width * .5;
+        QRadialGradient gradient(hCenter, 0,
+                                 width,
+                                 hCenter, 0);
+        gradient.setColorAt(1, QColor(0xff, 0xff, 0xff, 0));
+        gradient.setColorAt(0, QColor(0xff, 0xff, 0xff, 16));
+        painter->fillRect(0, 0, width, height, QBrush(gradient));
+    }
+
+    painter->setPen(borderColor);
+#if defined(APP_MAC) | defined(APP_WIN)
+    painter->drawRect(-1, -1, width, height);
+#else
+    painter->drawRect(0, 0, width, height - 1);
+#endif
+
+    painter->setFont(FontUtils::smallBold());
+
+    // text shadow
+    painter->setPen(QColor(0, 0, 0, 128));
+    painter->drawText(0, -1, width, height, Qt::AlignCenter, action->text());
+
+    painter->setPen(QPen(Qt::white, 1));
+    painter->drawText(0, 0, width, height, Qt::AlignCenter, action->text());
+
+    painter->restore();
+}
+
diff --git a/src/segmentedcontrol.h b/src/segmentedcontrol.h
new file mode 100644 (file)
index 0000000..094a3b7
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SEGMENTEDCONTROL_H
+#define SEGMENTEDCONTROL_H
+
+#include <QtGui>
+
+class SegmentedControl : public QWidget {
+
+    Q_OBJECT
+
+public:
+    SegmentedControl(QWidget *parent = 0);
+    ~SegmentedControl();
+    QAction *addAction(QAction *action);
+    bool setCheckedAction(int index);
+    bool setCheckedAction(QAction *action);
+    QSize minimumSizeHint(void) const;
+
+signals:
+    void checkedActionChanged(QAction & action);
+
+protected:
+    void paintEvent(QPaintEvent *event);
+    void mouseMoveEvent(QMouseEvent *event);
+    void mousePressEvent(QMouseEvent *event);
+    void mouseReleaseEvent(QMouseEvent *event);
+    void leaveEvent(QEvent *event);
+
+private:
+    void drawButton(QPainter *painter,
+                    const QRect& rect,
+                    const QAction *action);
+    void drawUnselectedButton(QPainter *painter,
+                              const QRect& rect,
+                              const QAction *action);
+    void drawSelectedButton(QPainter *painter,
+                            const QRect& rect,
+                            const QAction *action);
+    void paintButton(QPainter *painter,
+                    const QRect& rect,
+                    const QAction *action);
+    QAction *hoveredAction(const QPoint& pos) const;
+    int calculateButtonWidth(void) const;
+
+    class Private;
+    Private *d;
+
+};
+
+#endif /* !SEGMENTEDCONTROL_H */