]> git.sur5r.net Git - minitube/commitdiff
Renamed uppercase filenames to lowercase
authorFlavio <flavio@odisseo.local>
Wed, 12 Dec 2012 16:39:05 +0000 (17:39 +0100)
committerFlavio <flavio@odisseo.local>
Wed, 12 Dec 2012 16:39:05 +0000 (17:39 +0100)
39 files changed:
.gitignore
CHANGES
minitube.pro
resources.qrc
src/AboutView.cpp [deleted file]
src/AboutView.h [deleted file]
src/ListModel.cpp [deleted file]
src/ListModel.h [deleted file]
src/MainWindow.cpp [deleted file]
src/MainWindow.h [deleted file]
src/MediaView.cpp [deleted file]
src/MediaView.h [deleted file]
src/SearchView.cpp [deleted file]
src/SearchView.h [deleted file]
src/View.h [deleted file]
src/aboutview.cpp [new file with mode: 0644]
src/aboutview.h [new file with mode: 0644]
src/downloadlistview.cpp
src/downloadmanager.cpp
src/downloadmodel.cpp
src/downloadsettings.cpp
src/downloadview.cpp
src/downloadview.h
src/listmodel.cpp [new file with mode: 0644]
src/listmodel.h [new file with mode: 0644]
src/main.cpp
src/mainwindow.cpp [new file with mode: 0644]
src/mainwindow.h [new file with mode: 0644]
src/mediaview.cpp [new file with mode: 0644]
src/mediaview.h [new file with mode: 0644]
src/playlist/PrettyItemDelegate.cpp [deleted file]
src/playlist/PrettyItemDelegate.h [deleted file]
src/playlistitemdelegate.cpp [new file with mode: 0644]
src/playlistitemdelegate.h [new file with mode: 0644]
src/playlistview.cpp
src/searchview.cpp [new file with mode: 0644]
src/searchview.h [new file with mode: 0644]
src/videoareawidget.h
src/view.h [new file with mode: 0644]

index d3fbddf063b1c1bcdbe492013af9a8476556ab15..c645b5d9713d1506f38aa9a1f58909254d3aa01c 100644 (file)
@@ -8,3 +8,5 @@ minitube.pro.user
 local/
 *.swp
 .tx
+android
+qtc_packaging
diff --git a/CHANGES b/CHANGES
index ed037c42ac9b3acfa09fd93224ea0c924726489f..6be6d803b7f32ba1dac3a0992f574aaecadebcdf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+2.0
+- Autoupdate on Mac and Windows
+- Fixed clicking on channel names not working in some cases
+
 1.9 - September 27, 2012
 - Adapted to YouTube changes
 - New search filter UI. Filter results by publication date, video duration and video quality.
index e705eb178618cb9a56b783de0e5539e1e73693df..1846c02f860b6ab4cb457f28cf795bd541c85196 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG += release
 TEMPLATE = app
-VERSION = 1.9
+VERSION = 2.0
 DEFINES += APP_VERSION="$$VERSION"
 
 APP_NAME = Minitube
@@ -11,29 +11,23 @@ DEFINES += APP_UNIX_NAME="$$APP_UNIX_NAME"
 
 DEFINES += QT_USE_FAST_CONCATENATION
 DEFINES += QT_USE_FAST_OPERATOR_PLUS
+DEFINES += QT_STRICT_ITERATORS
 
 # TODO Saner string behaviour
-# DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII QT_STRICT_ITERATORS
+# DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
 TARGET = minitube
-QT += network \
-    xml \
-    phonon
+QT += network xml phonon declarative
 include(src/qtsingleapplication/qtsingleapplication.pri)
-HEADERS += src/MainWindow.h \
-    src/SearchView.h \
-    src/MediaView.h \
-    src/AboutView.h \
+HEADERS += \
     src/youtubesearch.h \
     src/video.h \
     src/youtubestreamreader.h \
-    src/View.h \
     src/searchlineedit.h \
     src/urllineedit.h \
     src/spacer.h \
     src/constants.h \
     src/iconloader/qticonloader.h \
-    src/ListModel.h \
-    src/playlist/PrettyItemDelegate.h \
+    src/playlistitemdelegate.h \
     src/networkaccess.h \
     src/videomimedata.h \
     src/global.h \
@@ -62,12 +56,18 @@ HEADERS += src/MainWindow.h \
     src/playlistview.h \
     src/refinesearchwidget.h \
     src/refinesearchbutton.h \
-    src/sidebarwidget.h
+    src/sidebarwidget.h \
+    src/homeview.h \
+    src/aboutview.h \
+    src/listmodel.h \
+    src/mainwindow.h \
+    src/mediaview.h \
+    src/searchview.h \
+    src/view.h \
+    src/categoriesview.h \
+    src/userview.h \
+    src/youtubecategories.h
 SOURCES += src/main.cpp \
-    src/MainWindow.cpp \
-    src/SearchView.cpp \
-    src/MediaView.cpp \
-    src/AboutView.cpp \
     src/youtubesearch.cpp \
     src/youtubestreamreader.cpp \
     src/searchlineedit.cpp \
@@ -75,8 +75,6 @@ SOURCES += src/main.cpp \
     src/spacer.cpp \
     src/video.cpp \
     src/iconloader/qticonloader.cpp \
-    src/ListModel.cpp \
-    src/playlist/PrettyItemDelegate.cpp \
     src/videomimedata.cpp \
     src/updatechecker.cpp \
     src/networkaccess.cpp \
@@ -104,7 +102,17 @@ SOURCES += src/main.cpp \
     src/playlistview.cpp \
     src/refinesearchwidget.cpp \
     src/refinesearchbutton.cpp \
-    src/sidebarwidget.cpp
+    src/sidebarwidget.cpp \
+    src/homeview.cpp \
+    src/mainwindow.cpp \
+    src/mediaview.cpp \
+    src/listmodel.cpp \
+    src/aboutview.cpp \
+    src/searchview.cpp \
+    src/categoriesview.cpp \
+    src/userview.cpp \
+    src/playlistitemdelegate.cpp \
+    src/youtubecategories.cpp
 RESOURCES += resources.qrc
 DESTDIR = build/target/
 OBJECTS_DIR = build/obj/
@@ -117,8 +125,7 @@ CODECFORSRC = UTF-8
 include(locale/locale.pri)
 
 # deploy
-DISTFILES += CHANGES \
-    COPYING
+DISTFILES += CHANGES COPYING
 unix:!mac {
     INCLUDEPATH += /usr/include/phonon
     QT += dbus
@@ -167,3 +174,6 @@ unix:!mac {
     icon512.files += data/512x512/minitube.png
 }
 mac|win32:include(local/local.pri)
+
+OTHER_FILES += \
+    qml/categories.qml
index 64c2549d94e96a763c503e5aab0b6163b75c1eac..5961a8fda384648ac2e370a8cb860d1dda2be835 100644 (file)
@@ -6,5 +6,6 @@
         <file>images/search-sortBy.png</file>
         <file>images/search-quality.png</file>
         <file>images/search-duration.png</file>
+        <file>qml/categories.qml</file>
     </qresource>
 </RCC>
diff --git a/src/AboutView.cpp b/src/AboutView.cpp
deleted file mode 100644 (file)
index 8cbfad7..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "AboutView.h"
-#include "constants.h"
-#ifndef Q_WS_X11
-#include "extra.h"
-#endif
-#ifdef APP_ACTIVATION
-#include "activation.h"
-#endif
-#ifdef APP_MAC
-#include "macutils.h"
-#include "mac_startup.h"
-#endif
-
-AboutView::AboutView(QWidget *parent) : QWidget(parent) {
-
-    QBoxLayout *hLayout = new QHBoxLayout(this);
-    hLayout->setAlignment(Qt::AlignCenter);
-    hLayout->setMargin(30);
-    hLayout->setSpacing(30);
-
-    QLabel *logo = new QLabel(this);
-    logo->setPixmap(QPixmap(":/images/app.png"));
-    hLayout->addWidget(logo, 0, Qt::AlignTop);
-
-    QBoxLayout *layout = new QVBoxLayout();
-    layout->setAlignment(Qt::AlignCenter);
-    layout->setSpacing(30);
-    hLayout->addLayout(layout);
-
-    QString info = "<html><style>a { color: palette(text); text-decoration: none; font-weight: bold }</style><body>"
-            "<h1>" + QString(Constants::NAME) + "</h1>"
-            "<p>" + tr("There's life outside the browser!") + "</p>"
-            "<p>" + tr("Version %1").arg(Constants::VERSION) + "</p>"
-            + QString("<p><a href=\"%1/\">%1</a></p>").arg(Constants::WEBSITE);
-
-#ifdef APP_ACTIVATION
-    if (Activation::instance().isActivated())
-        info += "<p>" + tr("Licensed to: %1").arg("<b>" + Activation::instance().getEmail() + "</b>");
-#endif
-
-#ifdef Q_WS_X11
-    info += "<p>" +  tr("%1 is Free Software but its development takes precious time.").arg(Constants::NAME) + "<br/>"
-            + tr("Please <a href='%1'>donate</a> to support the continued development of %2.")
-            .arg(QString(Constants::WEBSITE).append("#donate"), Constants::NAME) + "</p>";
-#endif
-
-    info += "<p>" + tr("You may want to try my other apps as well:") + "</p>"
-            "<ul>"
-
-            "<li>" + tr("%1, a YouTube music player")
-            .arg("<a href='http://flavio.tordini.org/musictube'>Musictube</a>")
-            + "</li>"
-
-            "<li>" + tr("%1, a music player")
-            .arg("<a href='http://flavio.tordini.org/musique'>Musique</a>")
-            + "</li>"
-
-            "</ul>"
-
-            "<p>" + tr("Translate %1 to your native language using %2").arg(Constants::NAME)
-            .arg("<a href='http://www.transifex.net/projects/p/" + QString(Constants::UNIX_NAME) + "/resource/main/'>Transifex</a>")
-            + "</p>"
-
-            "<p>"
-            + tr("Icon designed by %1.").arg("<a href='http://www.kolorguild.com/'>David Nel</a>")
-            + "</p>"
-
-        #ifdef Q_WS_X11
-            "<p>" + tr("Released under the <a href='%1'>GNU General Public License</a>")
-            .arg("http://www.gnu.org/licenses/gpl.html") + "</p>"
-        #endif
-            "<p>&copy; 2009-2012 " + Constants::ORG_NAME + "</p>"
-            "</body></html>";
-    QLabel *infoLabel = new QLabel(info, this);
-    infoLabel->setOpenExternalLinks(true);
-    infoLabel->setWordWrap(true);
-    layout->addWidget(infoLabel);
-
-    QLayout *buttonLayout = new QHBoxLayout();
-    buttonLayout->setMargin(0);
-    buttonLayout->setSpacing(0);
-    buttonLayout->setAlignment(Qt::AlignLeft);
-
-    QPushButton *closeButton = new QPushButton(tr("&Close"), this);
-    closeButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
-    closeButton->setDefault(true);
-    closeButton->setFocus(Qt::OtherFocusReason);
-    connect(closeButton, SIGNAL(clicked()), parent, SLOT(goBack()));
-    buttonLayout->addWidget(closeButton);
-
-    layout->addLayout(buttonLayout);
-}
-
-void AboutView::paintEvent(QPaintEvent * /*event*/) {
-#if defined(APP_MAC) | defined(APP_WIN)
-    QBrush brush;
-    if (window()->isActiveWindow()) {
-        brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
-    } else {
-        brush = palette().window();
-    }
-    QPainter painter(this);
-    painter.fillRect(0, 0, width(), height(), brush);
-#endif
-}
-
-void AboutView::appear() {
-#ifdef APP_MAC
-    mac::uncloseWindow(window()->winId());
-#ifdef APP_ACTIVATION
-    mac::CheckForUpdates();
-#endif
-#endif
-}
diff --git a/src/AboutView.h b/src/AboutView.h
deleted file mode 100644 (file)
index e1977dd..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef ABOUTVIEW_H
-#define ABOUTVIEW_H
-
-#include <QtGui>
-#include "View.h"
-#include "constants.h"
-
-class AboutView : public QWidget, public View {
-
-    Q_OBJECT
-
-public:
-    AboutView(QWidget *parent);
-    void appear();
-    void disappear() {}
-    QMap<QString, QVariant> metadata() {
-        QMap<QString, QVariant> metadata;
-        metadata.insert("title", tr("About"));
-        metadata.insert("description",
-                        tr("What you always wanted to know about %1 and never dared to ask")
-                        .arg(Constants::NAME));
-        return metadata;
-    }
-
-protected:
-    void paintEvent(QPaintEvent *);
-
-};
-#endif
diff --git a/src/ListModel.cpp b/src/ListModel.cpp
deleted file mode 100644 (file)
index 851c152..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-#include "ListModel.h"
-#include "videomimedata.h"
-
-#define MAX_ITEMS 10
-static const QString recentKeywordsKey = "recentKeywords";
-static const QString recentChannelsKey = "recentChannels";
-
-ListModel::ListModel(QWidget *parent) : QAbstractListModel(parent) {
-    youtubeSearch = 0;
-    searching = false;
-    canSearchMore = true;
-    m_activeVideo = 0;
-    m_activeRow = -1;
-    skip = 1;
-
-    hoveredRow = -1;
-    authorHovered = false;
-    authorPressed = false;
-}
-
-ListModel::~ListModel() {
-    delete youtubeSearch;
-}
-
-int ListModel::rowCount(const QModelIndex &/*parent*/) const {
-    int count = videos.size();
-    
-    // add the message item
-    if (videos.isEmpty() || !searching)
-        count++;
-    
-    return count;
-}
-
-QVariant ListModel::data(const QModelIndex &index, int role) const {
-    
-    int row = index.row();
-    
-    if (row == videos.size()) {
-        
-        QPalette palette;
-        QFont boldFont;
-        boldFont.setBold(true);
-        
-        switch (role) {
-        case ItemTypeRole:
-            return ItemTypeShowMore;
-        case Qt::DisplayRole:
-        case Qt::StatusTipRole:
-            if (!errorMessage.isEmpty()) return errorMessage;
-            if (searching) return tr("Searching...");
-            if (canSearchMore) return tr("Show %1 More").arg(MAX_ITEMS);
-            if (videos.isEmpty()) return tr("No videos");
-            else return tr("No more videos");
-        case Qt::TextAlignmentRole:
-            return QVariant(int(Qt::AlignHCenter | Qt::AlignVCenter));
-        case Qt::ForegroundRole:
-            if (!errorMessage.isEmpty())
-                return palette.color(QPalette::ToolTipText);
-            else
-                return palette.color(QPalette::Dark);
-        case Qt::BackgroundColorRole:
-            if (!errorMessage.isEmpty())
-                return palette.color(QPalette::ToolTipBase);
-            else
-                return QVariant();
-        case Qt::FontRole:
-            return boldFont;
-        default:
-            return QVariant();
-        }
-        
-    } else if (row < 0 || row >= videos.size())
-        return QVariant();
-    
-    Video *video = videos.at(row);
-    
-    switch (role) {
-    case ItemTypeRole:
-        return ItemTypeVideo;
-    case VideoRole:
-        return QVariant::fromValue(QPointer<Video>(video));
-    case ActiveTrackRole:
-        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();
-}
-
-void ListModel::setActiveRow( int row) {
-    if ( rowExists( row ) ) {
-        
-        m_activeRow = row;
-        m_activeVideo = videoAt(row);
-        
-        int oldactiverow = m_activeRow;
-        
-        if ( rowExists( oldactiverow ) )
-            emit dataChanged( createIndex( oldactiverow, 0 ), createIndex( oldactiverow, columnCount() - 1 ) );
-        
-        emit dataChanged( createIndex( m_activeRow, 0 ), createIndex( m_activeRow, columnCount() - 1 ) );
-        emit activeRowChanged(row);
-        
-    } else {
-        m_activeRow = -1;
-        m_activeVideo = 0;
-    }
-
-}
-
-int ListModel::nextRow() const {
-    int nextRow = m_activeRow + 1;
-    if (rowExists(nextRow))
-        return nextRow;
-    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 );
-    return 0;
-}
-
-Video* ListModel::activeVideo() const {
-    return m_activeVideo;
-}
-
-void ListModel::search(SearchParams *searchParams) {
-
-    // delete current videos
-    while (!videos.isEmpty())
-        delete videos.takeFirst();
-    m_activeVideo = 0;
-    m_activeRow = -1;
-    skip = 1;
-    errorMessage.clear();
-    reset();
-
-    // (re)initialize the YouTubeSearch
-    if (youtubeSearch) delete youtubeSearch;
-    youtubeSearch = new YouTubeSearch();
-    connect(youtubeSearch, SIGNAL(gotVideo(Video*)), this, SLOT(addVideo(Video*)));
-    connect(youtubeSearch, SIGNAL(finished(int)), this, SLOT(searchFinished(int)));
-    connect(youtubeSearch, SIGNAL(error(QString)), this, SLOT(searchError(QString)));
-
-    this->searchParams = searchParams;
-    searching = true;
-    youtubeSearch->search(searchParams, MAX_ITEMS, skip);
-    skip += MAX_ITEMS;
-}
-
-void ListModel::searchMore(int max) {
-    if (searching) return;
-    searching = true;
-    errorMessage.clear();
-    youtubeSearch->search(searchParams, max, skip);
-    skip += max;
-}
-
-void ListModel::searchMore() {
-    searchMore(MAX_ITEMS);
-}
-
-void ListModel::searchNeeded() {
-    int remainingRows = videos.size() - m_activeRow;
-    int rowsNeeded = MAX_ITEMS - remainingRows;
-    if (rowsNeeded > 0)
-        searchMore(rowsNeeded);
-}
-
-void ListModel::abortSearch() {
-    while (!videos.isEmpty())
-        delete videos.takeFirst();
-    reset();
-    youtubeSearch->abort();
-    searching = false;
-}
-
-void ListModel::searchFinished(int total) {
-    searching = false;
-    canSearchMore = total > 0;
-
-    // update the message item
-    emit dataChanged( createIndex( MAX_ITEMS, 0 ), createIndex( MAX_ITEMS, columnCount() - 1 ) );
-
-    if (!youtubeSearch->getSuggestions().isEmpty()) {
-        emit haveSuggestions(youtubeSearch->getSuggestions());
-    }
-}
-
-void ListModel::searchError(QString message) {
-    errorMessage = message;
-    // update the message item
-    emit dataChanged( createIndex( MAX_ITEMS, 0 ), createIndex( MAX_ITEMS, columnCount() - 1 ) );
-}
-
-void ListModel::addVideo(Video* video) {
-    
-    connect(video, SIGNAL(gotThumbnail()), this, SLOT(updateThumbnail()));
-
-    beginInsertRows(QModelIndex(), videos.size(), videos.size());
-    videos << video;
-    endInsertRows();
-    
-    // first result!
-    if (videos.size() == 1) {
-
-        // manualplay
-        QSettings settings;
-        if (!settings.value("manualplay", false).toBool())
-            setActiveRow(0);
-
-        // save keyword
-        QString query = searchParams->keywords();
-        if (!query.isEmpty() && !searchParams->isTransient()) {
-            if (query.startsWith("http://")) {
-                // Save the video title
-                query += "|" + videos.first()->title();
-            }
-            QStringList keywords = settings.value(recentKeywordsKey).toStringList();
-            keywords.removeAll(query);
-            keywords.prepend(query);
-            while (keywords.size() > 10)
-                keywords.removeLast();
-            settings.setValue(recentKeywordsKey, keywords);
-        }
-
-        // save channel
-        QString channel = searchParams->author();
-        if (!channel.isEmpty() && !searchParams->isTransient()) {
-            QSettings settings;
-            QStringList channels = settings.value(recentChannelsKey).toStringList();
-            channels.removeAll(channel);
-            channels.prepend(channel);
-            while (channels.size() > 10)
-                channels.removeLast();
-            settings.setValue(recentChannelsKey, channels);
-        }
-
-    }
-
-}
-
-void ListModel::updateThumbnail() {
-
-    Video *video = static_cast<Video *>(sender());
-    if (!video) {
-        qDebug() << "Cannot get sender";
-        return;
-    }
-
-    int row = rowForVideo(video);
-    emit dataChanged( createIndex( row, 0 ), createIndex( row, columnCount() - 1 ) );
-
-}
-
-// --- item removal
-
-/**
-  * This function does not free memory
-  */
-bool ListModel::removeRows(int position, int rows, const QModelIndex & /*parent*/) {
-    beginRemoveRows(QModelIndex(), position, position+rows-1);
-    for (int row = 0; row < rows; ++row) {
-        videos.removeAt(position);
-    }
-    endRemoveRows();
-    return true;
-}
-
-void ListModel::removeIndexes(QModelIndexList &indexes) {
-    QList<Video*> originalList(videos);
-    QList<Video*> delitems;
-    foreach (QModelIndex index, indexes) {
-        if (index.row() >= originalList.size()) continue;
-        Video* video = originalList.at(index.row());
-        int idx = videos.indexOf(video);
-        if (idx != -1) {
-            beginRemoveRows(QModelIndex(), idx, idx);
-            delitems.append(video);
-            videos.removeAll(video);
-            endRemoveRows();
-        }
-    }
-
-    qDeleteAll(delitems);
-
-}
-
-// --- Sturm und drang ---
-
-
-
-Qt::DropActions ListModel::supportedDropActions() const {
-    return Qt::MoveAction;
-}
-
-Qt::ItemFlags ListModel::flags(const QModelIndex &index) const {
-    Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
-
-    if (index.isValid()) {
-        if (index.row() == videos.size()) {
-            // don't drag the "show 10 more" item
-            return defaultFlags;
-        } else
-            return ( defaultFlags | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled );
-    } else
-        return Qt::ItemIsDropEnabled | defaultFlags;
-}
-
-QStringList ListModel::mimeTypes() const {
-    QStringList types;
-    types << "application/x-minitube-video";
-    return types;
-}
-
-QMimeData* ListModel::mimeData( const QModelIndexList &indexes ) const {
-    VideoMimeData* mime = new VideoMimeData();
-
-    foreach( const QModelIndex &it, indexes ) {
-        int row = it.row();
-        if (row >= 0 && row < videos.size())
-            mime->addVideo( videos.at( it.row() ) );
-    }
-
-    return mime;
-}
-
-bool ListModel::dropMimeData(const QMimeData *data,
-                             Qt::DropAction action, int row, int column,
-                             const QModelIndex &parent) {
-    if (action == Qt::IgnoreAction)
-        return true;
-
-    if (!data->hasFormat("application/x-minitube-video"))
-        return false;
-
-    if (column > 0)
-        return false;
-
-    int beginRow;
-    if (row != -1)
-        beginRow = row;
-    else if (parent.isValid())
-        beginRow = parent.row();
-    else
-        beginRow = rowCount(QModelIndex());
-
-    const VideoMimeData* videoMimeData = dynamic_cast<const VideoMimeData*>( data );
-    if(!videoMimeData ) return false;
-
-    QList<Video*> droppedVideos = videoMimeData->videos();
-    foreach( Video *video, droppedVideos) {
-        
-        // remove videos
-        int videoRow = videos.indexOf(video);
-        removeRows(videoRow, 1, QModelIndex());
-        
-        // and then add them again at the new position
-        beginInsertRows(QModelIndex(), beginRow, beginRow);
-        videos.insert(beginRow, video);
-        endInsertRows();
-
-    }
-
-    // fix m_activeRow after all this
-    m_activeRow = videos.indexOf(m_activeVideo);
-
-    // let the MediaView restore the selection
-    emit needSelectionFor(droppedVideos);
-
-    return true;
-
-}
-
-int ListModel::rowForVideo(Video* video) {
-    return videos.indexOf(video);
-}
-
-QModelIndex ListModel::indexForVideo(Video* video) {
-    return createIndex(videos.indexOf(video), 0);
-}
-
-void ListModel::move(QModelIndexList &indexes, bool up) {
-    QList<Video*> movedVideos;
-
-    foreach (QModelIndex index, indexes) {
-        int row = index.row();
-        if (row >= videos.size()) continue;
-        // qDebug() << "index row" << row;
-        Video *video = videoAt(row);
-        movedVideos << video;
-    }
-
-    int end=up ? -1 : rowCount()-1, mod=up ? -1 : 1;
-    foreach (Video *video, movedVideos) {
-
-        int row = rowForVideo(video);
-        if (row+mod==end) { end=row; continue; }
-        // qDebug() << "video row" << row;
-        removeRows(row, 1, QModelIndex());
-
-        if (up) row--;
-        else row++;
-
-        beginInsertRows(QModelIndex(), row, row);
-        videos.insert(row, video);
-        endInsertRows();
-
-    }
-
-    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 ) );
-}
diff --git a/src/ListModel.h b/src/ListModel.h
deleted file mode 100644 (file)
index f9d424b..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#ifndef LISTMODEL_H
-#define LISTMODEL_H
-
-#include "video.h"
-#include "youtubesearch.h"
-#include "searchparams.h"
-
-enum DataRoles {
-    ItemTypeRole = Qt::UserRole,
-    VideoRole,
-    ActiveTrackRole,
-    DownloadItemRole,
-    HoveredItemRole,
-    DownloadButtonHoveredRole,
-    DownloadButtonPressedRole,
-    AuthorHoveredRole,
-    AuthorPressedRole
-};
-
-enum ItemTypes {
-    ItemTypeVideo = 1,
-    ItemTypeShowMore
-};
-
-class ListModel : public QAbstractListModel {
-
-    Q_OBJECT
-
-public:
-
-    ListModel(QWidget *parent);
-    ~ListModel();
-
-    // inherited from QAbstractListModel
-    int rowCount(const QModelIndex &parent = QModelIndex()) const;
-    // int rowCount( const QModelIndex& parent = QModelIndex() ) const { Q_UNUSED( parent ); return videos.size(); }
-    int columnCount( const QModelIndex& parent = QModelIndex() ) const { Q_UNUSED( parent ); return 4; }
-    QVariant data(const QModelIndex &index, int role) const;
-    bool removeRows(int position, int rows, const QModelIndex &parent);
-
-    Qt::ItemFlags flags(const QModelIndex &index) const;
-    QStringList mimeTypes() const;
-    Qt::DropActions supportedDropActions() const;
-    QMimeData* mimeData( const QModelIndexList &indexes ) const;
-    bool dropMimeData(const QMimeData *data,
-                      Qt::DropAction action, int row, int column,
-                      const QModelIndex &parent);
-
-    // custom methods
-    void setActiveRow( int row );
-    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);
-    void move(QModelIndexList &indexes, bool up);
-
-    Video* videoAt( int row ) const;
-    Video* activeVideo() const;
-
-    // video search methods
-    void search(SearchParams *searchParams);
-    void abortSearch();
-
-
-public slots:
-    void searchMore();
-    void searchNeeded();
-    void addVideo(Video* video);
-    void searchFinished(int total);
-    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*>);
-    void haveSuggestions(const QStringList &suggestions);
-
-private:
-    void searchMore(int max);
-
-    YouTubeSearch *youtubeSearch;
-    SearchParams *searchParams;
-    bool searching;
-    bool canSearchMore;
-
-    QList<Video*> videos;
-    int skip;
-
-    // the row being played
-    int m_activeRow;
-    Video *m_activeVideo;
-
-    QString errorMessage;
-
-    int hoveredRow;
-    bool authorHovered;
-    bool authorPressed;
-};
-
-#endif
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
deleted file mode 100644 (file)
index b0e184e..0000000
+++ /dev/null
@@ -1,1501 +0,0 @@
-#include "MainWindow.h"
-#include "spacer.h"
-#include "constants.h"
-#include "iconloader/qticonloader.h"
-#include "global.h"
-#include "videodefinition.h"
-#include "fontutils.h"
-#include "globalshortcuts.h"
-#ifdef Q_WS_X11
-#include "gnomeglobalshortcutbackend.h"
-#endif
-#ifdef Q_WS_MAC
-#include "mac_startup.h"
-#include "macfullscreen.h"
-#include "macsupport.h"
-#include "macutils.h"
-#endif
-#include "downloadmanager.h"
-#include "youtubesuggest.h"
-#include "updatechecker.h"
-#include "temporary.h"
-#ifdef APP_MAC
-#include "searchlineedit_mac.h"
-#else
-#include "searchlineedit.h"
-#endif
-#include <iostream>
-#ifndef Q_WS_X11
-#include "extra.h"
-#include "updatedialog.h"
-#endif
-#ifdef APP_ACTIVATION
-#include "activation.h"
-#include "activationview.h"
-#include "activationdialog.h"
-#endif
-
-static MainWindow *singleton = 0;
-
-MainWindow* MainWindow::instance() {
-    if (!singleton) singleton = new MainWindow();
-    return singleton;
-}
-
-MainWindow::MainWindow() :
-        updateChecker(0),
-        aboutView(0),
-        downloadView(0),
-        mediaObject(0),
-        audioOutput(0),
-        m_fullscreen(false) {
-
-    singleton = this;
-
-    // views mechanism
-    history = new QStack<QWidget*>();
-    views = new QStackedWidget(this);
-
-    // views
-    searchView = new SearchView(this);
-    connect(searchView, SIGNAL(search(SearchParams*)), this, SLOT(showMedia(SearchParams*)));
-    views->addWidget(searchView);
-
-    mediaView = new MediaView(this);
-    mediaView->setEnabled(false);
-    views->addWidget(mediaView);
-
-    // build ui
-    createActions();
-    createMenus();
-    createToolBars();
-    createStatusBar();
-
-    initPhonon();
-    mediaView->setSlider(seekSlider);
-    mediaView->setMediaObject(mediaObject);
-
-    // remove that useless menu/toolbar context menu
-    this->setContextMenuPolicy(Qt::NoContextMenu);
-
-    // mediaView init stuff thats needs actions
-    mediaView->initialize();
-
-    // event filter to block ugly toolbar tooltips
-    qApp->installEventFilter(this);
-
-    setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
-
-    // restore window position
-    readSettings();
-
-    // fix stacked widget minimum size
-    for (int i = 0; i < views->count(); i++) {
-        QWidget* view = views->widget(i);
-        if (view) view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
-    }
-    setMinimumWidth(0);
-
-    // show the initial view
-    showSearch(false);
-
-#ifdef APP_ACTIVATION
-    if (!Activation::instance().isActivated())
-        showActivationView(false);
-#endif
-
-    setCentralWidget(views);
-
-    // Global shortcuts
-    GlobalShortcuts &shortcuts = GlobalShortcuts::instance();
-#ifdef Q_WS_X11
-    if (GnomeGlobalShortcutBackend::IsGsdAvailable())
-        shortcuts.setBackend(new GnomeGlobalShortcutBackend(&shortcuts));
-#endif
-#ifdef Q_WS_MAC
-    mac::MacSetup();
-#endif
-    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(&shortcuts, SIGNAL(StopAfter()), The::globalActions()->value("stopafterthis"), SLOT(toggle()));
-
-    connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
-            SLOT(updateDownloadMessage(QString)));
-    connect(DownloadManager::instance(), SIGNAL(finished()),
-            SLOT(downloadsFinished()));
-
-    setAcceptDrops(true);
-
-    mouseTimer = new QTimer(this);
-    mouseTimer->setInterval(5000);
-    mouseTimer->setSingleShot(true);
-    connect(mouseTimer, SIGNAL(timeout()), SLOT(hideMouse()));
-
-    QTimer::singleShot(0, this, SLOT(checkForUpdate()));
-
-}
-
-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) {
-
-    if (m_fullscreen && event->type() == QEvent::MouseMove) {
-
-        QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
-        const int x = mouseEvent->pos().x();
-        const QString className = QString(obj->metaObject()->className());
-        const bool isHoveringVideo = (className == "QGLWidget") || (className == "VideoAreaWidget");
-
-        // qDebug() << obj << mouseEvent->pos() << isHoveringVideo << mediaView->isPlaylistVisible();
-
-        if (mediaView->isPlaylistVisible()) {
-            if (isHoveringVideo && x > 5) mediaView->setPlaylistVisible(false);
-        } else {
-            if (isHoveringVideo && x >= 0 && x < 5) mediaView->setPlaylistVisible(true);
-        }
-
-#ifndef APP_MAC
-        const int y = mouseEvent->pos().y();
-        if (mainToolBar->isVisible()) {
-            if (isHoveringVideo && y > 5) mainToolBar->setVisible(false);
-        } else {
-            if (isHoveringVideo && y >= 0 && y < 5) mainToolBar->setVisible(true);
-        }
-#endif
-
-        // show the normal cursor
-        unsetCursor();
-        // then hide it again after a few seconds
-        mouseTimer->start();
-
-    }
-
-    if (event->type() == QEvent::ToolTip) {
-        // kill tooltips
-        return true;
-    }
-    // standard event processing
-    return QMainWindow::eventFilter(obj, event);
-}
-
-void MainWindow::createActions() {
-
-    QMap<QString, QAction*> *actions = The::globalActions();
-
-    stopAct = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop"), this);
-    stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
-    stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
-    stopAct->setEnabled(false);
-    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));
-    skipAct->setEnabled(false);
-    actions->insert("skip", skipAct);
-    connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
-
-    pauseAct = new QAction(QtIconLoader::icon("media-playback-pause"), tr("&Pause"), this);
-    pauseAct->setStatusTip(tr("Pause playback"));
-    pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
-    pauseAct->setEnabled(false);
-    actions->insert("pause", pauseAct);
-    connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
-
-    fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen"), tr("&Full Screen"), this);
-    fullscreenAct->setStatusTip(tr("Go full screen"));
-    QList<QKeySequence> fsShortcuts;
-#ifdef APP_MAC
-    fsShortcuts << QKeySequence(Qt::CTRL + Qt::META + Qt::Key_F);
-#else
-    fsShortcuts << QKeySequence(Qt::Key_F11) << QKeySequence(Qt::ALT + Qt::Key_Return);
-#endif
-    fullscreenAct->setShortcuts(fsShortcuts);
-    fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
-#if QT_VERSION >= 0x040600
-    fullscreenAct->setPriority(QAction::LowPriority);
-#endif
-    actions->insert("fullscreen", fullscreenAct);
-    connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
-
-    compactViewAct = new QAction(tr("&Compact Mode"), this);
-    compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
-#ifdef APP_MAC
-    compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::META + Qt::Key_C));
-#else
-    compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
-#endif
-    compactViewAct->setCheckable(true);
-    compactViewAct->setChecked(false);
-    compactViewAct->setEnabled(false);
-    actions->insert("compactView", compactViewAct);
-    connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
-
-    webPageAct = new QAction(tr("Open the &YouTube Page"), this);
-    webPageAct->setStatusTip(tr("Go to the YouTube video page and pause playback"));
-    webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
-    webPageAct->setEnabled(false);
-    actions->insert("webpage", webPageAct);
-    connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
-
-    copyPageAct = new QAction(tr("Copy the YouTube &Link"), this);
-    copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
-    copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
-    copyPageAct->setEnabled(false);
-    actions->insert("pagelink", copyPageAct);
-    connect(copyPageAct, SIGNAL(triggered()), mediaView, SLOT(copyWebPage()));
-
-    copyLinkAct = new QAction(tr("Copy the Video Stream &URL"), this);
-    copyLinkAct->setStatusTip(tr("Copy the current video stream URL to the clipboard"));
-    copyLinkAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
-    copyLinkAct->setEnabled(false);
-    actions->insert("videolink", copyLinkAct);
-    connect(copyLinkAct, SIGNAL(triggered()), mediaView, SLOT(copyVideoLink()));
-
-    findVideoPartsAct = new QAction(tr("Find Video &Parts"), this);
-    findVideoPartsAct->setStatusTip(tr("Find other video parts hopefully in the right order"));
-    findVideoPartsAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
-    findVideoPartsAct->setEnabled(false);
-    connect(findVideoPartsAct, SIGNAL(triggered()), mediaView, SLOT(findVideoParts()));
-    actions->insert("findVideoParts", findVideoPartsAct);
-
-    removeAct = new QAction(tr("&Remove"), this);
-    removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
-    removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
-    removeAct->setEnabled(false);
-    actions->insert("remove", removeAct);
-    connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
-
-    moveUpAct = new QAction(tr("Move &Up"), this);
-    moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
-    moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
-    moveUpAct->setEnabled(false);
-    actions->insert("moveUp", moveUpAct);
-    connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
-
-    moveDownAct = new QAction(tr("Move &Down"), this);
-    moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
-    moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
-    moveDownAct->setEnabled(false);
-    actions->insert("moveDown", moveDownAct);
-    connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
-
-    clearAct = new QAction(tr("&Clear Recent Searches"), this);
-    clearAct->setMenuRole(QAction::ApplicationSpecificRole);
-    clearAct->setShortcuts(QList<QKeySequence>()
-                           << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)
-                           << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
-    clearAct->setStatusTip(tr("Clear the search history. Cannot be undone."));
-    clearAct->setEnabled(true);
-    actions->insert("clearRecentKeywords", clearAct);
-    connect(clearAct, SIGNAL(triggered()), SLOT(clearRecentKeywords()));
-
-    quitAct = new QAction(tr("&Quit"), this);
-    quitAct->setMenuRole(QAction::QuitRole);
-    quitAct->setShortcut(QKeySequence(QKeySequence::Quit));
-    quitAct->setStatusTip(tr("Bye"));
-    actions->insert("quit", quitAct);
-    connect(quitAct, SIGNAL(triggered()), SLOT(quit()));
-
-    siteAct = new QAction(tr("&Website"), this);
-    siteAct->setShortcut(QKeySequence::HelpContents);
-    siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::NAME));
-    actions->insert("site", siteAct);
-    connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
-
-#if !defined(APP_MAC) && !defined(APP_WIN)
-    donateAct = new QAction(tr("Make a &Donation"), this);
-    donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::NAME));
-    actions->insert("donate", donateAct);
-    connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
-#endif
-
-    aboutAct = new QAction(tr("&About"), this);
-    aboutAct->setMenuRole(QAction::AboutRole);
-    aboutAct->setStatusTip(tr("Info about %1").arg(Constants::NAME));
-    actions->insert("about", aboutAct);
-    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
-
-    // Invisible actions
-
-    searchFocusAct = new QAction(this);
-    searchFocusAct->setShortcut(QKeySequence::Find);
-    searchFocusAct->setStatusTip(tr("Search"));
-    actions->insert("search", searchFocusAct);
-    connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
-    addAction(searchFocusAct);
-
-    volumeUpAct = new QAction(this);
-    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));
-    actions->insert("volume-down", volumeDownAct);
-    connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
-    addAction(volumeDownAct);
-
-    volumeMuteAct = new QAction(this);
-    volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
-    volumeMuteAct->setStatusTip(tr("Mute volume"));
-    volumeMuteAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_E));
-    actions->insert("volume-mute", volumeMuteAct);
-    connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
-    addAction(volumeMuteAct);
-
-    QAction *definitionAct = new QAction(this);
-    definitionAct->setIcon(QtIconLoader::icon("video-display"));
-    definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
-    /*
-    QMenu *definitionMenu = new QMenu(this);
-    foreach (QString definition, VideoDefinition::getDefinitionNames()) {
-        definitionMenu->addAction(definition);
-    }
-    definitionAct->setMenu(definitionMenu);
-    */
-    actions->insert("definition", definitionAct);
-    connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
-    addAction(definitionAct);
-
-    QAction *action;
-
-    action = new QAction(QtIconLoader::icon("media-playback-start"), tr("&Manually Start Playing"), this);
-    action->setStatusTip(tr("Manually start playing videos"));
-    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
-    action->setCheckable(true);
-    connect(action, SIGNAL(toggled(bool)), SLOT(setManualPlay(bool)));
-    actions->insert("manualplay", action);
-
-    action = new QAction(tr("&Downloads"), this);
-    action->setStatusTip(tr("Show details about video downloads"));
-    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
-    action->setCheckable(true);
-    action->setIcon(QtIconLoader::icon("go-down"));
-    action->setVisible(false);
-    connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
-    actions->insert("downloads", action);
-
-    action = new QAction(tr("&Download"), this);
-    action->setStatusTip(tr("Download the current video"));
-#ifndef APP_NO_DOWNLOADS
-    action->setShortcut(QKeySequence::Save);
-#endif
-    action->setIcon(QtIconLoader::icon("go-down"));
-    action->setEnabled(false);
-#if QT_VERSION >= 0x040600
-    action->setPriority(QAction::LowPriority);
-#endif
-    connect(action, SIGNAL(triggered()), mediaView, SLOT(downloadVideo()));
-    actions->insert("download", action);
-
-    /*
-    action = new QAction(tr("&Snapshot"), this);
-    action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S));
-    actions->insert("snapshot", action);
-    connect(action, SIGNAL(triggered()), mediaView, SLOT(snapshot()));
-    */
-
-    QString shareTip = tr("Share the current video using %1");
-
-    action = new QAction("&Twitter", this);
-    action->setStatusTip(shareTip.arg("Twitter"));
-    actions->insert("twitter", action);
-    connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaTwitter()));
-
-    action = new QAction("&Facebook", this);
-    action->setStatusTip(shareTip.arg("Facebook"));
-    actions->insert("facebook", action);
-    connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaFacebook()));
-
-    action = new QAction("&Buffer", this);
-    action->setStatusTip(shareTip.arg("Buffer"));
-    actions->insert("buffer", action);
-    connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaBuffer()));
-
-    action = new QAction(tr("&Email"), this);
-    action->setStatusTip(shareTip.arg(tr("Email")));
-    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(Constants::NAME, this);
-    action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_1));
-    actions->insert("restore", action);
-    connect(action, SIGNAL(triggered()), SLOT(restore()));
-
-    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)));
-
-    action = new QAction(tr("&Report an Issue..."), this);
-    actions->insert("report-issue", action);
-    connect(action, SIGNAL(triggered()), SLOT(reportIssue()));
-
-    action = new QAction(tr("&Refine Search..."), this);
-    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
-    action->setCheckable(true);
-    actions->insert("refine-search", action);
-
-#ifdef APP_ACTIVATION
-    Extra::createActivationAction(tr("Buy %1...").arg(Constants::NAME));
-#endif
-
-    // common action properties
-    foreach (QAction *action, actions->values()) {
-
-        // add actions to the MainWindow so that they work
-        // when the menu is hidden
-        addAction(action);
-
-        // never autorepeat.
-        // unexperienced users tend to keep keys pressed for a "long" time
-        action->setAutoRepeat(false);
-
-        // set to something more meaningful then the toolbar text
-        if (!action->statusTip().isEmpty())
-            action->setToolTip(action->statusTip());
-
-        // show keyboard shortcuts in the status bar
-        if (!action->shortcut().isEmpty())
-            action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
-    }
-
-}
-
-void MainWindow::createMenus() {
-
-    QMap<QString, QMenu*> *menus = The::globalMenus();
-
-    fileMenu = menuBar()->addMenu(tr("&Application"));
-#ifdef APP_ACTIVATION
-    QAction *buyAction = The::globalActions()->value("buy");
-    if (buyAction) fileMenu->addAction(buyAction);
-#ifndef APP_MAC
-    fileMenu->addSeparator();
-#endif
-#endif
-    fileMenu->addAction(clearAct);
-#ifndef APP_MAC
-    fileMenu->addSeparator();
-#endif
-    fileMenu->addAction(quitAct);
-
-    QMenu* playbackMenu = menuBar()->addMenu(tr("&Playback"));
-    menus->insert("playback", playbackMenu);
-    playbackMenu->addAction(pauseAct);
-    playbackMenu->addAction(stopAct);
-    playbackMenu->addAction(The::globalActions()->value("stopafterthis"));
-    playbackMenu->addSeparator();
-    playbackMenu->addAction(skipAct);
-    playbackMenu->addAction(skipBackwardAct);
-    playbackMenu->addSeparator();
-    playbackMenu->addAction(The::globalActions()->value("manualplay"));
-#ifdef APP_MAC
-    MacSupport::dockMenu(playbackMenu);
-#endif
-
-    playlistMenu = menuBar()->addMenu(tr("&Playlist"));
-    menus->insert("playlist", playlistMenu);
-    playlistMenu->addAction(removeAct);
-    playlistMenu->addSeparator();
-    playlistMenu->addAction(moveUpAct);
-    playlistMenu->addAction(moveDownAct);
-    playlistMenu->addSeparator();
-    playlistMenu->addAction(The::globalActions()->value("refine-search"));
-
-    QMenu* videoMenu = menuBar()->addMenu(tr("&Video"));
-    menus->insert("video", videoMenu);
-    videoMenu->addAction(findVideoPartsAct);
-    videoMenu->addSeparator();
-    videoMenu->addAction(webPageAct);
-    videoMenu->addSeparator();
-#ifndef APP_NO_DOWNLOADS
-    videoMenu->addAction(The::globalActions()->value("download"));
-    // videoMenu->addAction(copyLinkAct);
-#endif
-    // videoMenu->addAction(The::globalActions()->value("snapshot"));
-
-    QMenu* viewMenu = menuBar()->addMenu(tr("&View"));
-    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);
-    shareMenu->addAction(copyPageAct);
-    shareMenu->addSeparator();
-    shareMenu->addAction(The::globalActions()->value("twitter"));
-    shareMenu->addAction(The::globalActions()->value("facebook"));
-    shareMenu->addAction(The::globalActions()->value("buffer"));
-    shareMenu->addSeparator();
-    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)
-    helpMenu->addAction(donateAct);
-#endif
-    helpMenu->addAction(The::globalActions()->value("report-issue"));
-    helpMenu->addAction(aboutAct);
-}
-
-void MainWindow::createToolBars() {
-
-    setUnifiedTitleAndToolBarOnMac(true);
-
-    mainToolBar = new QToolBar(this);
-#if QT_VERSION < 0x040600 | defined(APP_MAC)
-    mainToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
-#else
-    mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
-#endif
-    mainToolBar->setFloatable(false);
-    mainToolBar->setMovable(false);
-
-#if defined(APP_MAC) | defined(APP_WIN)
-    mainToolBar->setIconSize(QSize(32, 32));
-#endif
-
-    mainToolBar->addAction(stopAct);
-    mainToolBar->addAction(pauseAct);
-    mainToolBar->addAction(skipAct);
-
-    bool addFullScreenAct = true;
-#ifdef Q_WS_MAC
-    addFullScreenAct = !mac::CanGoFullScreen(winId());
-#endif
-    if (addFullScreenAct) mainToolBar->addAction(fullscreenAct);
-
-#ifndef APP_NO_DOWNLOADS
-    mainToolBar->addAction(The::globalActions()->value("download"));
-#endif
-
-    mainToolBar->addWidget(new Spacer());
-
-    QFont smallerFont = FontUtils::small();
-    currentTime = new QLabel(mainToolBar);
-    currentTime->setFont(smallerFont);
-    mainToolBar->addWidget(currentTime);
-
-    mainToolBar->addWidget(new Spacer());
-
-    seekSlider = new Phonon::SeekSlider(this);
-    seekSlider->setIconVisible(false);
-    seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
-    mainToolBar->addWidget(seekSlider);
-
-/*
-    mainToolBar->addWidget(new Spacer());
-    slider = new QSlider(this);
-    slider->setOrientation(Qt::Horizontal);
-    slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
-    mainToolBar->addWidget(slider);
-*/
-
-    mainToolBar->addWidget(new Spacer());
-
-    totalTime = new QLabel(mainToolBar);
-    totalTime->setFont(smallerFont);
-    mainToolBar->addWidget(totalTime);
-
-    mainToolBar->addWidget(new Spacer());
-
-    mainToolBar->addAction(volumeMuteAct);
-
-    volumeSlider = new Phonon::VolumeSlider(this);
-    volumeSlider->setMuteVisible(false);
-    // qDebug() << volumeSlider->children();
-    // status tip for the volume slider
-    QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
-    if (volumeQSlider)
-        volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
-                volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
-    // this makes the volume slider smaller
-    volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-    mainToolBar->addWidget(volumeSlider);
-
-    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);
-    Spacer* spacer = new Spacer();
-    // spacer->setWidth(4);
-    mainToolBar->addWidget(spacer);
-#endif
-
-    addToolBar(mainToolBar);
-}
-
-void MainWindow::createStatusBar() {
-    QToolBar* toolBar = new QToolBar(this);
-    statusToolBar = toolBar;
-    toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
-    toolBar->setIconSize(QSize(16, 16));
-    toolBar->addAction(The::globalActions()->value("downloads"));
-    toolBar->addAction(The::globalActions()->value("definition"));
-    statusBar()->addPermanentWidget(toolBar);
-    statusBar()->show();
-}
-
-void MainWindow::showStopAfterThisInStatusBar(bool show) {
-    QAction* action = The::globalActions()->value("stopafterthis");
-    showActionInStatusBar(action, show);
-}
-
-void MainWindow::showActionInStatusBar(QAction* action, bool show) {
-    if (show) {
-        statusToolBar->insertAction(statusToolBar->actions().first(), action);
-    } else {
-        statusToolBar->removeAction(action);
-    }
-}
-
-void MainWindow::readSettings() {
-    QSettings settings;
-    if (settings.contains("geometry")) {
-        restoreGeometry(settings.value("geometry").toByteArray());
-#ifdef APP_MAC
-    MacSupport::fixGeometry(this);
-#endif
-    } else {
-        setGeometry(100, 100, 1000, 500);
-    }
-    setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
-    audioOutput->setVolume(settings.value("volume", 1).toDouble());
-    audioOutput->setMuted(settings.value("volumeMute").toBool());
-    The::globalActions()->value("manualplay")->setChecked(settings.value("manualplay", false).toBool());
-}
-
-void MainWindow::writeSettings() {
-    QSettings settings;
-
-    settings.setValue("geometry", saveGeometry());
-    mediaView->saveSplitterState();
-
-    settings.setValue("volume", audioOutput->volume());
-    settings.setValue("volumeMute", audioOutput->isMuted());
-    settings.setValue("manualplay", The::globalActions()->value("manualplay")->isChecked());
-}
-
-void MainWindow::goBack() {
-    if ( history->size() > 1 ) {
-        history->pop();
-        QWidget *widget = history->pop();
-        showWidget(widget);
-    }
-}
-
-void MainWindow::showWidget(QWidget* widget, bool transition) {
-
-    if (compactViewAct->isChecked())
-        compactViewAct->toggle();
-
-    setUpdatesEnabled(false);
-
-    // call hide method on the current view
-    View* oldView = dynamic_cast<View *> (views->currentWidget());
-    if (oldView) {
-        oldView->disappear();
-        views->currentWidget()->setEnabled(false);
-    } else qDebug() << "Cannot cast view";
-
-    // call show method on the new view
-    View* newView = dynamic_cast<View *> (widget);
-    if (newView) {
-        widget->setEnabled(true);
-        newView->appear();
-        QMap<QString,QVariant> metadata = newView->metadata();
-        QString windowTitle = metadata.value("title").toString();
-        if (windowTitle.length())
-            windowTitle += " - ";
-        setWindowTitle(windowTitle + Constants::NAME);
-        statusBar()->showMessage((metadata.value("description").toString()));
-    }
-
-    const bool isMediaView = widget == mediaView;
-
-    stopAct->setEnabled(isMediaView);
-    compactViewAct->setEnabled(isMediaView);
-    webPageAct->setEnabled(isMediaView);
-    copyPageAct->setEnabled(isMediaView);
-    copyLinkAct->setEnabled(isMediaView);
-    findVideoPartsAct->setEnabled(isMediaView);
-    toolbarSearch->setEnabled(widget == searchView || isMediaView || 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(isMediaView);
-    The::globalActions()->value("facebook")->setEnabled(isMediaView);
-    The::globalActions()->value("buffer")->setEnabled(isMediaView);
-    The::globalActions()->value("email")->setEnabled(isMediaView);
-
-    aboutAct->setEnabled(widget != aboutView);
-    The::globalActions()->value("downloads")->setChecked(widget == downloadView);
-
-    setUpdatesEnabled(true);
-
-    QWidget *oldWidget = views->currentWidget();
-    if (oldWidget)
-        oldWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
-
-    views->setCurrentWidget(widget);
-    widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-
-#ifndef Q_WS_X11
-    if (transition) Extra::fadeInWidget(oldWidget, widget);
-#endif
-
-    history->push(widget);
-}
-
-void MainWindow::about() {
-    if (!aboutView) {
-        aboutView = new AboutView(this);
-        views->addWidget(aboutView);
-    }
-    showWidget(aboutView);
-}
-
-void MainWindow::visitSite() {
-    QUrl url(Constants::WEBSITE);
-    statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
-    QDesktopServices::openUrl(url);
-}
-
-void MainWindow::donate() {
-    QUrl url(QString(Constants::WEBSITE) + "#donate");
-    statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
-    QDesktopServices::openUrl(url);
-}
-
-void MainWindow::reportIssue() {
-    QUrl url("http://flavio.tordini.org/forums/forum/minitube-forums/minitube-troubleshooting");
-    QDesktopServices::openUrl(url);
-}
-
-void MainWindow::quit() {
-#ifdef APP_MAC
-    if (!confirmQuit()) {
-        return;
-    }
-#endif
-    // do not save geometry when in full screen or in compact mode
-    if (!m_fullscreen && !compactViewAct->isChecked()) {
-        writeSettings();
-    }
-    Temporary::deleteAll();
-    qApp->quit();
-}
-
-void MainWindow::closeEvent(QCloseEvent *event) {
-#ifdef APP_MAC
-    mac::closeWindow(winId());
-    event->ignore();
-#else
-    if (!confirmQuit()) {
-        event->ignore();
-        return;
-    }
-    QWidget::closeEvent(event);
-    quit();
-#endif
-}
-
-bool MainWindow::confirmQuit() {
-    if (DownloadManager::instance()->activeItems() > 0) {
-        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);
-
-        msgBox.exec();
-
-        if (msgBox.clickedButton() == waitButton) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void MainWindow::showSearch(bool transition) {
-    showWidget(searchView, transition);
-    currentTime->clear();
-    totalTime->clear();
-}
-
-void MainWindow::showMedia(SearchParams *searchParams) {
-    mediaView->search(searchParams);
-    showWidget(mediaView);
-}
-
-void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
-
-    // qDebug() << "Phonon state: " << newState;
-
-    switch (newState) {
-
-    case Phonon::ErrorState:
-        if (mediaObject->errorType() == Phonon::FatalError) {
-            // Do not display because we try to play incomplete video files and sometimes trigger this
-            // We retry automatically (in MediaView) so no need to show it
-            // statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
-        } else {
-            statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
-        }
-        break;
-
-         case Phonon::PlayingState:
-        pauseAct->setEnabled(true);
-        pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
-        pauseAct->setText(tr("&Pause"));
-        pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
-        // stopAct->setEnabled(true);
-        break;
-
-         case Phonon::StoppedState:
-        pauseAct->setEnabled(false);
-        // stopAct->setEnabled(false);
-        break;
-
-         case Phonon::PausedState:
-        pauseAct->setEnabled(true);
-        pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
-        pauseAct->setText(tr("&Play"));
-        pauseAct->setStatusTip(tr("Resume playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
-        // stopAct->setEnabled(true);
-        break;
-
-         case Phonon::BufferingState:
-         case Phonon::LoadingState:
-        pauseAct->setEnabled(false);
-        currentTime->clear();
-        totalTime->clear();
-        // stopAct->setEnabled(true);
-        break;
-
-         default:
-        ;
-    }
-}
-
-void MainWindow::stop() {
-    mediaView->stop();
-    showSearch();
-}
-
-void MainWindow::resizeEvent(QResizeEvent*) {
-#ifdef Q_WS_MAC
-    if (mac::CanGoFullScreen(winId())) {
-        bool isFullscreen = mac::IsFullScreen(winId());
-        if (isFullscreen != m_fullscreen) {
-            if (compactViewAct->isChecked()) {
-                compactViewAct->setChecked(false);
-                compactView(false);
-            }
-            m_fullscreen = isFullscreen;
-            updateUIForFullscreen();
-        }
-    }
-#endif
-}
-
-void MainWindow::fullscreen() {
-
-    if (compactViewAct->isChecked())
-        compactViewAct->toggle();
-
-#ifdef Q_WS_MAC
-    WId handle = winId();
-    if (mac::CanGoFullScreen(handle)) {
-        mainToolBar->setVisible(true);
-        mac::ToggleFullScreen(handle);
-        return;
-    }
-#endif
-
-    m_fullscreen = !m_fullscreen;
-
-    if (m_fullscreen) {
-        // Enter full screen
-
-        m_maximized = isMaximized();
-
-        // save geometry now, if the user quits when in full screen
-        // geometry won't be saved
-        writeSettings();
-
-#ifdef Q_WS_MAC
-        MacSupport::enterFullScreen(this, views);
-#else
-        mainToolBar->hide();
-        showFullScreen();
-#endif
-
-    } else {
-        // Exit full screen
-
-#ifdef Q_WS_MAC
-        MacSupport::exitFullScreen(this, views);
-#else
-        mainToolBar->show();
-        if (m_maximized) showMaximized();
-        else showNormal();
-#endif
-
-        // Make sure the window has focus
-        activateWindow();
-
-    }
-
-    updateUIForFullscreen();
-
-}
-
-void MainWindow::updateUIForFullscreen() {
-    static QList<QKeySequence> fsShortcuts;
-    static QString fsText;
-
-    if (m_fullscreen) {
-        fsShortcuts = fullscreenAct->shortcuts();
-        fsText = fullscreenAct->text();
-        fullscreenAct->setShortcuts(QList<QKeySequence>(fsShortcuts)
-                                    << QKeySequence(Qt::Key_Escape));
-        fullscreenAct->setText(tr("Leave &Full Screen"));
-    } else {
-        fullscreenAct->setShortcuts(fsShortcuts);
-        fullscreenAct->setText(fsText);
-    }
-
-    // No compact view action when in full screen
-    compactViewAct->setVisible(!m_fullscreen);
-    compactViewAct->setChecked(false);
-
-    // Hide anything but the video
-    mediaView->setPlaylistVisible(!m_fullscreen);
-    statusBar()->setVisible(!m_fullscreen);
-
-#ifndef APP_MAC
-    menuBar()->setVisible(!m_fullscreen);
-#endif
-
-    if (m_fullscreen) {
-        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
-    } else {
-        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
-    }
-
-#ifdef Q_WS_MAC
-    MacSupport::fullScreenActions(The::globalActions()->values(), m_fullscreen);
-#endif
-
-    if (views->currentWidget() == mediaView)
-        mediaView->setFocus();
-
-    if (m_fullscreen) {
-        hideMouse();
-    } else {
-        mouseTimer->stop();
-        unsetCursor();
-    }
-}
-
-void MainWindow::compactView(bool enable) {
-
-    static QList<QKeySequence> compactShortcuts;
-    static QList<QKeySequence> stopShortcuts;
-
-    const static QString key = "compactGeometry";
-    QSettings settings;
-
-#ifndef APP_MAC
-    menuBar()->setVisible(!enable);
-#endif
-
-    if (enable) {
-        setMinimumSize(160, 120);
-#ifdef Q_WS_MAC
-        mac::RemoveFullScreenWindow(winId());
-#endif
-        writeSettings();
-
-        if (settings.contains(key))
-            restoreGeometry(settings.value(key).toByteArray());
-        else
-            resize(320, 240);
-
-        mainToolBar->setVisible(!enable);
-        mediaView->setPlaylistVisible(!enable);
-        statusBar()->setVisible(!enable);
-
-        compactShortcuts = compactViewAct->shortcuts();
-        stopShortcuts = stopAct->shortcuts();
-
-        QList<QKeySequence> newStopShortcuts(stopShortcuts);
-        newStopShortcuts.removeAll(QKeySequence(Qt::Key_Escape));
-        stopAct->setShortcuts(newStopShortcuts);
-        compactViewAct->setShortcuts(QList<QKeySequence>(compactShortcuts) << QKeySequence(Qt::Key_Escape));
-
-        // ensure focus does not end up to the search box
-        // as it would steal the Space shortcut
-        mediaView->setFocus();
-
-    } else {
-        // unset minimum size
-        setMinimumSize(0, 0);
-#ifdef Q_WS_MAC
-        mac::SetupFullScreenWindow(winId());
-#endif
-        settings.setValue(key, saveGeometry());
-        mainToolBar->setVisible(!enable);
-        mediaView->setPlaylistVisible(!enable);
-        statusBar()->setVisible(!enable);
-        readSettings();
-
-        compactViewAct->setShortcuts(compactShortcuts);
-        stopAct->setShortcuts(stopShortcuts);
-    }
-
-    // auto float on top
-    floatOnTop(enable);
-}
-
-void MainWindow::searchFocus() {
-    toolbarSearch->selectAll();
-    toolbarSearch->setFocus();
-}
-
-void MainWindow::initPhonon() {
-    // Phonon initialization
-    if (mediaObject) delete mediaObject;
-    if (audioOutput) delete audioOutput;
-    mediaObject = new Phonon::MediaObject(this);
-    mediaObject->setTickInterval(100);
-    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
-            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
-    connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
-    connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
-    seekSlider->setMediaObject(mediaObject);
-    audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
-    connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
-    connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
-    volumeSlider->setAudioOutput(audioOutput);
-    Phonon::createPath(mediaObject, audioOutput);
-}
-
-void MainWindow::tick(qint64 time) {
-    if (time <= 0) {
-        // the "if" is important because tick is continually called
-        // and we don't want to paint the toolbar every 100ms
-        if (!currentTime->text().isEmpty()) currentTime->clear();
-        return;
-    }
-
-    currentTime->setText(formatTime(time));
-
-    // remaining time
-    const qint64 remainingTime = mediaObject->remainingTime();
-    currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
-
-    /*
-    slider->blockSignals(true);
-    slider->setValue(time/1000);
-    slider->blockSignals(false);
-    */
-}
-
-void MainWindow::totalTimeChanged(qint64 time) {
-    if (time <= 0) {
-        totalTime->clear();
-        return;
-    }
-    totalTime->setText(formatTime(time));
-
-    /*
-    slider->blockSignals(true);
-    slider->setMaximum(time/1000);
-    slider->blockSignals(false);
-    */
-
-}
-
-QString MainWindow::formatTime(qint64 time) {
-    QTime displayTime;
-    displayTime = displayTime.addMSecs(time);
-    QString timeString;
-    // 60 * 60 * 1000 = 3600000
-    if (time > 3600000)
-        timeString = displayTime.toString("h:mm:ss");
-    else
-        timeString = displayTime.toString("m:ss");
-    return timeString;
-}
-
-void MainWindow::volumeUp() {
-    qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
-    if (newVolume > volumeSlider->maximumVolume())
-        newVolume = volumeSlider->maximumVolume();
-    volumeSlider->audioOutput()->setVolume(newVolume);
-}
-
-void MainWindow::volumeDown() {
-    qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
-    if (newVolume < 0)
-        newVolume = 0;
-    volumeSlider->audioOutput()->setVolume(newVolume);
-}
-
-void MainWindow::volumeMute() {
-    volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
-}
-
-void MainWindow::volumeChanged(qreal newVolume) {
-    // automatically unmute when volume changes
-    if (volumeSlider->audioOutput()->isMuted())
-        volumeSlider->audioOutput()->setMuted(false);
-    statusBar()->showMessage(tr("Volume at %1%").arg((int)(newVolume*100)));
-}
-
-void MainWindow::volumeMutedChanged(bool muted) {
-    if (muted) {
-        volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
-        statusBar()->showMessage(tr("Volume is muted"));
-    } else {
-        volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
-        statusBar()->showMessage(tr("Volume is unmuted"));
-    }
-}
-
-void MainWindow::setDefinitionMode(QString definitionName) {
-    QAction *definitionAct = The::globalActions()->value("definition");
-    definitionAct->setText(definitionName);
-    definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
-                                + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
-    statusBar()->showMessage(definitionAct->statusTip());
-    QSettings settings;
-    settings.setValue("definition", definitionName);
-}
-
-void MainWindow::toggleDefinitionMode() {
-    QSettings settings;
-    QString currentDefinition = settings.value("definition").toString();
-    QStringList definitionNames = VideoDefinition::getDefinitionNames();
-    int currentIndex = definitionNames.indexOf(currentDefinition);
-    int nextIndex = 0;
-    if (currentIndex != definitionNames.size() - 1) {
-        nextIndex = currentIndex + 1;
-    }
-    QString nextDefinition = definitionNames.at(nextIndex);
-    setDefinitionMode(nextDefinition);
-}
-
-void MainWindow::showFullscreenToolbar(bool show) {
-    if (!m_fullscreen) return;
-    mainToolBar->setVisible(show);
-}
-
-void MainWindow::showFullscreenPlaylist(bool show) {
-    if (!m_fullscreen) return;
-    mediaView->setPlaylistVisible(show);
-}
-
-void MainWindow::clearRecentKeywords() {
-    QSettings settings;
-    settings.remove("recentKeywords");
-    settings.remove("recentChannels");
-    searchView->updateRecentKeywords();
-    searchView->updateRecentChannels();
-    statusBar()->showMessage(tr("Your privacy is now safe"));
-}
-
-void MainWindow::setManualPlay(bool enabled) {
-    QSettings settings;
-    settings.setValue("manualplay", QVariant::fromValue(enabled));
-    showActionInStatusBar(The::globalActions()->value("manualplay"), enabled);
-}
-
-void MainWindow::updateDownloadMessage(QString message) {
-    The::globalActions()->value("downloads")->setText(message);
-}
-
-void MainWindow::downloadsFinished() {
-    The::globalActions()->value("downloads")->setText(tr("&Downloads"));
-    statusBar()->showMessage(tr("Downloads complete"));
-}
-
-void MainWindow::toggleDownloads(bool show) {
-
-    if (show) {
-        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
-        The::globalActions()->value("downloads")->setShortcuts(
-                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
-                << QKeySequence(Qt::Key_Escape));
-    } else {
-        The::globalActions()->value("downloads")->setShortcuts(
-                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
-        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
-    }
-
-    if (!downloadView) {
-        downloadView = new DownloadView(this);
-        views->addWidget(downloadView);
-    }
-    if (show) showWidget(downloadView);
-    else goBack();
-}
-
-void MainWindow::startToolbarSearch(QString query) {
-    query = query.trimmed();
-
-    // check for empty query
-    if (query.length() == 0) {
-        return;
-    }
-
-    SearchParams *searchParams = new SearchParams();
-    searchParams->setKeywords(query);
-
-    // go!
-    showMedia(searchParams);
-}
-
-void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
-    if (event->mimeData()->hasFormat("text/uri-list")) {
-        QList<QUrl> urls = event->mimeData()->urls();
-        if (urls.isEmpty())
-            return;
-        QUrl url = urls.first();
-        QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
-        if (!videoId.isNull())
-            event->acceptProposedAction();
-    }
-}
-
-void MainWindow::dropEvent(QDropEvent *event) {
-    QList<QUrl> urls = event->mimeData()->urls();
-    if (urls.isEmpty())
-        return;
-    QUrl url = urls.first();
-    QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
-    if (!videoId.isNull()) {
-        setWindowTitle(url.toString());
-        SearchParams *searchParams = new SearchParams();
-        searchParams->setKeywords(videoId);
-        showMedia(searchParams);
-    }
-}
-
-void MainWindow::checkForUpdate() {
-    static const QString updateCheckKey = "updateCheck";
-
-    // check every 24h
-    QSettings settings;
-    uint unixTime = QDateTime::currentDateTime().toTime_t();
-    int lastCheck = settings.value(updateCheckKey).toInt();
-    int secondsSinceLastCheck = unixTime - lastCheck;
-    // qDebug() << "secondsSinceLastCheck" << unixTime << lastCheck << secondsSinceLastCheck;
-    if (secondsSinceLastCheck < 86400) return;
-
-    // check it out
-    if (updateChecker) delete updateChecker;
-    updateChecker = new UpdateChecker();
-    connect(updateChecker, SIGNAL(newVersion(QString)),
-            this, SLOT(gotNewVersion(QString)));
-    updateChecker->checkForUpdate();
-    settings.setValue(updateCheckKey, unixTime);
-}
-
-void MainWindow::gotNewVersion(QString version) {
-    if (updateChecker) {
-        delete updateChecker;
-        updateChecker = 0;
-    }
-
-    QSettings settings;
-    QString checkedVersion = settings.value("checkedVersion").toString();
-    if (checkedVersion == version) return;
-
-#ifdef APP_SIMPLEUPDATE
-    simpleUpdateDialog(version);
-#endif
-#if defined(APP_ACTIVATION) && !defined(APP_MAC)
-    UpdateDialog *dialog = new UpdateDialog(version, this);
-    dialog->show();
-#endif
-}
-
-void MainWindow::simpleUpdateDialog(QString version) {
-    QMessageBox msgBox(this);
-    msgBox.setIconPixmap(
-                QPixmap(":/images/app.png")
-                .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
-    msgBox.setText(tr("%1 version %2 is now available.").arg(Constants::NAME, version));
-    msgBox.setModal(true);
-    msgBox.setWindowModality(Qt::WindowModal);
-    msgBox.addButton(QMessageBox::Close);
-    QPushButton* laterButton = msgBox.addButton(tr("Remind me later"), QMessageBox::RejectRole);
-    QPushButton* updateButton = msgBox.addButton(tr("Update"), QMessageBox::AcceptRole);
-    msgBox.exec();
-    if (msgBox.clickedButton() != laterButton) {
-        QSettings settings;
-        settings.setValue("checkedVersion", version);
-    }
-    if (msgBox.clickedButton() == updateButton) visitSite();
-}
-
-void MainWindow::floatOnTop(bool onTop) {
-    showActionInStatusBar(The::globalActions()->value("ontop"), onTop);
-#ifdef APP_MAC
-    mac::floatOnTop(winId(), onTop);
-    return;
-#endif
-    if (onTop) {
-        setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
-        show();
-    } else {
-        setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
-        show();
-    }
-}
-
-void MainWindow::restore() {
-#ifdef APP_MAC
-    mac::uncloseWindow(window()->winId());
-#endif
-}
-
-void MainWindow::messageReceived(const QString &message) {
-    if (message == "--toggle-playing") {
-        if (pauseAct->isEnabled()) pauseAct->trigger();
-    } else if (message == "--next") {
-        if (skipAct->isEnabled()) skipAct->trigger();
-    } else if (message == "--previous") {
-        if (skipBackwardAct->isEnabled()) skipBackwardAct->trigger();
-    }  else if (message.startsWith("--")) {
-        MainWindow::printHelp();
-    } else if (!message.isEmpty()) {
-        SearchParams *searchParams = new SearchParams();
-        searchParams->setKeywords(message);
-        showMedia(searchParams);
-    }
-}
-
-void MainWindow::hideMouse() {
-    setCursor(Qt::BlankCursor);
-    mediaView->setPlaylistVisible(false);
-#ifndef APP_MAC
-    mainToolBar->setVisible(false);
-#endif
-}
-
-void MainWindow::printHelp() {
-    QString msg = QString("%1 %2\n\n").arg(Constants::NAME, Constants::VERSION);
-    msg += "Usage: minitube [options]\n";
-    msg += "Options:\n";
-    msg += "  --toggle-playing\t";
-    msg += "Start or pause playback.\n";
-    msg += "  --next\t\t";
-    msg += "Skip to the next video.\n";
-    msg += "  --previous\t\t";
-    msg += "Go back to the previous video.\n";
-    std::cout << msg.toLocal8Bit().data();
-}
-
-void MainWindow::showMessage(QString message) {
-    statusBar()->showMessage(message, 60000);
-}
-
-#ifdef APP_ACTIVATION
-void MainWindow::showActivationView(bool transition) {
-    QWidget *activationView = ActivationView::instance();
-    if (views->currentWidget() == activationView) {
-        buy();
-        return;
-    }
-    views->addWidget(activationView);
-    showWidget(activationView, transition);
-}
-
-void MainWindow::showActivationDialog() {
-    QTimer::singleShot(0, new ActivationDialog(this), SLOT(show()));
-}
-
-void MainWindow::buy() {
-    Extra::buy();
-}
-
-void MainWindow::hideBuyAction() {
-    QAction *action = The::globalActions()->value("buy");
-    action->setVisible(false);
-    action->setEnabled(false);
-}
-#endif
diff --git a/src/MainWindow.h b/src/MainWindow.h
deleted file mode 100644 (file)
index b0b3b74..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include <QtGui>
-#include <phonon/audiooutput.h>
-#include <phonon/volumeslider.h>
-#include <phonon/mediaobject.h>
-#include <phonon/seekslider.h>
-#include "View.h"
-#include "SearchView.h"
-#include "MediaView.h"
-#include "AboutView.h"
-#include "downloadview.h"
-
-class SearchLineEdit;
-class UpdateChecker;
-
-class MainWindow : public QMainWindow {
-
-    Q_OBJECT
-
-public:
-    static MainWindow* instance();
-    MainWindow();
-    ~MainWindow();
-    Phonon::SeekSlider* getSeekSlider() { return seekSlider; }
-    void readSettings();
-    void writeSettings();
-    static void printHelp();
-
-public slots:
-    void showMedia(SearchParams *params);
-    void restore();
-    void messageReceived(const QString &message);
-    void quit();
-    void startToolbarSearch(QString query);
-    void goBack();
-    void showMessage(QString message);
-#ifdef APP_ACTIVATION
-    void showActivationView(bool transition = true);
-    void showActivationDialog();
-    void buy();
-    void hideBuyAction();
-#endif
-
-protected:
-    void changeEvent(QEvent *);
-    void closeEvent(QCloseEvent *);
-    bool eventFilter(QObject *obj, QEvent *event);
-    void dragEnterEvent(QDragEnterEvent *event);
-    void dropEvent(QDropEvent *event);
-    void resizeEvent(QResizeEvent *);
-
-private slots:
-    void checkForUpdate();
-    void gotNewVersion(QString version);
-    void showSearch(bool transition = true);
-    void visitSite();
-    void donate();
-    void reportIssue();
-    void about();
-    void fullscreen();
-    void updateUIForFullscreen();
-    void compactView(bool enable);
-    void stop();
-    void stateChanged(Phonon::State newState, Phonon::State oldState);
-    void searchFocus();
-    void tick(qint64 time);
-    void totalTimeChanged(qint64 time);
-    void setDefinitionMode(QString definitionName);
-    void toggleDefinitionMode();
-    void clearRecentKeywords();
-
-    // volume shortcuts
-    void volumeUp();
-    void volumeDown();
-    void volumeMute();
-    void volumeChanged(qreal newVolume);
-    void volumeMutedChanged(bool muted);
-
-    // fullscreen toolbar
-    void showFullscreenToolbar(bool show);
-    void showFullscreenPlaylist(bool show);
-
-    void setManualPlay(bool enabled);
-    void updateDownloadMessage(QString);
-    void downloadsFinished();
-    void toggleDownloads(bool show);
-
-    void floatOnTop(bool);
-    void showActionInStatusBar(QAction*, bool show);
-    void showStopAfterThisInStatusBar(bool show);
-
-    void hideMouse();
-
-private:
-    void initPhonon();
-    void createActions();
-    void createMenus();
-    void createToolBars();
-    void createStatusBar();
-    void showWidget(QWidget*, bool transition = true);
-    static QString formatTime(qint64 time);
-    bool confirmQuit();
-    void simpleUpdateDialog(QString version);
-
-    UpdateChecker *updateChecker;
-
-    // view mechanism
-    QStackedWidget *views;
-    QStack<QWidget*> *history;
-
-    // view widgets
-    SearchView *searchView;
-    MediaView *mediaView;
-    QWidget *aboutView;
-    QWidget *downloadView;
-
-    // actions
-    QAction *addGadgetAct;
-    QAction *backAct;
-    QAction *quitAct;
-    QAction *siteAct;
-    QAction *donateAct;
-    QAction *aboutAct;
-    QAction *searchFocusAct;
-
-    // media actions
-    QAction *skipBackwardAct;
-    QAction *skipAct;
-    QAction *pauseAct;
-    QAction *stopAct;
-    QAction *fullscreenAct;
-    QAction *compactViewAct;
-    QAction *webPageAct;
-    QAction *copyPageAct;
-    QAction *copyLinkAct;
-    QAction *volumeUpAct;
-    QAction *volumeDownAct;
-    QAction *volumeMuteAct;
-    QAction *findVideoPartsAct;
-
-    // playlist actions
-    QAction *removeAct;
-    QAction *moveDownAct;
-    QAction *moveUpAct;
-    QAction *fetchMoreAct;
-    QAction *clearAct;
-
-    // menus
-    QMenu *fileMenu;
-    QMenu *viewMenu;
-    QMenu *playlistMenu;
-    QMenu *helpMenu;
-
-    // toolbar
-    QToolBar *mainToolBar;
-    SearchLineEdit *toolbarSearch;
-    QToolBar *statusToolBar;
-
-    // phonon
-    Phonon::SeekSlider *seekSlider;
-    Phonon::VolumeSlider *volumeSlider;
-    Phonon::MediaObject *mediaObject;
-    Phonon::AudioOutput *audioOutput;
-    QLabel *currentTime;
-    QLabel *totalTime;
-
-    bool m_fullscreen;
-    bool m_maximized;
-
-    QTimer *mouseTimer;
-
-};
-
-#endif
diff --git a/src/MediaView.cpp b/src/MediaView.cpp
deleted file mode 100644 (file)
index 1b0dce1..0000000
+++ /dev/null
@@ -1,882 +0,0 @@
-#include "MediaView.h"
-#include "playlistview.h"
-#include "playlist/PrettyItemDelegate.h"
-#include "networkaccess.h"
-#include "videowidget.h"
-#include "minisplitter.h"
-#include "constants.h"
-#include "downloadmanager.h"
-#include "downloaditem.h"
-#include "MainWindow.h"
-#include "temporary.h"
-#include "sidebarwidget.h"
-#include "playlistwidget.h"
-#include "refinesearchwidget.h"
-#include "sidebarwidget.h"
-#ifdef APP_MAC
-#include "macfullscreen.h"
-#endif
-#ifdef APP_ACTIVATION
-#include "activation.h"
-#endif
-
-namespace The {
-NetworkAccess* http();
-}
-
-namespace The {
-QMap<QString, QAction*>* globalActions();
-QMap<QString, QMenu*>* globalMenus();
-QNetworkAccessManager* networkAccessManager();
-}
-
-MediaView::MediaView(QWidget *parent) : QWidget(parent) {
-
-    reallyStopped = false;
-    downloadItem = 0;
-
-    QBoxLayout *layout = new QVBoxLayout();
-    layout->setMargin(0);
-
-    splitter = new MiniSplitter(this);
-    splitter->setChildrenCollapsible(false);
-
-    listView = new PlaylistView(this);
-    listView->setItemDelegate(new PrettyItemDelegate(this));
-    listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
-
-    // dragndrop
-    listView->setDragEnabled(true);
-    listView->setAcceptDrops(true);
-    listView->setDropIndicatorShown(true);
-    listView->setDragDropMode(QAbstractItemView::DragDrop);
-
-    // cosmetics
-    listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
-    listView->setFrameShape( QFrame::NoFrame );
-    listView->setAttribute(Qt::WA_MacShowFocusRect, false);
-    listView->setMinimumSize(320,240);
-    listView->setUniformItemSizes(true);
-
-    // respond to the user doubleclicking a playlist item
-    connect(listView, SIGNAL(activated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &)));
-
-    listModel = new ListModel(this);
-    connect(listModel, SIGNAL(activeRowChanged(int)), this, SLOT(activeRowChanged(int)));
-    // needed to restore the selection after dragndrop
-    connect(listModel, SIGNAL(needSelectionFor(QList<Video*>)), this, SLOT(selectVideos(QList<Video*>)));
-    listView->setModel(listModel);
-
-    connect(listView->selectionModel(),
-            SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )),
-            this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & )));
-
-    connect(listView, SIGNAL(authorPushed(QModelIndex)), SLOT(authorPushed(QModelIndex)));
-
-    sidebar = new SidebarWidget(this);
-    sidebar->setPlaylist(listView);
-    connect(sidebar->getRefineSearchWidget(), SIGNAL(searchRefined()),
-            SLOT(searchAgain()));
-    connect(listModel, SIGNAL(haveSuggestions(const QStringList &)),
-            sidebar, SLOT(showSuggestions(const QStringList &)));
-    connect(sidebar, SIGNAL(suggestionAccepted(QString)),
-            MainWindow::instance(), SLOT(startToolbarSearch(QString)));
-    splitter->addWidget(sidebar);
-
-    videoAreaWidget = new VideoAreaWidget(this);
-    videoAreaWidget->setMinimumSize(320,240);
-    videoWidget = new Phonon::VideoWidget(this);
-    videoAreaWidget->setVideoWidget(videoWidget);
-    videoAreaWidget->setListModel(listModel);
-
-    loadingWidget = new LoadingWidget(this);
-    videoAreaWidget->setLoadingWidget(loadingWidget);
-
-    splitter->addWidget(videoAreaWidget);
-
-    layout->addWidget(splitter);
-    setLayout(layout);
-
-    splitter->setStretchFactor(0, 1);
-    splitter->setStretchFactor(1, 6);
-
-    // restore splitter state
-    QSettings settings;
-    splitter->restoreState(settings.value("splitter").toByteArray());
-
-    errorTimer = new QTimer(this);
-    errorTimer->setSingleShot(true);
-    errorTimer->setInterval(3000);
-    connect(errorTimer, SIGNAL(timeout()), SLOT(skipVideo()));
-
-    workaroundTimer = new QTimer(this);
-    workaroundTimer->setSingleShot(true);
-    workaroundTimer->setInterval(3000);
-    connect(workaroundTimer, SIGNAL(timeout()), SLOT(timerPlay()));
-
-#ifdef APP_ACTIVATION
-    demoTimer = new QTimer(this);
-    demoTimer->setSingleShot(true);
-    connect(demoTimer, SIGNAL(timeout()), SLOT(demoMessage()));
-#endif
-
-}
-
-void MediaView::initialize() {
-    connect(videoAreaWidget, SIGNAL(doubleClicked()), The::globalActions()->value("fullscreen"), SLOT(trigger()));
-
-    /*
-    videoAreaWidget->setContextMenuPolicy(Qt::CustomContextMenu);
-    connect(videoAreaWidget, SIGNAL(customContextMenuRequested(QPoint)),
-            this, SLOT(showVideoContextMenu(QPoint)));
-            */
-
-    QAction* refineSearchAction = The::globalActions()->value("refine-search");
-    connect(refineSearchAction, SIGNAL(toggled(bool)),
-            sidebar, SLOT(toggleRefineSearch(bool)));
-}
-
-void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
-    this->mediaObject = mediaObject;
-    Phonon::createPath(this->mediaObject, videoWidget);
-    connect(mediaObject, SIGNAL(finished()), this, SLOT(playbackFinished()));
-    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
-            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
-    connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
-            this, SLOT(currentSourceChanged(Phonon::MediaSource)));
-    // connect(mediaObject, SIGNAL(bufferStatus(int)), loadingWidget, SLOT(bufferStatus(int)));
-    connect(mediaObject, SIGNAL(aboutToFinish()), SLOT(aboutToFinish()));
-}
-
-void MediaView::search(SearchParams *searchParams) {
-    reallyStopped = false;
-
-#ifdef APP_ACTIVATION
-    demoTimer->stop();
-#endif
-    workaroundTimer->stop();
-    errorTimer->stop();
-
-    this->searchParams = searchParams;
-
-    // start serching for videos
-    listModel->search(searchParams);
-
-    sidebar->showPlaylist();
-    listView->setFocus();
-
-    QString keyword = searchParams->keywords();
-    QString display = keyword;
-    if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
-        int separator = keyword.indexOf("|");
-        if (separator > 0 && separator + 1 < keyword.length()) {
-            display = keyword.mid(separator+1);
-        }
-    }
-
-    sidebar->getRefineSearchWidget()->setSearchParams(searchParams);
-    sidebar->hideSuggestions();
-
-}
-
-void MediaView::searchAgain() {
-    search(searchParams);
-}
-
-void MediaView::appear() {
-    listView->setFocus();
-}
-
-void MediaView::disappear() {
-    timerPlayFlag = true;
-}
-
-void MediaView::handleError(QString /* message */) {
-
-    QTimer::singleShot(500, this, SLOT(startPlaying()));
-
-    /*
-    videoAreaWidget->showError(message);
-    skippedVideo = listModel->activeVideo();
-    // recover from errors by skipping to the next video
-    errorTimer->start(2000);
-    */
-}
-
-void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/) {
-    // qDebug() << "Phonon state: " << newState;
-    // slider->setEnabled(newState == Phonon::PlayingState);
-
-    switch (newState) {
-
-    case Phonon::ErrorState:
-        qDebug() << "Phonon error:" << mediaObject->errorString() << mediaObject->errorType();
-        if (mediaObject->errorType() == Phonon::FatalError)
-            handleError(mediaObject->errorString());
-        break;
-
-    case Phonon::PlayingState:
-        // qDebug("playing");
-        videoAreaWidget->showVideo();
-        break;
-
-    case Phonon::StoppedState:
-        // qDebug("stopped");
-        // play() has already been called when setting the source
-        // but Phonon on Linux needs a little more help to start playback
-        // if (!reallyStopped) mediaObject->play();
-
-#ifdef APP_MAC
-        // Workaround for Mac playback start problem
-        if (!timerPlayFlag) {
-            // workaroundTimer->start();
-        }
-#endif
-
-        break;
-
-    case Phonon::PausedState:
-        qDebug("paused");
-        break;
-
-    case Phonon::BufferingState:
-        qDebug("buffering");
-        break;
-
-    case Phonon::LoadingState:
-        qDebug("loading");
-        break;
-
-    }
-}
-
-void MediaView::pause() {
-    // qDebug() << "pause() called" << mediaObject->state();
-
-    switch( mediaObject->state() ) {
-    case Phonon::PlayingState:
-        mediaObject->pause();
-        break;
-    default:
-        mediaObject->play();
-        break;
-    }
-
-}
-
-QRegExp MediaView::wordRE(QString s) {
-    return QRegExp("\\W" + s + "\\W?", Qt::CaseInsensitive);
-}
-
-void MediaView::stop() {
-    listModel->abortSearch();
-    reallyStopped = true;
-    mediaObject->stop();
-    videoAreaWidget->clear();
-    workaroundTimer->stop();
-    errorTimer->stop();
-    listView->selectionModel()->clearSelection();
-    if (downloadItem) {
-        downloadItem->stop();
-        delete downloadItem;
-        downloadItem = 0;
-    }
-    The::globalActions()->value("refine-search")->setChecked(false);
-}
-
-void MediaView::activeRowChanged(int row) {
-    if (reallyStopped) return;
-
-    Video *video = listModel->videoAt(row);
-    if (!video) return;
-
-    // now that we have a new video to play
-    // stop all the timers
-    workaroundTimer->stop();
-    errorTimer->stop();
-
-    mediaObject->stop();
-    if (downloadItem) {
-        downloadItem->stop();
-        delete downloadItem;
-        downloadItem = 0;
-    }
-    // slider->setMinimum(0);
-
-    // immediately show the loading widget
-    videoAreaWidget->showLoading(video);
-
-    connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl)), Qt::UniqueConnection);
-    // TODO handle signal in a proper slot and impl item error status
-    connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)), Qt::UniqueConnection);
-
-    video->loadStreamUrl();
-
-    // reset the timer flag
-    timerPlayFlag = false;
-
-    // video title in the statusbar
-    MainWindow::instance()->showMessage(video->title());
-
-    // ensure active item is visible
-    // int row = listModel->activeRow();
-    if (row != -1) {
-        QModelIndex index = listModel->index(row, 0, QModelIndex());
-        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...
-
-}
-
-void MediaView::gotStreamUrl(QUrl streamUrl) {
-    if (reallyStopped) return;
-
-    Video *video = static_cast<Video *>(sender());
-    if (!video) {
-        qDebug() << "Cannot get sender";
-        return;
-    }
-    video->disconnect(this);
-
-    QString tempFile = Temporary::filename();
-
-    Video *videoCopy = video->clone();
-    if (downloadItem) {
-        downloadItem->stop();
-        delete downloadItem;
-    }
-    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
-    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()), Qt::UniqueConnection);
-    // connect(downloadItem, SIGNAL(progress(int)), SLOT(downloadProgress(int)));
-    connect(downloadItem, SIGNAL(bufferProgress(int)), loadingWidget, SLOT(bufferStatus(int)), Qt::UniqueConnection);
-    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
-    connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)), Qt::UniqueConnection);
-    connect(downloadItem, SIGNAL(error(QString)), SLOT(handleError(QString)), Qt::UniqueConnection);
-    downloadItem->start();
-
-}
-
-/*
-void MediaView::downloadProgress(int percent) {
-    MainWindow* mainWindow = dynamic_cast<MainWindow*>(window());
-
-    mainWindow->getSeekSlider()->setStyleSheet(" QSlider::groove:horizontal {"
-        "border: 1px solid #999999;"
-        // "border-left: 50px solid rgba(255, 0, 0, 128);"
-        "height: 8px;"
-        "background: qlineargradient(x1:0, y1:0, x2:.5, y2:0, stop:0 rgba(255, 0, 0, 92), stop:"
-        + QString::number(percent/100.0) +
-
-        " rgba(255, 0, 0, 92), stop:" + QString::number((percent+1)/100.0) + " transparent, stop:1 transparent);"
-        "margin: 2px 0;"
-    "}"
-    "QSlider::handle:horizontal {"
-        "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);"
-        "border: 1px solid #5c5c5c;"
-        "width: 16px;"
-        "height: 16px;"
-        "margin: -2px 0;"
-        "border-radius: 8px;"
-    "}"
-
-    );
-}
-
-*/
-
-void MediaView::downloadStatusChanged() {
-    switch(downloadItem->status()) {
-    case Downloading:
-        startPlaying();
-        break;
-    case Starting:
-        // qDebug() << "Starting";
-        break;
-    case Finished:
-        // qDebug() << "Finished" << mediaObject->state();
-        // if (mediaObject->state() == Phonon::StoppedState) startPlaying();
-#ifdef Q_WS_X11
-        seekSlider->setEnabled(mediaObject->isSeekable());
-#endif
-        break;
-    case Failed:
-        // qDebug() << "Failed";
-    case Idle:
-        // qDebug() << "Idle";
-        break;
-    }
-}
-
-void MediaView::startPlaying() {
-    if (reallyStopped) return;
-    if (!downloadItem) {
-        skip();
-        return;
-    }
-
-    // go!
-    QString source = downloadItem->currentFilename();
-    qDebug() << "Playing" << source;
-    mediaObject->setCurrentSource(source);
-    mediaObject->play();
-#ifdef Q_WS_X11
-    seekSlider->setEnabled(false);
-#endif
-
-    // ensure we always have 10 videos ahead
-    listModel->searchNeeded();
-
-    // ensure active item is visible
-    int row = listModel->activeRow();
-    if (row != -1) {
-        QModelIndex index = listModel->index(row, 0, QModelIndex());
-        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
-    }
-
-#ifdef APP_ACTIVATION
-    if (!Activation::instance().isActivated())
-        demoTimer->start(180000);
-#endif
-
-}
-
-void MediaView::itemActivated(const QModelIndex &index) {
-    if (listModel->rowExists(index.row())) {
-
-        // if it's the current video, just rewind and play
-        Video *activeVideo = listModel->activeVideo();
-        Video *video = listModel->videoAt(index.row());
-        if (activeVideo && video && activeVideo == video) {
-            mediaObject->seek(0);
-            mediaObject->play();
-        } else listModel->setActiveRow(index.row());
-
-    // the user doubleclicked on the "Search More" item
-    } else {
-        listModel->searchMore();
-        listView->selectionModel()->clearSelection();
-    }
-}
-
-void MediaView::currentSourceChanged(const Phonon::MediaSource /* source */ ) {
-
-}
-
-void MediaView::skipVideo() {
-    // skippedVideo is useful for DELAYED skip operations
-    // in order to be sure that we're skipping the video we wanted
-    // and not another one
-    if (skippedVideo) {
-        if (listModel->activeVideo() != skippedVideo) {
-            qDebug() << "Skip of video canceled";
-            return;
-        }
-        int nextRow = listModel->rowForVideo(skippedVideo);
-        nextRow++;
-        if (nextRow == -1) return;
-        listModel->setActiveRow(nextRow);
-    }
-}
-
-void MediaView::skip() {
-    int nextRow = listModel->nextRow();
-    if (nextRow == -1) return;
-    listModel->setActiveRow(nextRow);
-}
-
-void MediaView::skipBackward() {
-    int prevRow = listModel->previousRow();
-    if (prevRow == -1) return;
-    listModel->setActiveRow(prevRow);
-}
-
-void MediaView::aboutToFinish() {
-    qint64 currentTime = mediaObject->currentTime();
-    qDebug() << __PRETTY_FUNCTION__ << currentTime;
-    if (currentTime + 10000 < mediaObject->totalTime()) {
-        // mediaObject->seek(mediaObject->currentTime());
-        // QTimer::singleShot(500, this, SLOT(playbackResume()));
-        mediaObject->seek(currentTime);
-        mediaObject->play();
-    }
-}
-
-void MediaView::playbackFinished() {
-    qDebug() << __PRETTY_FUNCTION__ << mediaObject->currentTime();
-    // 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(500, this, SLOT(playbackResume()));
-    } else {
-        QAction* stopAfterThisAction = The::globalActions()->value("stopafterthis");
-        if (stopAfterThisAction->isChecked()) {
-            stopAfterThisAction->setChecked(false);
-        } else skip();
-    }
-}
-
-void MediaView::playbackResume() {
-    qDebug() << __PRETTY_FUNCTION__ << mediaObject->currentTime();
-    mediaObject->seek(mediaObject->currentTime());
-    mediaObject->play();
-}
-
-void MediaView::openWebPage() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    mediaObject->pause();
-    QDesktopServices::openUrl(video->webpage());
-}
-
-void MediaView::copyWebPage() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    QString address = video->webpage().toString();
-    QApplication::clipboard()->setText(address);
-    QString message = tr("You can now paste the YouTube link into another application");
-    MainWindow::instance()->showMessage(message);
-}
-
-void MediaView::copyVideoLink() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    QApplication::clipboard()->setText(video->getStreamUrl().toEncoded());
-    QString message = tr("You can now paste the video stream URL into another application")
-            + ". " + tr("The link will be valid only for a limited time.");
-    MainWindow::instance()->showMessage(message);
-}
-
-void MediaView::removeSelected() {
-    if (!listView->selectionModel()->hasSelection()) return;
-    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
-    listModel->removeIndexes(indexes);
-}
-
-void MediaView::selectVideos(QList<Video*> videos) {
-    foreach (Video *video, videos) {
-        QModelIndex index = listModel->indexForVideo(video);
-        listView->selectionModel()->select(index, QItemSelectionModel::Select);
-        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
-    }
-}
-
-void MediaView::selectionChanged(const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/) {
-    const bool gotSelection = listView->selectionModel()->hasSelection();
-    The::globalActions()->value("remove")->setEnabled(gotSelection);
-    The::globalActions()->value("moveUp")->setEnabled(gotSelection);
-    The::globalActions()->value("moveDown")->setEnabled(gotSelection);
-}
-
-void MediaView::moveUpSelected() {
-    if (!listView->selectionModel()->hasSelection()) return;
-
-    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
-    qStableSort(indexes.begin(), indexes.end());
-    listModel->move(indexes, true);
-
-    // set current index after row moves to something more intuitive
-    int row = indexes.first().row();
-    listView->selectionModel()->setCurrentIndex(listModel->index(row>1?row:1), QItemSelectionModel::NoUpdate);
-}
-
-void MediaView::moveDownSelected() {
-    if (!listView->selectionModel()->hasSelection()) return;
-
-    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
-    qStableSort(indexes.begin(), indexes.end(), qGreater<QModelIndex>());
-    listModel->move(indexes, false);
-
-    // set current index after row moves to something more intuitive (respect 1 static item on bottom)
-    int row = indexes.first().row()+1, max = listModel->rowCount() - 2;
-    listView->selectionModel()->setCurrentIndex(listModel->index(row>max?max:row), QItemSelectionModel::NoUpdate);
-}
-
-void MediaView::showVideoContextMenu(QPoint point) {
-    The::globalMenus()->value("video")->popup(videoWidget->mapToGlobal(point));
-}
-
-void MediaView::searchMostRelevant() {
-    searchParams->setSortBy(SearchParams::SortByRelevance);
-    search(searchParams);
-}
-
-void MediaView::searchMostRecent() {
-    searchParams->setSortBy(SearchParams::SortByNewest);
-    search(searchParams);
-}
-
-void MediaView::searchMostViewed() {
-    searchParams->setSortBy(SearchParams::SortByViewCount);
-    search(searchParams);
-}
-
-void MediaView::setPlaylistVisible(bool visible) {
-    if (splitter->widget(0)->isVisible() == visible) return;
-    splitter->widget(0)->setVisible(visible);
-    listView->setFocus();
-}
-
-bool MediaView::isPlaylistVisible() {
-    return splitter->widget(0)->isVisible();
-}
-
-void MediaView::timerPlay() {
-    // Workaround Phonon bug on Mac OSX
-    // qDebug() << mediaObject->currentTime();
-    if (mediaObject->currentTime() <= 0 && mediaObject->state() == Phonon::PlayingState) {
-        // qDebug() << "Mac playback workaround";
-        mediaObject->pause();
-        // QTimer::singleShot(1000, mediaObject, SLOT(play()));
-        mediaObject->play();
-    }
-}
-
-void MediaView::saveSplitterState() {
-    QSettings settings;
-    settings.setValue("splitter", splitter->saveState());
-}
-
-#ifdef APP_ACTIVATION
-
-static QPushButton *continueButton;
-
-void MediaView::demoMessage() {
-    if (mediaObject->state() != Phonon::PlayingState) return;
-    mediaObject->pause();
-
-    QMessageBox msgBox(this);
-    msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
-    msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::NAME));
-    msgBox.setInformativeText(tr("It allows you to test the application and see if it works for you."));
-    msgBox.setModal(true);
-    // make it a "sheet" on the Mac
-    msgBox.setWindowModality(Qt::WindowModal);
-
-    continueButton = msgBox.addButton("5", QMessageBox::RejectRole);
-    continueButton->setEnabled(false);
-    QPushButton *buyButton = msgBox.addButton(tr("Get the full version"), QMessageBox::ActionRole);
-
-    QTimeLine *timeLine = new QTimeLine(6000, this);
-    timeLine->setCurveShape(QTimeLine::LinearCurve);
-    timeLine->setFrameRange(5, 0);
-    connect(timeLine, SIGNAL(frameChanged(int)), SLOT(updateContinueButton(int)));
-    timeLine->start();
-
-    msgBox.exec();
-
-    if (msgBox.clickedButton() == buyButton) {
-        MainWindow::instance()->showActivationView();
-    } else {
-        mediaObject->play();
-        demoTimer->start(600000);
-    }
-
-    delete timeLine;
-
-}
-
-void MediaView::updateContinueButton(int value) {
-    if (value == 0) {
-        continueButton->setText(tr("Continue"));
-        continueButton->setEnabled(true);
-    } else {
-        continueButton->setText(QString::number(value));
-    }
-}
-
-#endif
-
-void MediaView::downloadVideo() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    DownloadManager::instance()->addItem(video);
-    The::globalActions()->value("downloads")->setVisible(true);
-    QString message = tr("Downloading %1").arg(video->title());
-    MainWindow::instance()->showMessage(message);
-}
-
-void MediaView::snapshot() {
-    QImage image = videoWidget->snapshot();
-    qDebug() << image.size();
-
-    const QPixmap& pixmap = QPixmap::grabWindow(videoWidget->winId());
-    // qDebug() << pixmap.size();
-    videoAreaWidget->showSnapshotPreview(pixmap);
-}
-
-void MediaView::fullscreen() {
-    videoAreaWidget->setParent(0);
-    videoAreaWidget->showFullScreen();
-}
-
-/*
-void MediaView::setSlider(QSlider *slider) {
-    this->slider = slider;
-    // slider->setEnabled(false);
-    slider->setTracking(false);
-    // connect(slider, SIGNAL(valueChanged(int)), SLOT(sliderMoved(int)));
-}
-
-void MediaView::sliderMoved(int value) {
-    qDebug() << __func__;
-    int sliderPercent = (value * 100) / (slider->maximum() - slider->minimum());
-    qDebug() << slider->minimum() << value << slider->maximum();
-    if (sliderPercent <= downloadItem->currentPercent()) {
-        qDebug() << sliderPercent << downloadItem->currentPercent();
-        mediaObject->seek(value);
-    } else {
-        seekTo(value);
-    }
-}
-
-void MediaView::seekTo(int value) {
-    qDebug() << __func__;
-    mediaObject->pause();
-    workaroundTimer->stop();
-    errorTimer->stop();
-    // mediaObject->clear();
-
-    QString tempDir = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
-    QString tempFile = tempDir + "/minitube" + QString::number(value) + ".mp4";
-    if (!QFile::remove(tempFile)) {
-        qDebug() << "Cannot remove temp file";
-    }
-    Video *videoCopy = downloadItem->getVideo()->clone();
-    QUrl streamUrl = videoCopy->getStreamUrl();
-    streamUrl.addQueryItem("begin", QString::number(value));
-    if (downloadItem) delete downloadItem;
-    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
-    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()));
-    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
-    downloadItem->start();
-
-    // slider->setMinimum(value);
-
-}
-
-*/
-
-void MediaView::findVideoParts() {
-
-    // parts
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-
-    QString query = video->title();
-
-    static QString optionalSpace = "\\s*";
-    static QString staticCounterSeparators = "[\\/\\-]";
-    QString counterSeparators = "( of | " +
-            tr("of", "Used in video parts, as in '2 of 3'") +
-            " |" + staticCounterSeparators + ")";
-
-    // numbers from 1 to 15
-    static QString counterNumber = "([1-9]|1[0-5])";
-
-    // query.remove(QRegExp(counterSeparators + optionalSpace + counterNumber));
-    query.remove(QRegExp(counterNumber + optionalSpace + counterSeparators + optionalSpace + counterNumber));
-    query.remove(wordRE("pr?t\\.?" + optionalSpace + counterNumber));
-    query.remove(wordRE("ep\\.?" + optionalSpace + counterNumber));
-    query.remove(wordRE("part" + optionalSpace + counterNumber));
-    query.remove(wordRE("episode" + optionalSpace + counterNumber));
-    query.remove(wordRE(tr("part", "This is for video parts, as in 'Cool video - part 1'") +
-                        optionalSpace + counterNumber));
-    query.remove(wordRE(tr("episode", "This is for video parts, as in 'Cool series - episode 1'") +
-                        optionalSpace + counterNumber));
-    query.remove(QRegExp("[\\(\\)\\[\\]]"));
-
-#define NUMBERS "one|two|three|four|five|six|seven|eight|nine|ten"
-
-    QRegExp englishNumberRE = QRegExp(QLatin1String(".*(") + NUMBERS + ").*", Qt::CaseInsensitive);
-    // bool numberAsWords = englishNumberRE.exactMatch(query);
-    query.remove(englishNumberRE);
-
-    QRegExp localizedNumberRE = QRegExp(QLatin1String(".*(") + tr(NUMBERS) + ").*", Qt::CaseInsensitive);
-    // if (!numberAsWords) numberAsWords = localizedNumberRE.exactMatch(query);
-    query.remove(localizedNumberRE);
-
-    SearchParams *searchParams = new SearchParams();
-    searchParams->setTransient(true);
-    searchParams->setKeywords(query);
-    searchParams->setAuthor(video->author());
-
-    /*
-    if (!numberAsWords) {
-        qDebug() << "We don't have number as words";
-        // searchParams->setSortBy(SearchParams::SortByNewest);
-        // TODO searchParams->setReverseOrder(true);
-        // TODO searchParams->setMax(50);
-    }
-    */
-
-    search(searchParams);
-
-}
-
-void MediaView::shareViaTwitter() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    QUrl url("https://twitter.com/intent/tweet");
-    url.addQueryItem("via", "minitubeapp");
-    url.addQueryItem("text", video->title());
-    url.addQueryItem("url", video->webpage().toString());
-    QDesktopServices::openUrl(url);
-}
-
-void MediaView::shareViaFacebook() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    QUrl url("https://www.facebook.com/sharer.php");
-    url.addQueryItem("t", video->title());
-    url.addQueryItem("u", video->webpage().toString());
-    QDesktopServices::openUrl(url);
-}
-
-void MediaView::shareViaBuffer() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    QUrl url("http://bufferapp.com/add");
-    url.addQueryItem("via", "minitubeapp");
-    url.addQueryItem("text", video->title());
-    url.addQueryItem("url", video->webpage().toString());
-    if (!video->thumbnailUrls().isEmpty())
-        url.addQueryItem("picture", video->thumbnailUrls().first().toString());
-    QDesktopServices::openUrl(url);
-}
-
-void MediaView::shareViaEmail() {
-    Video* video = listModel->activeVideo();
-    if (!video) return;
-    QUrl url("mailto:");
-    url.addQueryItem("subject", video->title());
-    QString body = video->title() + "\n" +
-            video->webpage().toString() + "\n\n" +
-            tr("Sent from %1").arg(Constants::NAME) + "\n" +
-            Constants::WEBSITE;
-    url.addQueryItem("body", body);
-    QDesktopServices::openUrl(url);
-}
-
-void MediaView::authorPushed(QModelIndex index) {
-    Video* video = listModel->videoAt(index.row());
-    if (!video) return;
-
-    QString channel = video->authorUri();
-    if (channel.isEmpty()) channel = video->author();
-    if (channel.isEmpty()) return;
-
-    SearchParams *searchParams = new SearchParams();
-    searchParams->setAuthor(channel);
-    searchParams->setSortBy(SearchParams::SortByNewest);
-
-    // go!
-    search(searchParams);
-}
diff --git a/src/MediaView.h b/src/MediaView.h
deleted file mode 100644 (file)
index 54a2803..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef __MEDIAVIEW_H__
-#define __MEDIAVIEW_H__
-
-#include <QtGui>
-#include <QtNetwork>
-#include <phonon/mediaobject.h>
-#include <phonon/videowidget.h>
-#include <phonon/seekslider.h>
-#include "View.h"
-#include "ListModel.h"
-#include "segmentedcontrol.h"
-#include "searchparams.h"
-#include "loadingwidget.h"
-#include "videoareawidget.h"
-
-class DownloadItem;
-class PlaylistView;
-class SidebarWidget;
-
-namespace The {
-    QMap<QString, QAction*>* globalActions();
-}
-
-class MediaView : public QWidget, public View {
-    Q_OBJECT
-
-public:
-    MediaView(QWidget *parent);
-    void initialize();
-
-    // View
-    void appear();
-    void disappear();
-    QMap<QString, QVariant> metadata() {
-        QMap<QString, QVariant> metadata;
-        if (searchParams) {
-            metadata.insert("title", "");
-            metadata.insert("description", "");
-        }
-        return metadata;
-    }
-
-    void setMediaObject(Phonon::MediaObject *mediaObject);
-    void setSlider(Phonon::SeekSlider *slider) { this->seekSlider = slider; }
-
-public slots:
-    void search(SearchParams *searchParams);
-    void pause();
-    void stop();
-    void skip();
-    void skipBackward();
-    void skipVideo();
-    void openWebPage();
-    void copyWebPage();
-    void copyVideoLink();
-    void shareViaTwitter();
-    void shareViaFacebook();
-    void shareViaBuffer();
-    void shareViaEmail();
-    void removeSelected();
-    void moveUpSelected();
-    void moveDownSelected();
-    bool isPlaylistVisible();
-    void setPlaylistVisible(bool visible=true);
-    void saveSplitterState();
-    void downloadVideo();
-    void snapshot();
-    void fullscreen();
-    void findVideoParts();
-
-private slots:
-    // list/model
-    void itemActivated(const QModelIndex &index);
-    void selectionChanged (const QItemSelection & selected, const QItemSelection & deselected);
-    void activeRowChanged(int);
-    void selectVideos(QList<Video*> videos);
-    void gotStreamUrl(QUrl streamUrl);
-    void handleError(QString message);
-    // phonon
-    void stateChanged(Phonon::State newState, Phonon::State oldState);
-    void currentSourceChanged(const Phonon::MediaSource source);
-    void showVideoContextMenu(QPoint point);
-    void aboutToFinish();
-    // bar
-    void searchMostRelevant();
-    void searchMostRecent();
-    void searchMostViewed();
-    // timer
-    void timerPlay();
-#ifdef APP_ACTIVATION
-    void demoMessage();
-    void updateContinueButton(int);
-#endif
-    void startPlaying();
-    void downloadStatusChanged();
-    void playbackFinished();
-    void playbackResume();
-    void authorPushed(QModelIndex);
-    void searchAgain();
-
-    /*
-    void downloadProgress(int percent);
-    void sliderMoved(int value);
-    void seekTo(int value);
-    */
-
-private:
-    static QRegExp wordRE(QString s);
-
-    SearchParams *searchParams;
-
-    QSplitter *splitter;
-
-    SidebarWidget *sidebar;
-    PlaylistView *listView;
-    ListModel *listModel;
-
-    // sortBar
-    SegmentedControl *sortBar;
-    QAction *mostRelevantAction;
-    QAction *mostRecentAction;
-    QAction *mostViewedAction;
-
-    // phonon
-    Phonon::MediaObject *mediaObject;
-    Phonon::VideoWidget *videoWidget;
-    Phonon::SeekSlider *seekSlider;
-
-    // loadingWidget
-    VideoAreaWidget *videoAreaWidget;
-    LoadingWidget *loadingWidget;
-
-    bool timerPlayFlag;
-    bool reallyStopped;
-
-    QTimer *errorTimer;
-    QTimer *workaroundTimer;
-    Video *skippedVideo;
-
-#ifdef APP_ACTIVATION
-    QTimer *demoTimer;
-#endif
-
-    DownloadItem *downloadItem;
-
-};
-
-#endif // __MEDIAVIEW_H__
diff --git a/src/SearchView.cpp b/src/SearchView.cpp
deleted file mode 100644 (file)
index 89dc98a..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-#include "SearchView.h"
-#include "constants.h"
-#include "fontutils.h"
-#include "searchparams.h"
-#include "youtubesuggest.h"
-#include "channelsuggest.h"
-#ifdef APP_MAC
-#include "searchlineedit_mac.h"
-#else
-#include "searchlineedit.h"
-#endif
-#ifndef Q_WS_X11
-#include "extra.h"
-#endif
-#ifdef APP_ACTIVATION
-#include "activation.h"
-#endif
-#include "MainWindow.h"
-
-namespace The {
-QMap<QString, QAction*>* globalActions();
-}
-
-static const QString recentKeywordsKey = "recentKeywords";
-static const QString recentChannelsKey = "recentChannels";
-static const int PADDING = 30;
-
-SearchView::SearchView(QWidget *parent) : QWidget(parent) {
-
-    QFont biggerFont = FontUtils::big();
-    QFont smallerFont = FontUtils::smallBold();
-
-#if defined(APP_MAC) | defined(APP_WIN)
-    // speedup painting since we'll paint the whole background
-    // by ourselves anyway in paintEvent()
-    setAttribute(Qt::WA_OpaquePaintEvent);
-#endif
-
-    QBoxLayout *mainLayout = new QVBoxLayout();
-    mainLayout->setMargin(0);
-    mainLayout->setSpacing(0);
-
-    // hidden message widget
-    message = new QLabel(this);
-    message->hide();
-    mainLayout->addWidget(message);
-
-#ifdef APP_ACTIVATION
-    if (!Activation::instance().isActivated())
-        mainLayout->addWidget(Extra::buyButton(tr("Get the full version")), 0, Qt::AlignCenter);
-#endif
-
-    mainLayout->addStretch();
-    mainLayout->addSpacing(PADDING);
-
-    QBoxLayout *hLayout = new QHBoxLayout();
-    hLayout->setAlignment(Qt::AlignCenter);
-    mainLayout->addLayout(hLayout);
-
-    QLabel *logo = new QLabel(this);
-    logo->setPixmap(QPixmap(":/images/app.png"));
-    hLayout->addWidget(logo, 0, Qt::AlignTop);
-    hLayout->addSpacing(PADDING);
-
-    QVBoxLayout *layout = new QVBoxLayout();
-    layout->setAlignment(Qt::AlignCenter);
-    hLayout->addLayout(layout);
-
-    QLabel *welcomeLabel =
-            new QLabel("<h1 style='font-weight:normal'>" +
-                       tr("Welcome to <a href='%1'>%2</a>,")
-                       // .replace("<a ", "<a style='color:palette(text)'")
-                       .replace("<a href", "<a style='text-decoration:none; color:palette(text); font-weight:bold' href")
-                       .arg(Constants::WEBSITE, Constants::NAME)
-                       + "</h1>", this);
-    welcomeLabel->setOpenExternalLinks(true);
-    layout->addWidget(welcomeLabel);
-
-    layout->addSpacing(PADDING / 2);
-
-    QBoxLayout *tipLayout = new QHBoxLayout();
-    tipLayout->setSpacing(10);
-
-    //: "Enter", as in "type". The whole phrase says: "Enter a keyword to start watching videos"
-    QLabel *tipLabel = new QLabel(tr("Enter"), this);
-    tipLabel->setFont(biggerFont);
-    tipLayout->addWidget(tipLabel);
-
-    typeCombo = new QComboBox(this);
-    typeCombo->addItem(tr("a keyword"));
-    typeCombo->addItem(tr("a channel"));
-    typeCombo->setFont(biggerFont);
-    connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
-    tipLayout->addWidget(typeCombo);
-
-    tipLabel = new QLabel(tr("to start watching videos."), this);
-    tipLabel->setFont(biggerFont);
-    tipLayout->addWidget(tipLabel);
-    layout->addLayout(tipLayout);
-
-    layout->addSpacing(PADDING / 2);
-
-    QHBoxLayout *searchLayout = new QHBoxLayout();
-    searchLayout->setAlignment(Qt::AlignVCenter);
-
-    queryEdit = new SearchLineEdit(this);
-    queryEdit->setFont(biggerFont);
-    queryEdit->setMinimumWidth(queryEdit->fontInfo().pixelSize()*15);
-    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);
-    searchTypeChanged(0);
-
-    searchLayout->addWidget(queryEdit);
-    searchLayout->addSpacing(10);
-
-    watchButton = new QPushButton(tr("Watch"), this);
-    watchButton->setDefault(true);
-    watchButton->setEnabled(false);
-    watchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-    connect(watchButton, SIGNAL(clicked()), this, SLOT(watch()));
-    searchLayout->addWidget(watchButton);
-
-    layout->addItem(searchLayout);
-
-    layout->addSpacing(PADDING / 2);
-
-    QHBoxLayout *otherLayout = new QHBoxLayout();
-    otherLayout->setMargin(0);
-    otherLayout->setSpacing(10);
-
-    recentKeywordsLayout = new QVBoxLayout();
-    recentKeywordsLayout->setSpacing(5);
-    recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
-    recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
-    recentKeywordsLabel->setProperty("recentHeader", true);
-    recentKeywordsLabel->setForegroundRole(QPalette::Dark);
-    recentKeywordsLabel->hide();
-    recentKeywordsLabel->setFont(smallerFont);
-    recentKeywordsLayout->addWidget(recentKeywordsLabel);
-
-    otherLayout->addLayout(recentKeywordsLayout);
-
-    // recent channels
-    recentChannelsLayout = new QVBoxLayout();
-    recentChannelsLayout->setSpacing(5);
-    recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
-    recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
-    recentChannelsLabel->setProperty("recentHeader", true);
-    recentChannelsLabel->setForegroundRole(QPalette::Dark);
-    recentChannelsLabel->hide();
-    recentChannelsLabel->setFont(smallerFont);
-    recentChannelsLayout->addWidget(recentChannelsLabel);
-
-    otherLayout->addLayout(recentChannelsLayout);
-
-    layout->addLayout(otherLayout);
-
-    mainLayout->addSpacing(PADDING);
-    mainLayout->addStretch();
-
-    setLayout(mainLayout);
-
-}
-
-void SearchView::appear() {
-    updateRecentKeywords();
-    updateRecentChannels();
-    queryEdit->selectAll();
-    queryEdit->enableSuggest();
-    QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
-}
-
-void SearchView::updateRecentKeywords() {
-
-    // cleanup
-    QLayoutItem *item;
-    while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
-        item->widget()->close();
-        delete item;
-    }
-
-    // load
-    QSettings settings;
-    QStringList keywords = settings.value(recentKeywordsKey).toStringList();
-    recentKeywordsLabel->setVisible(!keywords.isEmpty());
-    The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
-
-    foreach (QString keyword, keywords) {
-        QString link = keyword;
-        QString display = keyword;
-        if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
-            int separator = keyword.indexOf("|");
-            if (separator > 0 && separator + 1 < keyword.length()) {
-                link = keyword.left(separator);
-                display = keyword.mid(separator+1);
-            }
-        }
-        bool needStatusTip = false;
-        if (display.length() > 24) {
-            display.truncate(24);
-            display.append("...");
-            needStatusTip = true;
-        }
-        QLabel *itemLabel = new QLabel("<a href=\"" + link
-                                       + "\" 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
-        itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
-        if (needStatusTip)
-            itemLabel->setStatusTip(link);
-        connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchKeywords(QString)));
-        recentKeywordsLayout->addWidget(itemLabel);
-    }
-
-}
-
-void SearchView::updateRecentChannels() {
-
-    // cleanup
-    QLayoutItem *item;
-    while ((item = recentChannelsLayout->takeAt(1)) != 0) {
-        item->widget()->close();
-        delete item;
-    }
-
-    // load
-    QSettings settings;
-    QStringList keywords = settings.value(recentChannelsKey).toStringList();
-    recentChannelsLabel->setVisible(!keywords.isEmpty());
-    // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
-
-    foreach (QString keyword, keywords) {
-        QString link = keyword;
-        QString display = keyword;
-        if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
-            int separator = keyword.indexOf("|");
-            if (separator > 0 && separator + 1 < keyword.length()) {
-                link = keyword.left(separator);
-                display = keyword.mid(separator+1);
-            }
-        }
-        QLabel *itemLabel = new QLabel("<a href=\"" + link
-                                       + "\" 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
-        itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
-
-        connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
-        recentChannelsLayout->addWidget(itemLabel);
-    }
-
-}
-
-void SearchView::watch() {
-    QString query = queryEdit->text();
-    watch(query);
-}
-
-void SearchView::textChanged(const QString &text) {
-    watchButton->setEnabled(!text.simplified().isEmpty());
-}
-
-void SearchView::watch(QString query) {
-
-    query = query.simplified();
-
-    // check for empty query
-    if (query.length() == 0) {
-        queryEdit->setFocus(Qt::OtherFocusReason);
-        return;
-    }
-
-    SearchParams *searchParams = new SearchParams();
-    if (typeCombo->currentIndex() == 0)
-        searchParams->setKeywords(query);
-    else {
-        // remove spaces from channel name
-        query = query.replace(" ", "");
-        searchParams->setAuthor(query);
-        searchParams->setSortBy(SearchParams::SortByNewest);
-    }
-
-    // go!
-    emit search(searchParams);
-}
-
-void SearchView::watchChannel(QString channel) {
-
-    channel = channel.simplified();
-
-    // check for empty query
-    if (channel.length() == 0) {
-        queryEdit->setFocus(Qt::OtherFocusReason);
-        return;
-    }
-
-    // remove spaces from channel name
-    channel = channel.remove(" ");
-
-    SearchParams *searchParams = new SearchParams();
-    searchParams->setAuthor(channel);
-    searchParams->setSortBy(SearchParams::SortByNewest);
-
-    // go!
-    emit search(searchParams);
-}
-
-void SearchView::watchKeywords(QString query) {
-
-    query = query.simplified();
-
-    // check for empty query
-    if (query.length() == 0) {
-        queryEdit->setFocus(Qt::OtherFocusReason);
-        return;
-    }
-
-    if (typeCombo->currentIndex() == 0) {
-        queryEdit->setText(query);
-        watchButton->setEnabled(true);
-    }
-
-    SearchParams *searchParams = new SearchParams();
-    searchParams->setKeywords(query);
-
-    // go!
-    emit search(searchParams);
-}
-
-void SearchView::paintEvent(QPaintEvent * /*event*/) {
-#if defined(APP_MAC) | defined(APP_WIN)
-    QBrush brush;
-    if (window()->isActiveWindow()) {
-        brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
-    } else {
-        brush = palette().window();
-    }
-    QPainter painter(this);
-    painter.fillRect(0, 0, width(), height(), brush);
-#endif
-}
-
-void SearchView::searchTypeChanged(int index) {
-    if (index == 0) {
-        queryEdit->setSuggester(youtubeSuggest);
-    } else {
-        queryEdit->setSuggester(channelSuggest);
-    }
-    queryEdit->selectAll();
-    queryEdit->setFocus();
-}
diff --git a/src/SearchView.h b/src/SearchView.h
deleted file mode 100644 (file)
index b6be275..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __SEARCHVIEW_H__
-#define __SEARCHVIEW_H__
-
-#include <QtGui>
-#include "View.h"
-
-class SearchLineEdit;
-class SearchParams;
-class YouTubeSuggest;
-class ChannelSuggest;
-
-class SearchView : public QWidget, public View {
-
-    Q_OBJECT
-
-public:
-    SearchView(QWidget *parent);
-    void updateRecentKeywords();
-    void updateRecentChannels();
-    void appear();
-    void disappear() {}
-
-    QMap<QString, QVariant> metadata() {
-        QMap<QString, QVariant> metadata;
-        metadata.insert("title", "");
-        metadata.insert("description", tr("Make yourself comfortable"));
-        return metadata;
-    }
-
-public slots:
-    void watch(QString query);
-    void watchChannel(QString channel);
-    void watchKeywords(QString query);
-
-signals:
-    void search(SearchParams*);
-
-protected:
-    void paintEvent(QPaintEvent *);
-
-private slots:
-    void watch();
-    void textChanged(const QString &text);
-    void searchTypeChanged(int index);
-
-private:
-    YouTubeSuggest *youtubeSuggest;
-    ChannelSuggest *channelSuggest;
-
-    QComboBox *typeCombo;
-    SearchLineEdit *queryEdit;
-    QLabel *recentKeywordsLabel;
-    QBoxLayout *recentKeywordsLayout;
-    QLabel *recentChannelsLabel;
-    QBoxLayout *recentChannelsLayout;
-    QLabel *message;
-    QPushButton *watchButton;
-
-};
-
-#endif // __SEARCHVIEW_H__
diff --git a/src/View.h b/src/View.h
deleted file mode 100644 (file)
index ea701bd..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef VIEW_H
-#define VIEW_H
-
-class View {
-
-    public:
-        virtual QMap<QString, QVariant> metadata() = 0;
-        virtual void appear() = 0;
-        virtual void disappear() = 0;
-
-};
-
-#endif // VIEW_H
diff --git a/src/aboutview.cpp b/src/aboutview.cpp
new file mode 100644 (file)
index 0000000..9a5e259
--- /dev/null
@@ -0,0 +1,114 @@
+#include "aboutview.h"
+#include "constants.h"
+#ifndef Q_WS_X11
+#include "extra.h"
+#endif
+#ifdef APP_ACTIVATION
+#include "activation.h"
+#endif
+#ifdef APP_MAC
+#include "macutils.h"
+#include "mac_startup.h"
+#endif
+
+AboutView::AboutView(QWidget *parent) : QWidget(parent) {
+
+    QBoxLayout *hLayout = new QHBoxLayout(this);
+    hLayout->setAlignment(Qt::AlignCenter);
+    hLayout->setMargin(30);
+    hLayout->setSpacing(30);
+
+    QLabel *logo = new QLabel(this);
+    logo->setPixmap(QPixmap(":/images/app.png"));
+    hLayout->addWidget(logo, 0, Qt::AlignTop);
+
+    QBoxLayout *layout = new QVBoxLayout();
+    layout->setAlignment(Qt::AlignCenter);
+    layout->setSpacing(30);
+    hLayout->addLayout(layout);
+
+    QString info = "<html><style>a { color: palette(text); text-decoration: none; font-weight: bold }</style><body>"
+            "<h1>" + QString(Constants::NAME) + "</h1>"
+            "<p>" + tr("There's life outside the browser!") + "</p>"
+            "<p>" + tr("Version %1").arg(Constants::VERSION) + "</p>"
+            + QString("<p><a href=\"%1/\">%1</a></p>").arg(Constants::WEBSITE);
+
+#ifdef APP_ACTIVATION
+    if (Activation::instance().isActivated())
+        info += "<p>" + tr("Licensed to: %1").arg("<b>" + Activation::instance().getEmail() + "</b>");
+#endif
+
+#ifdef Q_WS_X11
+    info += "<p>" +  tr("%1 is Free Software but its development takes precious time.").arg(Constants::NAME) + "<br/>"
+            + tr("Please <a href='%1'>donate</a> to support the continued development of %2.")
+            .arg(QString(Constants::WEBSITE).append("#donate"), Constants::NAME) + "</p>";
+#endif
+
+    info += "<p>" + tr("You may want to try my other apps as well:") + "</p>"
+            "<ul>"
+
+            "<li>" + tr("%1, a YouTube music player")
+            .arg("<a href='http://flavio.tordini.org/musictube'>Musictube</a>")
+            + "</li>"
+
+            "<li>" + tr("%1, a music player")
+            .arg("<a href='http://flavio.tordini.org/musique'>Musique</a>")
+            + "</li>"
+
+            "</ul>"
+
+            "<p>" + tr("Translate %1 to your native language using %2").arg(Constants::NAME)
+            .arg("<a href='http://www.transifex.net/projects/p/" + QString(Constants::UNIX_NAME) + "/resource/main/'>Transifex</a>")
+            + "</p>"
+
+            "<p>"
+            + tr("Icon designed by %1.").arg("<a href='http://www.kolorguild.com/'>David Nel</a>")
+            + "</p>"
+
+        #ifdef Q_WS_X11
+            "<p>" + tr("Released under the <a href='%1'>GNU General Public License</a>")
+            .arg("http://www.gnu.org/licenses/gpl.html") + "</p>"
+        #endif
+            "<p>&copy; 2009-2012 " + Constants::ORG_NAME + "</p>"
+            "</body></html>";
+    QLabel *infoLabel = new QLabel(info, this);
+    infoLabel->setOpenExternalLinks(true);
+    infoLabel->setWordWrap(true);
+    layout->addWidget(infoLabel);
+
+    QLayout *buttonLayout = new QHBoxLayout();
+    buttonLayout->setMargin(0);
+    buttonLayout->setSpacing(0);
+    buttonLayout->setAlignment(Qt::AlignLeft);
+
+    QPushButton *closeButton = new QPushButton(tr("&Close"), this);
+    closeButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+    closeButton->setDefault(true);
+    closeButton->setFocus(Qt::OtherFocusReason);
+    connect(closeButton, SIGNAL(clicked()), parent, SLOT(goBack()));
+    buttonLayout->addWidget(closeButton);
+
+    layout->addLayout(buttonLayout);
+}
+
+void AboutView::paintEvent(QPaintEvent * /*event*/) {
+#if defined(APP_MAC) | defined(APP_WIN)
+    QBrush brush;
+    if (window()->isActiveWindow()) {
+        brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
+    } else {
+        brush = palette().window();
+    }
+    QPainter painter(this);
+    painter.fillRect(0, 0, width(), height(), brush);
+#endif
+}
+
+void AboutView::appear() {
+#ifdef APP_MAC
+    mac::uncloseWindow(window()->winId());
+#ifdef APP_ACTIVATION
+    mac::CheckForUpdates();
+#endif
+#endif
+}
diff --git a/src/aboutview.h b/src/aboutview.h
new file mode 100644 (file)
index 0000000..912c63c
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef ABOUTVIEW_H
+#define ABOUTVIEW_H
+
+#include <QtGui>
+#include "view.h"
+#include "constants.h"
+
+class AboutView : public QWidget, public View {
+
+    Q_OBJECT
+
+public:
+    AboutView(QWidget *parent);
+    void appear();
+    QHash<QString, QVariant> metadata() {
+        QHash<QString, QVariant> metadata;
+        metadata.insert("title", tr("About"));
+        metadata.insert("description",
+                        tr("What you always wanted to know about %1 and never dared to ask")
+                        .arg(Constants::NAME));
+        return metadata;
+    }
+
+protected:
+    void paintEvent(QPaintEvent *);
+
+};
+#endif
index 25ddf2feb56ad3e6668c90dc259a7b70b412b6bc..4ebb34ccb049ba5e51b683c2782fa9652dccd9b9 100644 (file)
@@ -1,6 +1,6 @@
 #include "downloadlistview.h"
 #include "downloadmodel.h"
-#include "playlist/PrettyItemDelegate.h"
+#include "playlistitemdelegate.h"
 
 DownloadListView::DownloadListView(QWidget *parent) : QListView(parent) {
 
@@ -48,7 +48,7 @@ bool DownloadListView::isHoveringPlayIcon(QMouseEvent *event) {
     const QRect itemRect = visualRect(itemIndex);
     // qDebug() << " itemRect.x()" <<  itemRect.x();
 
-    PrettyItemDelegate *delegate = dynamic_cast<PrettyItemDelegate *>(itemDelegate());
+    PlaylistItemDelegate *delegate = dynamic_cast<PlaylistItemDelegate *>(itemDelegate());
     if (!delegate) return false;
 
     QRect buttonRect = delegate->downloadButtonRect(itemRect);
index b06b3ec086c8edabe656c493ee9fdd9e455b851b..64302056e65a2ac5f6b9760d64598654937ae64a 100644 (file)
@@ -3,7 +3,7 @@
 #include "downloadmodel.h"
 #include "video.h"
 #include "constants.h"
-#include "MainWindow.h"
+#include "mainwindow.h"
 #ifdef APP_ACTIVATION
 #include "activation.h"
 #endif
index d68db0e3429985d410f726e4b3c6b3a8e784efef..702711eff646e912fe2ca70b51e592aed5211981 100644 (file)
@@ -2,7 +2,7 @@
 #include "downloadmanager.h"
 #include "downloaditem.h"
 #include "video.h"
-#include "ListModel.h"
+#include "listmodel.h"
 
 DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent) :
         QAbstractListModel(parent),
index 990f5c7c684491af32685c165c02a31fded27c26..d73182e73e543088087a30f898b6267699bb9883 100644 (file)
@@ -1,6 +1,6 @@
 #include "downloadsettings.h"
 #include "downloadmanager.h"
-#include "MainWindow.h"
+#include "mainwindow.h"
 
 DownloadSettings::DownloadSettings(QWidget *parent) : QWidget(parent) {
 
index 3ed343b7e30f32d3a25519d44b904a912346de0b..11b7400bc6849cbb381c73512e12d97c704298d4 100644 (file)
@@ -4,8 +4,8 @@
 #include "downloadlistview.h"
 #include "downloaditem.h"
 #include "downloadsettings.h"
-#include "ListModel.h"
-#include "playlist/PrettyItemDelegate.h"
+#include "listmodel.h"
+#include "playlistitemdelegate.h"
 #include "segmentedcontrol.h"
 
 DownloadView::DownloadView(QWidget *parent) : QWidget(parent) {
@@ -28,7 +28,7 @@ DownloadView::DownloadView(QWidget *parent) : QWidget(parent) {
     p.setColor(QPalette::Base, palette().color(QPalette::Window));
     listView->setPalette(p);
     */
-    PrettyItemDelegate *delegate = new PrettyItemDelegate(this, true);
+    PlaylistItemDelegate *delegate = new PlaylistItemDelegate(this, true);
     listView->setItemDelegate(delegate);
     listView->setSelectionMode(QAbstractItemView::NoSelection);
 
index fdbbb54ba841b689e32ebcb600e19535b31af10e..2ac7b3d742e880b8e71f5569e73565af3f63b0e5 100644 (file)
@@ -2,7 +2,7 @@
 #define DOWNLOADVIEW_H
 
 #include <QtGui>
-#include "View.h"
+#include "view.h"
 
 class SegmentedControl;
 class DownloadModel;
@@ -17,10 +17,9 @@ public:
     DownloadView(QWidget *parent);
     void appear();
     void disappear();
-    QMap<QString, QVariant> metadata() {
-        QMap<QString, QVariant> metadata;
+    QHash<QString, QVariant> metadata() {
+        QHash<QString, QVariant> metadata;
         metadata.insert("title", tr("Downloads"));
-        metadata.insert("description", "");
         return metadata;
     }
 
diff --git a/src/listmodel.cpp b/src/listmodel.cpp
new file mode 100644 (file)
index 0000000..4e8662b
--- /dev/null
@@ -0,0 +1,470 @@
+#include "listmodel.h"
+#include "videomimedata.h"
+
+#define MAX_ITEMS 10
+static const QString recentKeywordsKey = "recentKeywords";
+static const QString recentChannelsKey = "recentChannels";
+
+ListModel::ListModel(QWidget *parent) : QAbstractListModel(parent) {
+    youtubeSearch = 0;
+    searching = false;
+    canSearchMore = true;
+    m_activeVideo = 0;
+    m_activeRow = -1;
+    skip = 1;
+
+    hoveredRow = -1;
+    authorHovered = false;
+    authorPressed = false;
+}
+
+ListModel::~ListModel() {
+    delete youtubeSearch;
+}
+
+int ListModel::rowCount(const QModelIndex &/*parent*/) const {
+    int count = videos.size();
+    
+    // add the message item
+    if (videos.isEmpty() || !searching)
+        count++;
+    
+    return count;
+}
+
+QVariant ListModel::data(const QModelIndex &index, int role) const {
+    
+    int row = index.row();
+    
+    if (row == videos.size()) {
+        
+        QPalette palette;
+        QFont boldFont;
+        boldFont.setBold(true);
+        
+        switch (role) {
+        case ItemTypeRole:
+            return ItemTypeShowMore;
+        case Qt::DisplayRole:
+        case Qt::StatusTipRole:
+            if (!errorMessage.isEmpty()) return errorMessage;
+            if (searching) return tr("Searching...");
+            if (canSearchMore) return tr("Show %1 More").arg(MAX_ITEMS);
+            if (videos.isEmpty()) return tr("No videos");
+            else return tr("No more videos");
+        case Qt::TextAlignmentRole:
+            return QVariant(int(Qt::AlignHCenter | Qt::AlignVCenter));
+        case Qt::ForegroundRole:
+            if (!errorMessage.isEmpty())
+                return palette.color(QPalette::ToolTipText);
+            else
+                return palette.color(QPalette::Dark);
+        case Qt::BackgroundColorRole:
+            if (!errorMessage.isEmpty())
+                return palette.color(QPalette::ToolTipBase);
+            else
+                return QVariant();
+        case Qt::FontRole:
+            return boldFont;
+        default:
+            return QVariant();
+        }
+        
+    } else if (row < 0 || row >= videos.size())
+        return QVariant();
+    
+    Video *video = videos.at(row);
+    
+    switch (role) {
+    case ItemTypeRole:
+        return ItemTypeVideo;
+    case VideoRole:
+        return QVariant::fromValue(QPointer<Video>(video));
+    case ActiveTrackRole:
+        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();
+}
+
+void ListModel::setActiveRow( int row) {
+    if ( rowExists( row ) ) {
+        
+        m_activeRow = row;
+        m_activeVideo = videoAt(row);
+        
+        int oldactiverow = m_activeRow;
+        
+        if ( rowExists( oldactiverow ) )
+            emit dataChanged( createIndex( oldactiverow, 0 ), createIndex( oldactiverow, columnCount() - 1 ) );
+        
+        emit dataChanged( createIndex( m_activeRow, 0 ), createIndex( m_activeRow, columnCount() - 1 ) );
+        emit activeRowChanged(row);
+        
+    } else {
+        m_activeRow = -1;
+        m_activeVideo = 0;
+    }
+
+}
+
+int ListModel::nextRow() const {
+    int nextRow = m_activeRow + 1;
+    if (rowExists(nextRow))
+        return nextRow;
+    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 );
+    return 0;
+}
+
+Video* ListModel::activeVideo() const {
+    return m_activeVideo;
+}
+
+void ListModel::search(SearchParams *searchParams) {
+
+    // delete current videos
+    while (!videos.isEmpty())
+        delete videos.takeFirst();
+    m_activeVideo = 0;
+    m_activeRow = -1;
+    skip = 1;
+    errorMessage.clear();
+    reset();
+
+    // (re)initialize the YouTubeSearch
+    if (youtubeSearch) delete youtubeSearch;
+    youtubeSearch = new YouTubeSearch();
+    connect(youtubeSearch, SIGNAL(gotVideo(Video*)), this, SLOT(addVideo(Video*)));
+    connect(youtubeSearch, SIGNAL(finished(int)), this, SLOT(searchFinished(int)));
+    connect(youtubeSearch, SIGNAL(error(QString)), this, SLOT(searchError(QString)));
+
+    this->searchParams = searchParams;
+    searching = true;
+    youtubeSearch->search(searchParams, MAX_ITEMS, skip);
+    skip += MAX_ITEMS;
+}
+
+void ListModel::searchMore(int max) {
+    if (searching) return;
+    searching = true;
+    errorMessage.clear();
+    youtubeSearch->search(searchParams, max, skip);
+    skip += max;
+}
+
+void ListModel::searchMore() {
+    searchMore(MAX_ITEMS);
+}
+
+void ListModel::searchNeeded() {
+    int remainingRows = videos.size() - m_activeRow;
+    int rowsNeeded = MAX_ITEMS - remainingRows;
+    if (rowsNeeded > 0)
+        searchMore(rowsNeeded);
+}
+
+void ListModel::abortSearch() {
+    while (!videos.isEmpty())
+        delete videos.takeFirst();
+    reset();
+    youtubeSearch->abort();
+    searching = false;
+}
+
+void ListModel::searchFinished(int total) {
+    searching = false;
+    canSearchMore = total > 0;
+
+    // update the message item
+    emit dataChanged( createIndex( MAX_ITEMS, 0 ), createIndex( MAX_ITEMS, columnCount() - 1 ) );
+
+    if (!youtubeSearch->getSuggestions().isEmpty()) {
+        emit haveSuggestions(youtubeSearch->getSuggestions());
+    }
+}
+
+void ListModel::searchError(QString message) {
+    errorMessage = message;
+    // update the message item
+    emit dataChanged( createIndex( MAX_ITEMS, 0 ), createIndex( MAX_ITEMS, columnCount() - 1 ) );
+}
+
+void ListModel::addVideo(Video* video) {
+    
+    connect(video, SIGNAL(gotThumbnail()), this, SLOT(updateThumbnail()));
+
+    beginInsertRows(QModelIndex(), videos.size(), videos.size());
+    videos << video;
+    endInsertRows();
+    
+    // first result!
+    if (videos.size() == 1) {
+
+        // manualplay
+        QSettings settings;
+        if (!settings.value("manualplay", false).toBool())
+            setActiveRow(0);
+
+        // save keyword
+        QString query = searchParams->keywords();
+        if (!query.isEmpty() && !searchParams->isTransient()) {
+            if (query.startsWith("http://")) {
+                // Save the video title
+                query += "|" + videos.first()->title();
+            }
+            QStringList keywords = settings.value(recentKeywordsKey).toStringList();
+            keywords.removeAll(query);
+            keywords.prepend(query);
+            while (keywords.size() > 10)
+                keywords.removeLast();
+            settings.setValue(recentKeywordsKey, keywords);
+        }
+
+        // save channel
+        QString channel = searchParams->author();
+        if (!channel.isEmpty() && !searchParams->isTransient()) {
+            QSettings settings;
+            QStringList channels = settings.value(recentChannelsKey).toStringList();
+            channels.removeAll(channel);
+            channels.prepend(channel);
+            while (channels.size() > 10)
+                channels.removeLast();
+            settings.setValue(recentChannelsKey, channels);
+        }
+
+    }
+
+}
+
+void ListModel::updateThumbnail() {
+
+    Video *video = static_cast<Video *>(sender());
+    if (!video) {
+        qDebug() << "Cannot get sender";
+        return;
+    }
+
+    int row = rowForVideo(video);
+    emit dataChanged( createIndex( row, 0 ), createIndex( row, columnCount() - 1 ) );
+
+}
+
+// --- item removal
+
+/**
+  * This function does not free memory
+  */
+bool ListModel::removeRows(int position, int rows, const QModelIndex & /*parent*/) {
+    beginRemoveRows(QModelIndex(), position, position+rows-1);
+    for (int row = 0; row < rows; ++row) {
+        videos.removeAt(position);
+    }
+    endRemoveRows();
+    return true;
+}
+
+void ListModel::removeIndexes(QModelIndexList &indexes) {
+    QList<Video*> originalList(videos);
+    QList<Video*> delitems;
+    foreach (QModelIndex index, indexes) {
+        if (index.row() >= originalList.size()) continue;
+        Video* video = originalList.at(index.row());
+        int idx = videos.indexOf(video);
+        if (idx != -1) {
+            beginRemoveRows(QModelIndex(), idx, idx);
+            delitems.append(video);
+            videos.removeAll(video);
+            endRemoveRows();
+        }
+    }
+
+    qDeleteAll(delitems);
+
+}
+
+// --- Sturm und drang ---
+
+
+
+Qt::DropActions ListModel::supportedDropActions() const {
+    return Qt::MoveAction;
+}
+
+Qt::ItemFlags ListModel::flags(const QModelIndex &index) const {
+    if (index.isValid())
+        if (index.row() == videos.size()) {
+            // don't drag the "show 10 more" item
+            return Qt::ItemIsEnabled;
+        } else return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
+    return Qt::ItemIsDropEnabled;
+}
+
+QStringList ListModel::mimeTypes() const {
+    QStringList types;
+    types << "application/x-minitube-video";
+    return types;
+}
+
+QMimeData* ListModel::mimeData( const QModelIndexList &indexes ) const {
+    VideoMimeData* mime = new VideoMimeData();
+
+    foreach( const QModelIndex &it, indexes ) {
+        int row = it.row();
+        if (row >= 0 && row < videos.size())
+            mime->addVideo( videos.at( it.row() ) );
+    }
+
+    return mime;
+}
+
+bool ListModel::dropMimeData(const QMimeData *data,
+                             Qt::DropAction action, int row, int column,
+                             const QModelIndex &parent) {
+    if (action == Qt::IgnoreAction)
+        return true;
+
+    if (!data->hasFormat("application/x-minitube-video"))
+        return false;
+
+    if (column > 0)
+        return false;
+
+    int beginRow;
+    if (row != -1)
+        beginRow = row;
+    else if (parent.isValid())
+        beginRow = parent.row();
+    else
+        beginRow = rowCount(QModelIndex());
+
+    const VideoMimeData* videoMimeData = dynamic_cast<const VideoMimeData*>( data );
+    if(!videoMimeData ) return false;
+
+    QList<Video*> droppedVideos = videoMimeData->videos();
+    foreach( Video *video, droppedVideos) {
+        
+        // remove videos
+        int videoRow = videos.indexOf(video);
+        removeRows(videoRow, 1, QModelIndex());
+        
+        // and then add them again at the new position
+        beginInsertRows(QModelIndex(), beginRow, beginRow);
+        videos.insert(beginRow, video);
+        endInsertRows();
+
+    }
+
+    // fix m_activeRow after all this
+    m_activeRow = videos.indexOf(m_activeVideo);
+
+    // let the MediaView restore the selection
+    emit needSelectionFor(droppedVideos);
+
+    return true;
+
+}
+
+int ListModel::rowForVideo(Video* video) {
+    return videos.indexOf(video);
+}
+
+QModelIndex ListModel::indexForVideo(Video* video) {
+    return createIndex(videos.indexOf(video), 0);
+}
+
+void ListModel::move(QModelIndexList &indexes, bool up) {
+    QList<Video*> movedVideos;
+
+    foreach (QModelIndex index, indexes) {
+        int row = index.row();
+        if (row >= videos.size()) continue;
+        // qDebug() << "index row" << row;
+        Video *video = videoAt(row);
+        movedVideos << video;
+    }
+
+    int end=up ? -1 : rowCount()-1, mod=up ? -1 : 1;
+    foreach (Video *video, movedVideos) {
+
+        int row = rowForVideo(video);
+        if (row+mod==end) { end=row; continue; }
+        // qDebug() << "video row" << row;
+        removeRows(row, 1, QModelIndex());
+
+        if (up) row--;
+        else row++;
+
+        beginInsertRows(QModelIndex(), row, row);
+        videos.insert(row, video);
+        endInsertRows();
+
+    }
+
+    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 ) );
+}
diff --git a/src/listmodel.h b/src/listmodel.h
new file mode 100644 (file)
index 0000000..f9d424b
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef LISTMODEL_H
+#define LISTMODEL_H
+
+#include "video.h"
+#include "youtubesearch.h"
+#include "searchparams.h"
+
+enum DataRoles {
+    ItemTypeRole = Qt::UserRole,
+    VideoRole,
+    ActiveTrackRole,
+    DownloadItemRole,
+    HoveredItemRole,
+    DownloadButtonHoveredRole,
+    DownloadButtonPressedRole,
+    AuthorHoveredRole,
+    AuthorPressedRole
+};
+
+enum ItemTypes {
+    ItemTypeVideo = 1,
+    ItemTypeShowMore
+};
+
+class ListModel : public QAbstractListModel {
+
+    Q_OBJECT
+
+public:
+
+    ListModel(QWidget *parent);
+    ~ListModel();
+
+    // inherited from QAbstractListModel
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    // int rowCount( const QModelIndex& parent = QModelIndex() ) const { Q_UNUSED( parent ); return videos.size(); }
+    int columnCount( const QModelIndex& parent = QModelIndex() ) const { Q_UNUSED( parent ); return 4; }
+    QVariant data(const QModelIndex &index, int role) const;
+    bool removeRows(int position, int rows, const QModelIndex &parent);
+
+    Qt::ItemFlags flags(const QModelIndex &index) const;
+    QStringList mimeTypes() const;
+    Qt::DropActions supportedDropActions() const;
+    QMimeData* mimeData( const QModelIndexList &indexes ) const;
+    bool dropMimeData(const QMimeData *data,
+                      Qt::DropAction action, int row, int column,
+                      const QModelIndex &parent);
+
+    // custom methods
+    void setActiveRow( int row );
+    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);
+    void move(QModelIndexList &indexes, bool up);
+
+    Video* videoAt( int row ) const;
+    Video* activeVideo() const;
+
+    // video search methods
+    void search(SearchParams *searchParams);
+    void abortSearch();
+
+
+public slots:
+    void searchMore();
+    void searchNeeded();
+    void addVideo(Video* video);
+    void searchFinished(int total);
+    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*>);
+    void haveSuggestions(const QStringList &suggestions);
+
+private:
+    void searchMore(int max);
+
+    YouTubeSearch *youtubeSearch;
+    SearchParams *searchParams;
+    bool searching;
+    bool canSearchMore;
+
+    QList<Video*> videos;
+    int skip;
+
+    // the row being played
+    int m_activeRow;
+    Video *m_activeVideo;
+
+    QString errorMessage;
+
+    int hoveredRow;
+    bool authorHovered;
+    bool authorPressed;
+};
+
+#endif
index fa6045726f78caac54f71880e598bf1fdab6a58a..02b4abe3ddc7fcaf13000880bf07eb73c0038541 100644 (file)
@@ -1,7 +1,7 @@
 #include <QtGui>
 #include <qtsingleapplication.h>
 #include "constants.h"
-#include "MainWindow.h"
+#include "mainwindow.h"
 #include "searchparams.h"
 #include "iconloader/qticonloader.h"
 #ifndef Q_WS_X11
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
new file mode 100644 (file)
index 0000000..c427d91
--- /dev/null
@@ -0,0 +1,1509 @@
+#include "mainwindow.h"
+#include "homeview.h"
+#include "searchview.h"
+#include "mediaview.h"
+#include "aboutview.h"
+#include "downloadview.h"
+#include "spacer.h"
+#include "constants.h"
+#include "iconloader/qticonloader.h"
+#include "global.h"
+#include "videodefinition.h"
+#include "fontutils.h"
+#include "globalshortcuts.h"
+#ifdef Q_WS_X11
+#include "gnomeglobalshortcutbackend.h"
+#endif
+#ifdef Q_WS_MAC
+#include "mac_startup.h"
+#include "macfullscreen.h"
+#include "macsupport.h"
+#include "macutils.h"
+#endif
+#include "downloadmanager.h"
+#include "youtubesuggest.h"
+#include "updatechecker.h"
+#include "temporary.h"
+#ifdef APP_MAC
+#include "searchlineedit_mac.h"
+#else
+#include "searchlineedit.h"
+#endif
+#include <iostream>
+#ifndef Q_WS_X11
+#include "extra.h"
+#include "updatedialog.h"
+#endif
+#ifdef APP_ACTIVATION
+#include "activation.h"
+#include "activationview.h"
+#include "activationdialog.h"
+#endif
+
+static MainWindow *singleton = 0;
+
+MainWindow* MainWindow::instance() {
+    if (!singleton) singleton = new MainWindow();
+    return singleton;
+}
+
+MainWindow::MainWindow() :
+        updateChecker(0),
+        aboutView(0),
+        downloadView(0),
+        mediaObject(0),
+        audioOutput(0),
+        m_fullscreen(false) {
+
+    singleton = this;
+
+    // views mechanism
+    history = new QStack<QWidget*>();
+    views = new QStackedWidget(this);
+
+    // views
+    homeView = new HomeView(this);
+    views->addWidget(homeView);
+
+    // TODO make this lazy
+    mediaView = new MediaView(this);
+    mediaView->setEnabled(false);
+    views->addWidget(mediaView);
+
+    // build ui
+    createActions();
+    createMenus();
+    createToolBars();
+    createStatusBar();
+
+    initPhonon();
+    mediaView->setSlider(seekSlider);
+    mediaView->setMediaObject(mediaObject);
+
+    // remove that useless menu/toolbar context menu
+    this->setContextMenuPolicy(Qt::NoContextMenu);
+
+    // mediaView init stuff thats needs actions
+    mediaView->initialize();
+
+    // event filter to block ugly toolbar tooltips
+    qApp->installEventFilter(this);
+
+    setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+
+    // restore window position
+    readSettings();
+
+    // fix stacked widget minimum size
+    for (int i = 0; i < views->count(); i++) {
+        QWidget* view = views->widget(i);
+        if (view) view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+    }
+    setMinimumWidth(0);
+
+    // show the initial view
+    showHome(false);
+
+#ifdef APP_ACTIVATION
+    if (!Activation::instance().isActivated())
+        showActivationView(false);
+#endif
+
+    setCentralWidget(views);
+
+    // Global shortcuts
+    GlobalShortcuts &shortcuts = GlobalShortcuts::instance();
+#ifdef Q_WS_X11
+    if (GnomeGlobalShortcutBackend::IsGsdAvailable())
+        shortcuts.setBackend(new GnomeGlobalShortcutBackend(&shortcuts));
+#endif
+#ifdef Q_WS_MAC
+    mac::MacSetup();
+#endif
+    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(&shortcuts, SIGNAL(StopAfter()), The::globalActions()->value("stopafterthis"), SLOT(toggle()));
+
+    connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
+            SLOT(updateDownloadMessage(QString)));
+    connect(DownloadManager::instance(), SIGNAL(finished()),
+            SLOT(downloadsFinished()));
+
+    setAcceptDrops(true);
+
+    mouseTimer = new QTimer(this);
+    mouseTimer->setInterval(5000);
+    mouseTimer->setSingleShot(true);
+    connect(mouseTimer, SIGNAL(timeout()), SLOT(hideMouse()));
+
+    QTimer::singleShot(0, this, SLOT(checkForUpdate()));
+
+}
+
+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) {
+
+    if (m_fullscreen && event->type() == QEvent::MouseMove) {
+
+        QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
+        const int x = mouseEvent->pos().x();
+        const QString className = QString(obj->metaObject()->className());
+        const bool isHoveringVideo = (className == "QGLWidget") || (className == "VideoAreaWidget");
+
+        // qDebug() << obj << mouseEvent->pos() << isHoveringVideo << mediaView->isPlaylistVisible();
+
+        if (mediaView->isPlaylistVisible()) {
+            if (isHoveringVideo && x > 5) mediaView->setPlaylistVisible(false);
+        } else {
+            if (isHoveringVideo && x >= 0 && x < 5) mediaView->setPlaylistVisible(true);
+        }
+
+#ifndef APP_MAC
+        const int y = mouseEvent->pos().y();
+        if (mainToolBar->isVisible()) {
+            if (isHoveringVideo && y > 5) mainToolBar->setVisible(false);
+        } else {
+            if (isHoveringVideo && y >= 0 && y < 5) mainToolBar->setVisible(true);
+        }
+#endif
+
+        // show the normal cursor
+        unsetCursor();
+        // then hide it again after a few seconds
+        mouseTimer->start();
+
+    }
+
+    if (event->type() == QEvent::ToolTip) {
+        // kill tooltips
+        return true;
+    }
+    // standard event processing
+    return QMainWindow::eventFilter(obj, event);
+}
+
+void MainWindow::createActions() {
+
+    QMap<QString, QAction*> *actions = The::globalActions();
+
+    stopAct = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop"), this);
+    stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
+    stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
+    stopAct->setEnabled(false);
+    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));
+    skipAct->setEnabled(false);
+    actions->insert("skip", skipAct);
+    connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
+
+    pauseAct = new QAction(QtIconLoader::icon("media-playback-pause"), tr("&Pause"), this);
+    pauseAct->setStatusTip(tr("Pause playback"));
+    pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
+    pauseAct->setEnabled(false);
+    actions->insert("pause", pauseAct);
+    connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
+
+    fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen"), tr("&Full Screen"), this);
+    fullscreenAct->setStatusTip(tr("Go full screen"));
+    QList<QKeySequence> fsShortcuts;
+#ifdef APP_MAC
+    fsShortcuts << QKeySequence(Qt::CTRL + Qt::META + Qt::Key_F);
+#else
+    fsShortcuts << QKeySequence(Qt::Key_F11) << QKeySequence(Qt::ALT + Qt::Key_Return);
+#endif
+    fullscreenAct->setShortcuts(fsShortcuts);
+    fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
+#if QT_VERSION >= 0x040600
+    fullscreenAct->setPriority(QAction::LowPriority);
+#endif
+    actions->insert("fullscreen", fullscreenAct);
+    connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
+
+    compactViewAct = new QAction(tr("&Compact Mode"), this);
+    compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
+#ifdef APP_MAC
+    compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::META + Qt::Key_C));
+#else
+    compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
+#endif
+    compactViewAct->setCheckable(true);
+    compactViewAct->setChecked(false);
+    compactViewAct->setEnabled(false);
+    actions->insert("compactView", compactViewAct);
+    connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
+
+    webPageAct = new QAction(tr("Open the &YouTube Page"), this);
+    webPageAct->setStatusTip(tr("Go to the YouTube video page and pause playback"));
+    webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
+    webPageAct->setEnabled(false);
+    actions->insert("webpage", webPageAct);
+    connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
+
+    copyPageAct = new QAction(tr("Copy the YouTube &Link"), this);
+    copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
+    copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
+    copyPageAct->setEnabled(false);
+    actions->insert("pagelink", copyPageAct);
+    connect(copyPageAct, SIGNAL(triggered()), mediaView, SLOT(copyWebPage()));
+
+    copyLinkAct = new QAction(tr("Copy the Video Stream &URL"), this);
+    copyLinkAct->setStatusTip(tr("Copy the current video stream URL to the clipboard"));
+    copyLinkAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
+    copyLinkAct->setEnabled(false);
+    actions->insert("videolink", copyLinkAct);
+    connect(copyLinkAct, SIGNAL(triggered()), mediaView, SLOT(copyVideoLink()));
+
+    findVideoPartsAct = new QAction(tr("Find Video &Parts"), this);
+    findVideoPartsAct->setStatusTip(tr("Find other video parts hopefully in the right order"));
+    findVideoPartsAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
+    findVideoPartsAct->setEnabled(false);
+    connect(findVideoPartsAct, SIGNAL(triggered()), mediaView, SLOT(findVideoParts()));
+    actions->insert("findVideoParts", findVideoPartsAct);
+
+    removeAct = new QAction(tr("&Remove"), this);
+    removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
+    removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
+    removeAct->setEnabled(false);
+    actions->insert("remove", removeAct);
+    connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
+
+    moveUpAct = new QAction(tr("Move &Up"), this);
+    moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
+    moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
+    moveUpAct->setEnabled(false);
+    actions->insert("moveUp", moveUpAct);
+    connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
+
+    moveDownAct = new QAction(tr("Move &Down"), this);
+    moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
+    moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
+    moveDownAct->setEnabled(false);
+    actions->insert("moveDown", moveDownAct);
+    connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
+
+    clearAct = new QAction(tr("&Clear Recent Searches"), this);
+    clearAct->setMenuRole(QAction::ApplicationSpecificRole);
+    clearAct->setShortcuts(QList<QKeySequence>()
+                           << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)
+                           << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
+    clearAct->setStatusTip(tr("Clear the search history. Cannot be undone."));
+    clearAct->setEnabled(true);
+    actions->insert("clearRecentKeywords", clearAct);
+    connect(clearAct, SIGNAL(triggered()), SLOT(clearRecentKeywords()));
+
+    quitAct = new QAction(tr("&Quit"), this);
+    quitAct->setMenuRole(QAction::QuitRole);
+    quitAct->setShortcut(QKeySequence(QKeySequence::Quit));
+    quitAct->setStatusTip(tr("Bye"));
+    actions->insert("quit", quitAct);
+    connect(quitAct, SIGNAL(triggered()), SLOT(quit()));
+
+    siteAct = new QAction(tr("&Website"), this);
+    siteAct->setShortcut(QKeySequence::HelpContents);
+    siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::NAME));
+    actions->insert("site", siteAct);
+    connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
+
+#if !defined(APP_MAC) && !defined(APP_WIN)
+    donateAct = new QAction(tr("Make a &Donation"), this);
+    donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::NAME));
+    actions->insert("donate", donateAct);
+    connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
+#endif
+
+    aboutAct = new QAction(tr("&About"), this);
+    aboutAct->setMenuRole(QAction::AboutRole);
+    aboutAct->setStatusTip(tr("Info about %1").arg(Constants::NAME));
+    actions->insert("about", aboutAct);
+    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
+
+    // Invisible actions
+
+    searchFocusAct = new QAction(this);
+    searchFocusAct->setShortcut(QKeySequence::Find);
+    searchFocusAct->setStatusTip(tr("Search"));
+    actions->insert("search", searchFocusAct);
+    connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
+    addAction(searchFocusAct);
+
+    volumeUpAct = new QAction(this);
+    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));
+    actions->insert("volume-down", volumeDownAct);
+    connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
+    addAction(volumeDownAct);
+
+    volumeMuteAct = new QAction(this);
+    volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
+    volumeMuteAct->setStatusTip(tr("Mute volume"));
+    volumeMuteAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_E));
+    actions->insert("volume-mute", volumeMuteAct);
+    connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
+    addAction(volumeMuteAct);
+
+    QAction *definitionAct = new QAction(this);
+    definitionAct->setIcon(QtIconLoader::icon("video-display"));
+    definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
+    /*
+    QMenu *definitionMenu = new QMenu(this);
+    foreach (QString definition, VideoDefinition::getDefinitionNames()) {
+        definitionMenu->addAction(definition);
+    }
+    definitionAct->setMenu(definitionMenu);
+    */
+    actions->insert("definition", definitionAct);
+    connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
+    addAction(definitionAct);
+
+    QAction *action;
+
+    action = new QAction(QtIconLoader::icon("media-playback-start"), tr("&Manually Start Playing"), this);
+    action->setStatusTip(tr("Manually start playing videos"));
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
+    action->setCheckable(true);
+    connect(action, SIGNAL(toggled(bool)), SLOT(setManualPlay(bool)));
+    actions->insert("manualplay", action);
+
+    action = new QAction(tr("&Downloads"), this);
+    action->setStatusTip(tr("Show details about video downloads"));
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
+    action->setCheckable(true);
+    action->setIcon(QtIconLoader::icon("go-down"));
+    action->setVisible(false);
+    connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
+    actions->insert("downloads", action);
+
+    action = new QAction(tr("&Download"), this);
+    action->setStatusTip(tr("Download the current video"));
+#ifndef APP_NO_DOWNLOADS
+    action->setShortcut(QKeySequence::Save);
+#endif
+    action->setIcon(QtIconLoader::icon("go-down"));
+    action->setEnabled(false);
+#if QT_VERSION >= 0x040600
+    action->setPriority(QAction::LowPriority);
+#endif
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(downloadVideo()));
+    actions->insert("download", action);
+
+    /*
+    action = new QAction(tr("&Snapshot"), this);
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S));
+    actions->insert("snapshot", action);
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(snapshot()));
+    */
+
+    QString shareTip = tr("Share the current video using %1");
+
+    action = new QAction("&Twitter", this);
+    action->setStatusTip(shareTip.arg("Twitter"));
+    actions->insert("twitter", action);
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaTwitter()));
+
+    action = new QAction("&Facebook", this);
+    action->setStatusTip(shareTip.arg("Facebook"));
+    actions->insert("facebook", action);
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaFacebook()));
+
+    action = new QAction("&Buffer", this);
+    action->setStatusTip(shareTip.arg("Buffer"));
+    actions->insert("buffer", action);
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaBuffer()));
+
+    action = new QAction(tr("&Email"), this);
+    action->setStatusTip(shareTip.arg(tr("Email")));
+    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(Constants::NAME, this);
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_1));
+    actions->insert("restore", action);
+    connect(action, SIGNAL(triggered()), SLOT(restore()));
+
+    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)));
+
+    action = new QAction(tr("&Report an Issue..."), this);
+    actions->insert("report-issue", action);
+    connect(action, SIGNAL(triggered()), SLOT(reportIssue()));
+
+    action = new QAction(tr("&Refine Search..."), this);
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
+    action->setCheckable(true);
+    actions->insert("refine-search", action);
+
+#ifdef APP_ACTIVATION
+    Extra::createActivationAction(tr("Buy %1...").arg(Constants::NAME));
+#endif
+
+    // common action properties
+    foreach (QAction *action, actions->values()) {
+
+        // add actions to the MainWindow so that they work
+        // when the menu is hidden
+        addAction(action);
+
+        // never autorepeat.
+        // unexperienced users tend to keep keys pressed for a "long" time
+        action->setAutoRepeat(false);
+
+        // set to something more meaningful then the toolbar text
+        if (!action->statusTip().isEmpty())
+            action->setToolTip(action->statusTip());
+
+        // show keyboard shortcuts in the status bar
+        if (!action->shortcut().isEmpty())
+            action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
+    }
+
+}
+
+void MainWindow::createMenus() {
+
+    QMap<QString, QMenu*> *menus = The::globalMenus();
+
+    fileMenu = menuBar()->addMenu(tr("&Application"));
+#ifdef APP_ACTIVATION
+    QAction *buyAction = The::globalActions()->value("buy");
+    if (buyAction) fileMenu->addAction(buyAction);
+#ifndef APP_MAC
+    fileMenu->addSeparator();
+#endif
+#endif
+    fileMenu->addAction(clearAct);
+#ifndef APP_MAC
+    fileMenu->addSeparator();
+#endif
+    fileMenu->addAction(quitAct);
+
+    QMenu* playbackMenu = menuBar()->addMenu(tr("&Playback"));
+    menus->insert("playback", playbackMenu);
+    playbackMenu->addAction(pauseAct);
+    playbackMenu->addAction(stopAct);
+    playbackMenu->addAction(The::globalActions()->value("stopafterthis"));
+    playbackMenu->addSeparator();
+    playbackMenu->addAction(skipAct);
+    playbackMenu->addAction(skipBackwardAct);
+    playbackMenu->addSeparator();
+    playbackMenu->addAction(The::globalActions()->value("manualplay"));
+#ifdef APP_MAC
+    MacSupport::dockMenu(playbackMenu);
+#endif
+
+    playlistMenu = menuBar()->addMenu(tr("&Playlist"));
+    menus->insert("playlist", playlistMenu);
+    playlistMenu->addAction(removeAct);
+    playlistMenu->addSeparator();
+    playlistMenu->addAction(moveUpAct);
+    playlistMenu->addAction(moveDownAct);
+    playlistMenu->addSeparator();
+    playlistMenu->addAction(The::globalActions()->value("refine-search"));
+
+    QMenu* videoMenu = menuBar()->addMenu(tr("&Video"));
+    menus->insert("video", videoMenu);
+    videoMenu->addAction(findVideoPartsAct);
+    videoMenu->addSeparator();
+    videoMenu->addAction(webPageAct);
+    videoMenu->addSeparator();
+#ifndef APP_NO_DOWNLOADS
+    videoMenu->addAction(The::globalActions()->value("download"));
+    // videoMenu->addAction(copyLinkAct);
+#endif
+    // videoMenu->addAction(The::globalActions()->value("snapshot"));
+
+    QMenu* viewMenu = menuBar()->addMenu(tr("&View"));
+    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);
+    shareMenu->addAction(copyPageAct);
+    shareMenu->addSeparator();
+    shareMenu->addAction(The::globalActions()->value("twitter"));
+    shareMenu->addAction(The::globalActions()->value("facebook"));
+    shareMenu->addAction(The::globalActions()->value("buffer"));
+    shareMenu->addSeparator();
+    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)
+    helpMenu->addAction(donateAct);
+#endif
+    helpMenu->addAction(The::globalActions()->value("report-issue"));
+    helpMenu->addAction(aboutAct);
+}
+
+void MainWindow::createToolBars() {
+
+    setUnifiedTitleAndToolBarOnMac(true);
+
+    mainToolBar = new QToolBar(this);
+#if QT_VERSION < 0x040600 | defined(APP_MAC)
+    mainToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
+#else
+    mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
+#endif
+    mainToolBar->setFloatable(false);
+    mainToolBar->setMovable(false);
+
+#if defined(APP_MAC) | defined(APP_WIN)
+    mainToolBar->setIconSize(QSize(32, 32));
+#endif
+
+    mainToolBar->addAction(stopAct);
+    mainToolBar->addAction(pauseAct);
+    mainToolBar->addAction(skipAct);
+
+    bool addFullScreenAct = true;
+#ifdef Q_WS_MAC
+    addFullScreenAct = !mac::CanGoFullScreen(winId());
+#endif
+    if (addFullScreenAct) mainToolBar->addAction(fullscreenAct);
+
+#ifndef APP_NO_DOWNLOADS
+    mainToolBar->addAction(The::globalActions()->value("download"));
+#endif
+
+    mainToolBar->addWidget(new Spacer());
+
+    QFont smallerFont = FontUtils::small();
+    currentTime = new QLabel(mainToolBar);
+    currentTime->setFont(smallerFont);
+    mainToolBar->addWidget(currentTime);
+
+    mainToolBar->addWidget(new Spacer());
+
+    seekSlider = new Phonon::SeekSlider(this);
+    seekSlider->setIconVisible(false);
+    seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+    mainToolBar->addWidget(seekSlider);
+
+/*
+    mainToolBar->addWidget(new Spacer());
+    slider = new QSlider(this);
+    slider->setOrientation(Qt::Horizontal);
+    slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+    mainToolBar->addWidget(slider);
+*/
+
+    mainToolBar->addWidget(new Spacer());
+
+    totalTime = new QLabel(mainToolBar);
+    totalTime->setFont(smallerFont);
+    mainToolBar->addWidget(totalTime);
+
+    mainToolBar->addWidget(new Spacer());
+
+    mainToolBar->addAction(volumeMuteAct);
+
+    volumeSlider = new Phonon::VolumeSlider(this);
+    volumeSlider->setMuteVisible(false);
+    // qDebug() << volumeSlider->children();
+    // status tip for the volume slider
+    QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
+    if (volumeQSlider)
+        volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
+                volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
+    // this makes the volume slider smaller
+    volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    mainToolBar->addWidget(volumeSlider);
+
+    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);
+    Spacer* spacer = new Spacer();
+    // spacer->setWidth(4);
+    mainToolBar->addWidget(spacer);
+#endif
+
+    addToolBar(mainToolBar);
+}
+
+void MainWindow::createStatusBar() {
+    QToolBar* toolBar = new QToolBar(this);
+    statusToolBar = toolBar;
+    toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+    toolBar->setIconSize(QSize(16, 16));
+    toolBar->addAction(The::globalActions()->value("downloads"));
+    toolBar->addAction(The::globalActions()->value("definition"));
+    statusBar()->addPermanentWidget(toolBar);
+    statusBar()->show();
+}
+
+void MainWindow::showStopAfterThisInStatusBar(bool show) {
+    QAction* action = The::globalActions()->value("stopafterthis");
+    showActionInStatusBar(action, show);
+}
+
+void MainWindow::showActionInStatusBar(QAction* action, bool show) {
+    if (show) {
+        statusToolBar->insertAction(statusToolBar->actions().first(), action);
+    } else {
+        statusToolBar->removeAction(action);
+    }
+}
+
+void MainWindow::readSettings() {
+    QSettings settings;
+    if (settings.contains("geometry")) {
+        restoreGeometry(settings.value("geometry").toByteArray());
+#ifdef APP_MAC
+    MacSupport::fixGeometry(this);
+#endif
+    } else {
+        setGeometry(100, 100, 1000, 500);
+    }
+    setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
+    audioOutput->setVolume(settings.value("volume", 1).toDouble());
+    audioOutput->setMuted(settings.value("volumeMute").toBool());
+    The::globalActions()->value("manualplay")->setChecked(settings.value("manualplay", false).toBool());
+}
+
+void MainWindow::writeSettings() {
+    QSettings settings;
+
+    settings.setValue("geometry", saveGeometry());
+    mediaView->saveSplitterState();
+
+    settings.setValue("volume", audioOutput->volume());
+    settings.setValue("volumeMute", audioOutput->isMuted());
+    settings.setValue("manualplay", The::globalActions()->value("manualplay")->isChecked());
+}
+
+void MainWindow::goBack() {
+    if ( history->size() > 1 ) {
+        history->pop();
+        QWidget *widget = history->pop();
+        showWidget(widget);
+    }
+}
+
+void MainWindow::showWidget(QWidget* widget, bool transition) {
+
+    if (compactViewAct->isChecked())
+        compactViewAct->toggle();
+
+    setUpdatesEnabled(false);
+
+    // call hide method on the current view
+    View* oldView = dynamic_cast<View *> (views->currentWidget());
+    if (oldView) {
+        oldView->disappear();
+        views->currentWidget()->setEnabled(false);
+    } else qDebug() << "Cannot cast view";
+
+    // call show method on the new view
+    View* newView = dynamic_cast<View *> (widget);
+    if (newView) {
+        widget->setEnabled(true);
+        newView->appear();
+        QHash<QString,QVariant> metadata = newView->metadata();
+        QString title = metadata.value("title").toString();
+        if (!title.isEmpty()) title += " - ";
+        setWindowTitle(title + Constants::NAME);
+        QString desc = metadata.value("description").toString();
+        if (!desc.isEmpty()) showMessage(desc);
+    }
+
+    const bool isMediaView = widget == mediaView;
+
+    stopAct->setEnabled(isMediaView);
+    compactViewAct->setEnabled(isMediaView);
+    webPageAct->setEnabled(isMediaView);
+    copyPageAct->setEnabled(isMediaView);
+    copyLinkAct->setEnabled(isMediaView);
+    findVideoPartsAct->setEnabled(isMediaView);
+    toolbarSearch->setEnabled(widget == homeView || isMediaView || widget == downloadView);
+
+    if (widget == homeView) {
+        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(isMediaView);
+    The::globalActions()->value("facebook")->setEnabled(isMediaView);
+    The::globalActions()->value("buffer")->setEnabled(isMediaView);
+    The::globalActions()->value("email")->setEnabled(isMediaView);
+
+    aboutAct->setEnabled(widget != aboutView);
+    The::globalActions()->value("downloads")->setChecked(widget == downloadView);
+
+    setUpdatesEnabled(true);
+
+    QWidget *oldWidget = views->currentWidget();
+    if (oldWidget)
+        oldWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+
+    views->setCurrentWidget(widget);
+    widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+#ifndef Q_WS_X11
+    if (transition) Extra::fadeInWidget(oldWidget, widget);
+#endif
+
+    history->push(widget);
+}
+
+void MainWindow::about() {
+    if (!aboutView) {
+        aboutView = new AboutView(this);
+        views->addWidget(aboutView);
+    }
+    showWidget(aboutView);
+}
+
+void MainWindow::visitSite() {
+    QUrl url(Constants::WEBSITE);
+    statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
+    QDesktopServices::openUrl(url);
+}
+
+void MainWindow::donate() {
+    QUrl url(QString(Constants::WEBSITE) + "#donate");
+    statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
+    QDesktopServices::openUrl(url);
+}
+
+void MainWindow::reportIssue() {
+    QUrl url("http://flavio.tordini.org/forums/forum/minitube-forums/minitube-troubleshooting");
+    QDesktopServices::openUrl(url);
+}
+
+void MainWindow::quit() {
+#ifdef APP_MAC
+    if (!confirmQuit()) {
+        return;
+    }
+#endif
+    // do not save geometry when in full screen or in compact mode
+    if (!m_fullscreen && !compactViewAct->isChecked()) {
+        writeSettings();
+    }
+    Temporary::deleteAll();
+    qApp->quit();
+}
+
+void MainWindow::closeEvent(QCloseEvent *event) {
+#ifdef APP_MAC
+    mac::closeWindow(winId());
+    event->ignore();
+#else
+    if (!confirmQuit()) {
+        event->ignore();
+        return;
+    }
+    QWidget::closeEvent(event);
+    quit();
+#endif
+}
+
+bool MainWindow::confirmQuit() {
+    if (DownloadManager::instance()->activeItems() > 0) {
+        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);
+
+        msgBox.exec();
+
+        if (msgBox.clickedButton() == waitButton) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void MainWindow::showHome(bool transition) {
+    showWidget(homeView, transition);
+    currentTime->clear();
+    totalTime->clear();
+}
+
+void MainWindow::showMedia(SearchParams *searchParams) {
+    mediaView->search(searchParams);
+    showWidget(mediaView);
+}
+
+void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
+
+    // qDebug() << "Phonon state: " << newState;
+
+    switch (newState) {
+
+    case Phonon::ErrorState:
+        if (mediaObject->errorType() == Phonon::FatalError) {
+            // Do not display because we try to play incomplete video files and sometimes trigger this
+            // We retry automatically (in MediaView) so no need to show it
+            // statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
+        } else {
+            statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
+        }
+        break;
+
+         case Phonon::PlayingState:
+        pauseAct->setEnabled(true);
+        pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
+        pauseAct->setText(tr("&Pause"));
+        pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
+        // stopAct->setEnabled(true);
+        break;
+
+         case Phonon::StoppedState:
+        pauseAct->setEnabled(false);
+        // stopAct->setEnabled(false);
+        break;
+
+         case Phonon::PausedState:
+        pauseAct->setEnabled(true);
+        pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
+        pauseAct->setText(tr("&Play"));
+        pauseAct->setStatusTip(tr("Resume playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
+        // stopAct->setEnabled(true);
+        break;
+
+         case Phonon::BufferingState:
+         case Phonon::LoadingState:
+        pauseAct->setEnabled(false);
+        currentTime->clear();
+        totalTime->clear();
+        // stopAct->setEnabled(true);
+        break;
+
+         default:
+        ;
+    }
+}
+
+void MainWindow::stop() {
+    mediaView->stop();
+    showHome();
+}
+
+void MainWindow::resizeEvent(QResizeEvent*) {
+#ifdef Q_WS_MAC
+    if (mac::CanGoFullScreen(winId())) {
+        bool isFullscreen = mac::IsFullScreen(winId());
+        if (isFullscreen != m_fullscreen) {
+            if (compactViewAct->isChecked()) {
+                compactViewAct->setChecked(false);
+                compactView(false);
+            }
+            m_fullscreen = isFullscreen;
+            updateUIForFullscreen();
+        }
+    }
+#endif
+}
+
+void MainWindow::fullscreen() {
+
+    if (compactViewAct->isChecked())
+        compactViewAct->toggle();
+
+#ifdef Q_WS_MAC
+    WId handle = winId();
+    if (mac::CanGoFullScreen(handle)) {
+        mainToolBar->setVisible(true);
+        mac::ToggleFullScreen(handle);
+        return;
+    }
+#endif
+
+    m_fullscreen = !m_fullscreen;
+
+    if (m_fullscreen) {
+        // Enter full screen
+
+        m_maximized = isMaximized();
+
+        // save geometry now, if the user quits when in full screen
+        // geometry won't be saved
+        writeSettings();
+
+#ifdef Q_WS_MAC
+        MacSupport::enterFullScreen(this, views);
+#else
+        mainToolBar->hide();
+        showFullScreen();
+#endif
+
+    } else {
+        // Exit full screen
+
+#ifdef Q_WS_MAC
+        MacSupport::exitFullScreen(this, views);
+#else
+        mainToolBar->show();
+        if (m_maximized) showMaximized();
+        else showNormal();
+#endif
+
+        // Make sure the window has focus
+        activateWindow();
+
+    }
+
+    updateUIForFullscreen();
+
+}
+
+void MainWindow::updateUIForFullscreen() {
+    static QList<QKeySequence> fsShortcuts;
+    static QString fsText;
+
+    if (m_fullscreen) {
+        fsShortcuts = fullscreenAct->shortcuts();
+        fsText = fullscreenAct->text();
+        fullscreenAct->setShortcuts(QList<QKeySequence>(fsShortcuts)
+                                    << QKeySequence(Qt::Key_Escape));
+        fullscreenAct->setText(tr("Leave &Full Screen"));
+    } else {
+        fullscreenAct->setShortcuts(fsShortcuts);
+        fullscreenAct->setText(fsText);
+    }
+
+    // No compact view action when in full screen
+    compactViewAct->setVisible(!m_fullscreen);
+    compactViewAct->setChecked(false);
+
+    // Hide anything but the video
+    mediaView->setPlaylistVisible(!m_fullscreen);
+    statusBar()->setVisible(!m_fullscreen);
+
+#ifndef APP_MAC
+    menuBar()->setVisible(!m_fullscreen);
+#endif
+
+    if (m_fullscreen) {
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
+    } else {
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
+    }
+
+#ifdef Q_WS_MAC
+    MacSupport::fullScreenActions(The::globalActions()->values(), m_fullscreen);
+#endif
+
+    if (views->currentWidget() == mediaView)
+        mediaView->setFocus();
+
+    if (m_fullscreen) {
+        hideMouse();
+    } else {
+        mouseTimer->stop();
+        unsetCursor();
+    }
+}
+
+void MainWindow::compactView(bool enable) {
+
+    static QList<QKeySequence> compactShortcuts;
+    static QList<QKeySequence> stopShortcuts;
+
+    const static QString key = "compactGeometry";
+    QSettings settings;
+
+#ifndef APP_MAC
+    menuBar()->setVisible(!enable);
+#endif
+
+    if (enable) {
+        setMinimumSize(160, 120);
+#ifdef Q_WS_MAC
+        mac::RemoveFullScreenWindow(winId());
+#endif
+        writeSettings();
+
+        if (settings.contains(key))
+            restoreGeometry(settings.value(key).toByteArray());
+        else
+            resize(320, 240);
+
+        mainToolBar->setVisible(!enable);
+        mediaView->setPlaylistVisible(!enable);
+        statusBar()->setVisible(!enable);
+
+        compactShortcuts = compactViewAct->shortcuts();
+        stopShortcuts = stopAct->shortcuts();
+
+        QList<QKeySequence> newStopShortcuts(stopShortcuts);
+        newStopShortcuts.removeAll(QKeySequence(Qt::Key_Escape));
+        stopAct->setShortcuts(newStopShortcuts);
+        compactViewAct->setShortcuts(QList<QKeySequence>(compactShortcuts) << QKeySequence(Qt::Key_Escape));
+
+        // ensure focus does not end up to the search box
+        // as it would steal the Space shortcut
+        mediaView->setFocus();
+
+    } else {
+        // unset minimum size
+        setMinimumSize(0, 0);
+#ifdef Q_WS_MAC
+        mac::SetupFullScreenWindow(winId());
+#endif
+        settings.setValue(key, saveGeometry());
+        mainToolBar->setVisible(!enable);
+        mediaView->setPlaylistVisible(!enable);
+        statusBar()->setVisible(!enable);
+        readSettings();
+
+        compactViewAct->setShortcuts(compactShortcuts);
+        stopAct->setShortcuts(stopShortcuts);
+    }
+
+    // auto float on top
+    floatOnTop(enable);
+}
+
+void MainWindow::searchFocus() {
+    toolbarSearch->selectAll();
+    toolbarSearch->setFocus();
+}
+
+void MainWindow::initPhonon() {
+    // Phonon initialization
+    if (mediaObject) delete mediaObject;
+    if (audioOutput) delete audioOutput;
+    mediaObject = new Phonon::MediaObject(this);
+    mediaObject->setTickInterval(100);
+    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
+            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
+    connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
+    connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
+    seekSlider->setMediaObject(mediaObject);
+    audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
+    connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
+    connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
+    volumeSlider->setAudioOutput(audioOutput);
+    Phonon::createPath(mediaObject, audioOutput);
+}
+
+void MainWindow::tick(qint64 time) {
+    if (time <= 0) {
+        // the "if" is important because tick is continually called
+        // and we don't want to paint the toolbar every 100ms
+        if (!currentTime->text().isEmpty()) currentTime->clear();
+        return;
+    }
+
+    currentTime->setText(formatTime(time));
+
+    // remaining time
+    const qint64 remainingTime = mediaObject->remainingTime();
+    currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
+
+    /*
+    slider->blockSignals(true);
+    slider->setValue(time/1000);
+    slider->blockSignals(false);
+    */
+}
+
+void MainWindow::totalTimeChanged(qint64 time) {
+    if (time <= 0) {
+        totalTime->clear();
+        return;
+    }
+    totalTime->setText(formatTime(time));
+
+    /*
+    slider->blockSignals(true);
+    slider->setMaximum(time/1000);
+    slider->blockSignals(false);
+    */
+
+}
+
+QString MainWindow::formatTime(qint64 time) {
+    QTime displayTime;
+    displayTime = displayTime.addMSecs(time);
+    QString timeString;
+    // 60 * 60 * 1000 = 3600000
+    if (time > 3600000)
+        timeString = displayTime.toString("h:mm:ss");
+    else
+        timeString = displayTime.toString("m:ss");
+    return timeString;
+}
+
+void MainWindow::volumeUp() {
+    qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
+    if (newVolume > volumeSlider->maximumVolume())
+        newVolume = volumeSlider->maximumVolume();
+    volumeSlider->audioOutput()->setVolume(newVolume);
+}
+
+void MainWindow::volumeDown() {
+    qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
+    if (newVolume < 0)
+        newVolume = 0;
+    volumeSlider->audioOutput()->setVolume(newVolume);
+}
+
+void MainWindow::volumeMute() {
+    volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
+}
+
+void MainWindow::volumeChanged(qreal newVolume) {
+    // automatically unmute when volume changes
+    if (volumeSlider->audioOutput()->isMuted())
+        volumeSlider->audioOutput()->setMuted(false);
+    statusBar()->showMessage(tr("Volume at %1%").arg((int)(newVolume*100)));
+}
+
+void MainWindow::volumeMutedChanged(bool muted) {
+    if (muted) {
+        volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
+        statusBar()->showMessage(tr("Volume is muted"));
+    } else {
+        volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
+        statusBar()->showMessage(tr("Volume is unmuted"));
+    }
+}
+
+void MainWindow::setDefinitionMode(QString definitionName) {
+    QAction *definitionAct = The::globalActions()->value("definition");
+    definitionAct->setText(definitionName);
+    definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
+                                + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
+    statusBar()->showMessage(definitionAct->statusTip());
+    QSettings settings;
+    settings.setValue("definition", definitionName);
+}
+
+void MainWindow::toggleDefinitionMode() {
+    QSettings settings;
+    QString currentDefinition = settings.value("definition").toString();
+    QStringList definitionNames = VideoDefinition::getDefinitionNames();
+    int currentIndex = definitionNames.indexOf(currentDefinition);
+    int nextIndex = 0;
+    if (currentIndex != definitionNames.size() - 1) {
+        nextIndex = currentIndex + 1;
+    }
+    QString nextDefinition = definitionNames.at(nextIndex);
+    setDefinitionMode(nextDefinition);
+}
+
+void MainWindow::showFullscreenToolbar(bool show) {
+    if (!m_fullscreen) return;
+    mainToolBar->setVisible(show);
+}
+
+void MainWindow::showFullscreenPlaylist(bool show) {
+    if (!m_fullscreen) return;
+    mediaView->setPlaylistVisible(show);
+}
+
+void MainWindow::clearRecentKeywords() {
+    QSettings settings;
+    settings.remove("recentKeywords");
+    settings.remove("recentChannels");
+    if (views->currentWidget() == homeView) {
+        SearchView *searchView = homeView->getSearchView();
+        searchView->updateRecentKeywords();
+        searchView->updateRecentChannels();
+    }
+    showMessage(tr("Your privacy is now safe"));
+}
+
+void MainWindow::setManualPlay(bool enabled) {
+    QSettings settings;
+    settings.setValue("manualplay", QVariant::fromValue(enabled));
+    showActionInStatusBar(The::globalActions()->value("manualplay"), enabled);
+}
+
+void MainWindow::updateDownloadMessage(QString message) {
+    The::globalActions()->value("downloads")->setText(message);
+}
+
+void MainWindow::downloadsFinished() {
+    The::globalActions()->value("downloads")->setText(tr("&Downloads"));
+    statusBar()->showMessage(tr("Downloads complete"));
+}
+
+void MainWindow::toggleDownloads(bool show) {
+
+    if (show) {
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
+        The::globalActions()->value("downloads")->setShortcuts(
+                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
+                << QKeySequence(Qt::Key_Escape));
+    } else {
+        The::globalActions()->value("downloads")->setShortcuts(
+                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
+    }
+
+    if (!downloadView) {
+        downloadView = new DownloadView(this);
+        views->addWidget(downloadView);
+    }
+    if (show) showWidget(downloadView);
+    else goBack();
+}
+
+void MainWindow::startToolbarSearch(QString query) {
+    query = query.trimmed();
+
+    // check for empty query
+    if (query.length() == 0) {
+        return;
+    }
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setKeywords(query);
+
+    // go!
+    showMedia(searchParams);
+}
+
+void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
+    if (event->mimeData()->hasFormat("text/uri-list")) {
+        QList<QUrl> urls = event->mimeData()->urls();
+        if (urls.isEmpty())
+            return;
+        QUrl url = urls.first();
+        QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
+        if (!videoId.isNull())
+            event->acceptProposedAction();
+    }
+}
+
+void MainWindow::dropEvent(QDropEvent *event) {
+    QList<QUrl> urls = event->mimeData()->urls();
+    if (urls.isEmpty())
+        return;
+    QUrl url = urls.first();
+    QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
+    if (!videoId.isNull()) {
+        setWindowTitle(url.toString());
+        SearchParams *searchParams = new SearchParams();
+        searchParams->setKeywords(videoId);
+        showMedia(searchParams);
+    }
+}
+
+void MainWindow::checkForUpdate() {
+    static const QString updateCheckKey = "updateCheck";
+
+    // check every 24h
+    QSettings settings;
+    uint unixTime = QDateTime::currentDateTime().toTime_t();
+    int lastCheck = settings.value(updateCheckKey).toInt();
+    int secondsSinceLastCheck = unixTime - lastCheck;
+    // qDebug() << "secondsSinceLastCheck" << unixTime << lastCheck << secondsSinceLastCheck;
+    if (secondsSinceLastCheck < 86400) return;
+
+    // check it out
+    if (updateChecker) delete updateChecker;
+    updateChecker = new UpdateChecker();
+    connect(updateChecker, SIGNAL(newVersion(QString)),
+            this, SLOT(gotNewVersion(QString)));
+    updateChecker->checkForUpdate();
+    settings.setValue(updateCheckKey, unixTime);
+}
+
+void MainWindow::gotNewVersion(QString version) {
+    if (updateChecker) {
+        delete updateChecker;
+        updateChecker = 0;
+    }
+
+    QSettings settings;
+    QString checkedVersion = settings.value("checkedVersion").toString();
+    if (checkedVersion == version) return;
+
+#ifdef APP_SIMPLEUPDATE
+    simpleUpdateDialog(version);
+#endif
+#if defined(APP_ACTIVATION) && !defined(APP_MAC)
+    UpdateDialog *dialog = new UpdateDialog(version, this);
+    dialog->show();
+#endif
+}
+
+void MainWindow::simpleUpdateDialog(QString version) {
+    QMessageBox msgBox(this);
+    msgBox.setIconPixmap(
+                QPixmap(":/images/app.png")
+                .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+    msgBox.setText(tr("%1 version %2 is now available.").arg(Constants::NAME, version));
+    msgBox.setModal(true);
+    msgBox.setWindowModality(Qt::WindowModal);
+    msgBox.addButton(QMessageBox::Close);
+    QPushButton* laterButton = msgBox.addButton(tr("Remind me later"), QMessageBox::RejectRole);
+    QPushButton* updateButton = msgBox.addButton(tr("Update"), QMessageBox::AcceptRole);
+    msgBox.exec();
+    if (msgBox.clickedButton() != laterButton) {
+        QSettings settings;
+        settings.setValue("checkedVersion", version);
+    }
+    if (msgBox.clickedButton() == updateButton) visitSite();
+}
+
+void MainWindow::floatOnTop(bool onTop) {
+    showActionInStatusBar(The::globalActions()->value("ontop"), onTop);
+#ifdef APP_MAC
+    mac::floatOnTop(winId(), onTop);
+    return;
+#endif
+    if (onTop) {
+        setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
+        show();
+    } else {
+        setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
+        show();
+    }
+}
+
+void MainWindow::restore() {
+#ifdef APP_MAC
+    mac::uncloseWindow(window()->winId());
+#endif
+}
+
+void MainWindow::messageReceived(const QString &message) {
+    if (message == "--toggle-playing") {
+        if (pauseAct->isEnabled()) pauseAct->trigger();
+    } else if (message == "--next") {
+        if (skipAct->isEnabled()) skipAct->trigger();
+    } else if (message == "--previous") {
+        if (skipBackwardAct->isEnabled()) skipBackwardAct->trigger();
+    }  else if (message.startsWith("--")) {
+        MainWindow::printHelp();
+    } else if (!message.isEmpty()) {
+        SearchParams *searchParams = new SearchParams();
+        searchParams->setKeywords(message);
+        showMedia(searchParams);
+    }
+}
+
+void MainWindow::hideMouse() {
+    setCursor(Qt::BlankCursor);
+    mediaView->setPlaylistVisible(false);
+#ifndef APP_MAC
+    mainToolBar->setVisible(false);
+#endif
+}
+
+void MainWindow::printHelp() {
+    QString msg = QString("%1 %2\n\n").arg(Constants::NAME, Constants::VERSION);
+    msg += "Usage: minitube [options]\n";
+    msg += "Options:\n";
+    msg += "  --toggle-playing\t";
+    msg += "Start or pause playback.\n";
+    msg += "  --next\t\t";
+    msg += "Skip to the next video.\n";
+    msg += "  --previous\t\t";
+    msg += "Go back to the previous video.\n";
+    std::cout << msg.toLocal8Bit().data();
+}
+
+void MainWindow::showMessage(QString message) {
+    statusBar()->showMessage(message, 60000);
+}
+
+#ifdef APP_ACTIVATION
+void MainWindow::showActivationView(bool transition) {
+    QWidget *activationView = ActivationView::instance();
+    if (views->currentWidget() == activationView) {
+        buy();
+        return;
+    }
+    views->addWidget(activationView);
+    showWidget(activationView, transition);
+}
+
+void MainWindow::showActivationDialog() {
+    QTimer::singleShot(0, new ActivationDialog(this), SLOT(show()));
+}
+
+void MainWindow::buy() {
+    Extra::buy();
+}
+
+void MainWindow::hideBuyAction() {
+    QAction *action = The::globalActions()->value("buy");
+    action->setVisible(false);
+    action->setEnabled(false);
+}
+#endif
diff --git a/src/mainwindow.h b/src/mainwindow.h
new file mode 100644 (file)
index 0000000..cdb66f5
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QtGui>
+#include <phonon/audiooutput.h>
+#include <phonon/volumeslider.h>
+#include <phonon/mediaobject.h>
+#include <phonon/seekslider.h>
+#include "view.h"
+
+class HomeView;
+class MediaView;
+class DownloadView;
+class SearchLineEdit;
+class UpdateChecker;
+class SearchParams;
+
+class MainWindow : public QMainWindow {
+
+    Q_OBJECT
+
+public:
+    static MainWindow* instance();
+    MainWindow();
+    ~MainWindow();
+    Phonon::SeekSlider* getSeekSlider() { return seekSlider; }
+    void readSettings();
+    void writeSettings();
+    static void printHelp();
+
+public slots:
+    void showHome(bool transition = true);
+    void showMedia(SearchParams *params);
+    void restore();
+    void messageReceived(const QString &message);
+    void quit();
+    void startToolbarSearch(QString query);
+    void goBack();
+    void showMessage(QString message);
+#ifdef APP_ACTIVATION
+    void showActivationView(bool transition = true);
+    void showActivationDialog();
+    void buy();
+    void hideBuyAction();
+#endif
+
+protected:
+    void changeEvent(QEvent *);
+    void closeEvent(QCloseEvent *);
+    bool eventFilter(QObject *obj, QEvent *event);
+    void dragEnterEvent(QDragEnterEvent *event);
+    void dropEvent(QDropEvent *event);
+    void resizeEvent(QResizeEvent *);
+
+private slots:
+    void checkForUpdate();
+    void gotNewVersion(QString version);
+    void visitSite();
+    void donate();
+    void reportIssue();
+    void about();
+    void fullscreen();
+    void updateUIForFullscreen();
+    void compactView(bool enable);
+    void stop();
+    void stateChanged(Phonon::State newState, Phonon::State oldState);
+    void searchFocus();
+    void tick(qint64 time);
+    void totalTimeChanged(qint64 time);
+    void setDefinitionMode(QString definitionName);
+    void toggleDefinitionMode();
+    void clearRecentKeywords();
+
+    // volume shortcuts
+    void volumeUp();
+    void volumeDown();
+    void volumeMute();
+    void volumeChanged(qreal newVolume);
+    void volumeMutedChanged(bool muted);
+
+    // fullscreen toolbar
+    void showFullscreenToolbar(bool show);
+    void showFullscreenPlaylist(bool show);
+
+    void setManualPlay(bool enabled);
+    void updateDownloadMessage(QString);
+    void downloadsFinished();
+    void toggleDownloads(bool show);
+
+    void floatOnTop(bool);
+    void showActionInStatusBar(QAction*, bool show);
+    void showStopAfterThisInStatusBar(bool show);
+
+    void hideMouse();
+
+private:
+    void initPhonon();
+    void createActions();
+    void createMenus();
+    void createToolBars();
+    void createStatusBar();
+    void showWidget(QWidget*, bool transition = true);
+    static QString formatTime(qint64 time);
+    bool confirmQuit();
+    void simpleUpdateDialog(QString version);
+
+    UpdateChecker *updateChecker;
+
+    // view mechanism
+    QStackedWidget *views;
+    QStack<QWidget*> *history;
+
+    // view widgets
+    HomeView *homeView;
+    MediaView *mediaView;
+    QWidget *aboutView;
+    QWidget *downloadView;
+
+    // actions
+    QAction *addGadgetAct;
+    QAction *backAct;
+    QAction *quitAct;
+    QAction *siteAct;
+    QAction *donateAct;
+    QAction *aboutAct;
+    QAction *searchFocusAct;
+
+    // media actions
+    QAction *skipBackwardAct;
+    QAction *skipAct;
+    QAction *pauseAct;
+    QAction *stopAct;
+    QAction *fullscreenAct;
+    QAction *compactViewAct;
+    QAction *webPageAct;
+    QAction *copyPageAct;
+    QAction *copyLinkAct;
+    QAction *volumeUpAct;
+    QAction *volumeDownAct;
+    QAction *volumeMuteAct;
+    QAction *findVideoPartsAct;
+
+    // playlist actions
+    QAction *removeAct;
+    QAction *moveDownAct;
+    QAction *moveUpAct;
+    QAction *fetchMoreAct;
+    QAction *clearAct;
+
+    // menus
+    QMenu *fileMenu;
+    QMenu *viewMenu;
+    QMenu *playlistMenu;
+    QMenu *helpMenu;
+
+    // toolbar
+    QToolBar *mainToolBar;
+    SearchLineEdit *toolbarSearch;
+    QToolBar *statusToolBar;
+
+    // phonon
+    Phonon::SeekSlider *seekSlider;
+    Phonon::VolumeSlider *volumeSlider;
+    Phonon::MediaObject *mediaObject;
+    Phonon::AudioOutput *audioOutput;
+    QLabel *currentTime;
+    QLabel *totalTime;
+
+    bool m_fullscreen;
+    bool m_maximized;
+
+    QTimer *mouseTimer;
+
+};
+
+#endif
diff --git a/src/mediaview.cpp b/src/mediaview.cpp
new file mode 100644 (file)
index 0000000..32540b3
--- /dev/null
@@ -0,0 +1,882 @@
+#include "mediaview.h"
+#include "playlistview.h"
+#include "playlistitemdelegate.h"
+#include "networkaccess.h"
+#include "videowidget.h"
+#include "minisplitter.h"
+#include "constants.h"
+#include "downloadmanager.h"
+#include "downloaditem.h"
+#include "mainwindow.h"
+#include "temporary.h"
+#include "sidebarwidget.h"
+#include "playlistwidget.h"
+#include "refinesearchwidget.h"
+#include "sidebarwidget.h"
+#ifdef APP_MAC
+#include "macfullscreen.h"
+#endif
+#ifdef APP_ACTIVATION
+#include "activation.h"
+#endif
+
+namespace The {
+NetworkAccess* http();
+}
+
+namespace The {
+QMap<QString, QAction*>* globalActions();
+QMap<QString, QMenu*>* globalMenus();
+QNetworkAccessManager* networkAccessManager();
+}
+
+MediaView::MediaView(QWidget *parent) : QWidget(parent) {
+
+    reallyStopped = false;
+    downloadItem = 0;
+
+    QBoxLayout *layout = new QVBoxLayout();
+    layout->setMargin(0);
+
+    splitter = new MiniSplitter(this);
+    splitter->setChildrenCollapsible(false);
+
+    listView = new PlaylistView(this);
+    listView->setItemDelegate(new PlaylistItemDelegate(this));
+    listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+    // dragndrop
+    listView->setDragEnabled(true);
+    listView->setAcceptDrops(true);
+    listView->setDropIndicatorShown(true);
+    listView->setDragDropMode(QAbstractItemView::DragDrop);
+
+    // cosmetics
+    listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+    listView->setFrameShape( QFrame::NoFrame );
+    listView->setAttribute(Qt::WA_MacShowFocusRect, false);
+    listView->setMinimumSize(320,240);
+    listView->setUniformItemSizes(true);
+
+    // respond to the user doubleclicking a playlist item
+    connect(listView, SIGNAL(activated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &)));
+
+    listModel = new ListModel(this);
+    connect(listModel, SIGNAL(activeRowChanged(int)), this, SLOT(activeRowChanged(int)));
+    // needed to restore the selection after dragndrop
+    connect(listModel, SIGNAL(needSelectionFor(QList<Video*>)), this, SLOT(selectVideos(QList<Video*>)));
+    listView->setModel(listModel);
+
+    connect(listView->selectionModel(),
+            SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )),
+            this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & )));
+
+    connect(listView, SIGNAL(authorPushed(QModelIndex)), SLOT(authorPushed(QModelIndex)));
+
+    sidebar = new SidebarWidget(this);
+    sidebar->setPlaylist(listView);
+    connect(sidebar->getRefineSearchWidget(), SIGNAL(searchRefined()),
+            SLOT(searchAgain()));
+    connect(listModel, SIGNAL(haveSuggestions(const QStringList &)),
+            sidebar, SLOT(showSuggestions(const QStringList &)));
+    connect(sidebar, SIGNAL(suggestionAccepted(QString)),
+            MainWindow::instance(), SLOT(startToolbarSearch(QString)));
+    splitter->addWidget(sidebar);
+
+    videoAreaWidget = new VideoAreaWidget(this);
+    videoAreaWidget->setMinimumSize(320,240);
+    videoWidget = new Phonon::VideoWidget(this);
+    videoAreaWidget->setVideoWidget(videoWidget);
+    videoAreaWidget->setListModel(listModel);
+
+    loadingWidget = new LoadingWidget(this);
+    videoAreaWidget->setLoadingWidget(loadingWidget);
+
+    splitter->addWidget(videoAreaWidget);
+
+    layout->addWidget(splitter);
+    setLayout(layout);
+
+    splitter->setStretchFactor(0, 1);
+    splitter->setStretchFactor(1, 6);
+
+    // restore splitter state
+    QSettings settings;
+    splitter->restoreState(settings.value("splitter").toByteArray());
+
+    errorTimer = new QTimer(this);
+    errorTimer->setSingleShot(true);
+    errorTimer->setInterval(3000);
+    connect(errorTimer, SIGNAL(timeout()), SLOT(skipVideo()));
+
+    workaroundTimer = new QTimer(this);
+    workaroundTimer->setSingleShot(true);
+    workaroundTimer->setInterval(3000);
+    connect(workaroundTimer, SIGNAL(timeout()), SLOT(timerPlay()));
+
+#ifdef APP_ACTIVATION
+    demoTimer = new QTimer(this);
+    demoTimer->setSingleShot(true);
+    connect(demoTimer, SIGNAL(timeout()), SLOT(demoMessage()));
+#endif
+
+}
+
+void MediaView::initialize() {
+    connect(videoAreaWidget, SIGNAL(doubleClicked()), The::globalActions()->value("fullscreen"), SLOT(trigger()));
+
+    /*
+    videoAreaWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(videoAreaWidget, SIGNAL(customContextMenuRequested(QPoint)),
+            this, SLOT(showVideoContextMenu(QPoint)));
+            */
+
+    QAction* refineSearchAction = The::globalActions()->value("refine-search");
+    connect(refineSearchAction, SIGNAL(toggled(bool)),
+            sidebar, SLOT(toggleRefineSearch(bool)));
+}
+
+void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
+    this->mediaObject = mediaObject;
+    Phonon::createPath(this->mediaObject, videoWidget);
+    connect(mediaObject, SIGNAL(finished()), this, SLOT(playbackFinished()));
+    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
+            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
+    connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
+            this, SLOT(currentSourceChanged(Phonon::MediaSource)));
+    // connect(mediaObject, SIGNAL(bufferStatus(int)), loadingWidget, SLOT(bufferStatus(int)));
+    connect(mediaObject, SIGNAL(aboutToFinish()), SLOT(aboutToFinish()));
+}
+
+void MediaView::search(SearchParams *searchParams) {
+    reallyStopped = false;
+
+#ifdef APP_ACTIVATION
+    demoTimer->stop();
+#endif
+    workaroundTimer->stop();
+    errorTimer->stop();
+
+    this->searchParams = searchParams;
+
+    // start serching for videos
+    listModel->search(searchParams);
+
+    sidebar->showPlaylist();
+    listView->setFocus();
+
+    QString keyword = searchParams->keywords();
+    QString display = keyword;
+    if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
+        int separator = keyword.indexOf("|");
+        if (separator > 0 && separator + 1 < keyword.length()) {
+            display = keyword.mid(separator+1);
+        }
+    }
+
+    sidebar->getRefineSearchWidget()->setSearchParams(searchParams);
+    sidebar->hideSuggestions();
+
+}
+
+void MediaView::searchAgain() {
+    search(searchParams);
+}
+
+void MediaView::appear() {
+    listView->setFocus();
+}
+
+void MediaView::disappear() {
+    timerPlayFlag = true;
+}
+
+void MediaView::handleError(QString /* message */) {
+
+    QTimer::singleShot(500, this, SLOT(startPlaying()));
+
+    /*
+    videoAreaWidget->showError(message);
+    skippedVideo = listModel->activeVideo();
+    // recover from errors by skipping to the next video
+    errorTimer->start(2000);
+    */
+}
+
+void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/) {
+    // qDebug() << "Phonon state: " << newState;
+    // slider->setEnabled(newState == Phonon::PlayingState);
+
+    switch (newState) {
+
+    case Phonon::ErrorState:
+        qDebug() << "Phonon error:" << mediaObject->errorString() << mediaObject->errorType();
+        if (mediaObject->errorType() == Phonon::FatalError)
+            handleError(mediaObject->errorString());
+        break;
+
+    case Phonon::PlayingState:
+        // qDebug("playing");
+        videoAreaWidget->showVideo();
+        break;
+
+    case Phonon::StoppedState:
+        // qDebug("stopped");
+        // play() has already been called when setting the source
+        // but Phonon on Linux needs a little more help to start playback
+        // if (!reallyStopped) mediaObject->play();
+
+#ifdef APP_MAC
+        // Workaround for Mac playback start problem
+        if (!timerPlayFlag) {
+            // workaroundTimer->start();
+        }
+#endif
+
+        break;
+
+    case Phonon::PausedState:
+        qDebug("paused");
+        break;
+
+    case Phonon::BufferingState:
+        qDebug("buffering");
+        break;
+
+    case Phonon::LoadingState:
+        qDebug("loading");
+        break;
+
+    }
+}
+
+void MediaView::pause() {
+    // qDebug() << "pause() called" << mediaObject->state();
+
+    switch( mediaObject->state() ) {
+    case Phonon::PlayingState:
+        mediaObject->pause();
+        break;
+    default:
+        mediaObject->play();
+        break;
+    }
+
+}
+
+QRegExp MediaView::wordRE(QString s) {
+    return QRegExp("\\W" + s + "\\W?", Qt::CaseInsensitive);
+}
+
+void MediaView::stop() {
+    listModel->abortSearch();
+    reallyStopped = true;
+    mediaObject->stop();
+    videoAreaWidget->clear();
+    workaroundTimer->stop();
+    errorTimer->stop();
+    listView->selectionModel()->clearSelection();
+    if (downloadItem) {
+        downloadItem->stop();
+        delete downloadItem;
+        downloadItem = 0;
+    }
+    The::globalActions()->value("refine-search")->setChecked(false);
+}
+
+void MediaView::activeRowChanged(int row) {
+    if (reallyStopped) return;
+
+    Video *video = listModel->videoAt(row);
+    if (!video) return;
+
+    // now that we have a new video to play
+    // stop all the timers
+    workaroundTimer->stop();
+    errorTimer->stop();
+
+    mediaObject->stop();
+    if (downloadItem) {
+        downloadItem->stop();
+        delete downloadItem;
+        downloadItem = 0;
+    }
+    // slider->setMinimum(0);
+
+    // immediately show the loading widget
+    videoAreaWidget->showLoading(video);
+
+    connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl)), Qt::UniqueConnection);
+    // TODO handle signal in a proper slot and impl item error status
+    connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)), Qt::UniqueConnection);
+
+    video->loadStreamUrl();
+
+    // reset the timer flag
+    timerPlayFlag = false;
+
+    // video title in the statusbar
+    MainWindow::instance()->showMessage(video->title());
+
+    // ensure active item is visible
+    // int row = listModel->activeRow();
+    if (row != -1) {
+        QModelIndex index = listModel->index(row, 0, QModelIndex());
+        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...
+
+}
+
+void MediaView::gotStreamUrl(QUrl streamUrl) {
+    if (reallyStopped) return;
+
+    Video *video = static_cast<Video *>(sender());
+    if (!video) {
+        qDebug() << "Cannot get sender";
+        return;
+    }
+    video->disconnect(this);
+
+    QString tempFile = Temporary::filename();
+
+    Video *videoCopy = video->clone();
+    if (downloadItem) {
+        downloadItem->stop();
+        delete downloadItem;
+    }
+    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
+    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()), Qt::UniqueConnection);
+    // connect(downloadItem, SIGNAL(progress(int)), SLOT(downloadProgress(int)));
+    connect(downloadItem, SIGNAL(bufferProgress(int)), loadingWidget, SLOT(bufferStatus(int)), Qt::UniqueConnection);
+    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
+    connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)), Qt::UniqueConnection);
+    connect(downloadItem, SIGNAL(error(QString)), SLOT(handleError(QString)), Qt::UniqueConnection);
+    downloadItem->start();
+
+}
+
+/*
+void MediaView::downloadProgress(int percent) {
+    MainWindow* mainWindow = dynamic_cast<MainWindow*>(window());
+
+    mainWindow->getSeekSlider()->setStyleSheet(" QSlider::groove:horizontal {"
+        "border: 1px solid #999999;"
+        // "border-left: 50px solid rgba(255, 0, 0, 128);"
+        "height: 8px;"
+        "background: qlineargradient(x1:0, y1:0, x2:.5, y2:0, stop:0 rgba(255, 0, 0, 92), stop:"
+        + QString::number(percent/100.0) +
+
+        " rgba(255, 0, 0, 92), stop:" + QString::number((percent+1)/100.0) + " transparent, stop:1 transparent);"
+        "margin: 2px 0;"
+    "}"
+    "QSlider::handle:horizontal {"
+        "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);"
+        "border: 1px solid #5c5c5c;"
+        "width: 16px;"
+        "height: 16px;"
+        "margin: -2px 0;"
+        "border-radius: 8px;"
+    "}"
+
+    );
+}
+
+*/
+
+void MediaView::downloadStatusChanged() {
+    switch(downloadItem->status()) {
+    case Downloading:
+        startPlaying();
+        break;
+    case Starting:
+        // qDebug() << "Starting";
+        break;
+    case Finished:
+        // qDebug() << "Finished" << mediaObject->state();
+        // if (mediaObject->state() == Phonon::StoppedState) startPlaying();
+#ifdef Q_WS_X11
+        seekSlider->setEnabled(mediaObject->isSeekable());
+#endif
+        break;
+    case Failed:
+        // qDebug() << "Failed";
+    case Idle:
+        // qDebug() << "Idle";
+        break;
+    }
+}
+
+void MediaView::startPlaying() {
+    if (reallyStopped) return;
+    if (!downloadItem) {
+        skip();
+        return;
+    }
+
+    // go!
+    QString source = downloadItem->currentFilename();
+    qDebug() << "Playing" << source;
+    mediaObject->setCurrentSource(source);
+    mediaObject->play();
+#ifdef Q_WS_X11
+    seekSlider->setEnabled(false);
+#endif
+
+    // ensure we always have 10 videos ahead
+    listModel->searchNeeded();
+
+    // ensure active item is visible
+    int row = listModel->activeRow();
+    if (row != -1) {
+        QModelIndex index = listModel->index(row, 0, QModelIndex());
+        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
+    }
+
+#ifdef APP_ACTIVATION
+    if (!Activation::instance().isActivated())
+        demoTimer->start(180000);
+#endif
+
+}
+
+void MediaView::itemActivated(const QModelIndex &index) {
+    if (listModel->rowExists(index.row())) {
+
+        // if it's the current video, just rewind and play
+        Video *activeVideo = listModel->activeVideo();
+        Video *video = listModel->videoAt(index.row());
+        if (activeVideo && video && activeVideo == video) {
+            mediaObject->seek(0);
+            mediaObject->play();
+        } else listModel->setActiveRow(index.row());
+
+    // the user doubleclicked on the "Search More" item
+    } else {
+        listModel->searchMore();
+        listView->selectionModel()->clearSelection();
+    }
+}
+
+void MediaView::currentSourceChanged(const Phonon::MediaSource /* source */ ) {
+
+}
+
+void MediaView::skipVideo() {
+    // skippedVideo is useful for DELAYED skip operations
+    // in order to be sure that we're skipping the video we wanted
+    // and not another one
+    if (skippedVideo) {
+        if (listModel->activeVideo() != skippedVideo) {
+            qDebug() << "Skip of video canceled";
+            return;
+        }
+        int nextRow = listModel->rowForVideo(skippedVideo);
+        nextRow++;
+        if (nextRow == -1) return;
+        listModel->setActiveRow(nextRow);
+    }
+}
+
+void MediaView::skip() {
+    int nextRow = listModel->nextRow();
+    if (nextRow == -1) return;
+    listModel->setActiveRow(nextRow);
+}
+
+void MediaView::skipBackward() {
+    int prevRow = listModel->previousRow();
+    if (prevRow == -1) return;
+    listModel->setActiveRow(prevRow);
+}
+
+void MediaView::aboutToFinish() {
+    qint64 currentTime = mediaObject->currentTime();
+    qDebug() << __PRETTY_FUNCTION__ << currentTime;
+    if (currentTime + 10000 < mediaObject->totalTime()) {
+        // mediaObject->seek(mediaObject->currentTime());
+        // QTimer::singleShot(500, this, SLOT(playbackResume()));
+        mediaObject->seek(currentTime);
+        mediaObject->play();
+    }
+}
+
+void MediaView::playbackFinished() {
+    qDebug() << __PRETTY_FUNCTION__ << mediaObject->currentTime();
+    // 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(500, this, SLOT(playbackResume()));
+    } else {
+        QAction* stopAfterThisAction = The::globalActions()->value("stopafterthis");
+        if (stopAfterThisAction->isChecked()) {
+            stopAfterThisAction->setChecked(false);
+        } else skip();
+    }
+}
+
+void MediaView::playbackResume() {
+    qDebug() << __PRETTY_FUNCTION__ << mediaObject->currentTime();
+    mediaObject->seek(mediaObject->currentTime());
+    mediaObject->play();
+}
+
+void MediaView::openWebPage() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    mediaObject->pause();
+    QDesktopServices::openUrl(video->webpage());
+}
+
+void MediaView::copyWebPage() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    QString address = video->webpage().toString();
+    QApplication::clipboard()->setText(address);
+    QString message = tr("You can now paste the YouTube link into another application");
+    MainWindow::instance()->showMessage(message);
+}
+
+void MediaView::copyVideoLink() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    QApplication::clipboard()->setText(video->getStreamUrl().toEncoded());
+    QString message = tr("You can now paste the video stream URL into another application")
+            + ". " + tr("The link will be valid only for a limited time.");
+    MainWindow::instance()->showMessage(message);
+}
+
+void MediaView::removeSelected() {
+    if (!listView->selectionModel()->hasSelection()) return;
+    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
+    listModel->removeIndexes(indexes);
+}
+
+void MediaView::selectVideos(QList<Video*> videos) {
+    foreach (Video *video, videos) {
+        QModelIndex index = listModel->indexForVideo(video);
+        listView->selectionModel()->select(index, QItemSelectionModel::Select);
+        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
+    }
+}
+
+void MediaView::selectionChanged(const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/) {
+    const bool gotSelection = listView->selectionModel()->hasSelection();
+    The::globalActions()->value("remove")->setEnabled(gotSelection);
+    The::globalActions()->value("moveUp")->setEnabled(gotSelection);
+    The::globalActions()->value("moveDown")->setEnabled(gotSelection);
+}
+
+void MediaView::moveUpSelected() {
+    if (!listView->selectionModel()->hasSelection()) return;
+
+    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
+    qStableSort(indexes.begin(), indexes.end());
+    listModel->move(indexes, true);
+
+    // set current index after row moves to something more intuitive
+    int row = indexes.first().row();
+    listView->selectionModel()->setCurrentIndex(listModel->index(row>1?row:1), QItemSelectionModel::NoUpdate);
+}
+
+void MediaView::moveDownSelected() {
+    if (!listView->selectionModel()->hasSelection()) return;
+
+    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
+    qStableSort(indexes.begin(), indexes.end(), qGreater<QModelIndex>());
+    listModel->move(indexes, false);
+
+    // set current index after row moves to something more intuitive (respect 1 static item on bottom)
+    int row = indexes.first().row()+1, max = listModel->rowCount() - 2;
+    listView->selectionModel()->setCurrentIndex(listModel->index(row>max?max:row), QItemSelectionModel::NoUpdate);
+}
+
+void MediaView::showVideoContextMenu(QPoint point) {
+    The::globalMenus()->value("video")->popup(videoWidget->mapToGlobal(point));
+}
+
+void MediaView::searchMostRelevant() {
+    searchParams->setSortBy(SearchParams::SortByRelevance);
+    search(searchParams);
+}
+
+void MediaView::searchMostRecent() {
+    searchParams->setSortBy(SearchParams::SortByNewest);
+    search(searchParams);
+}
+
+void MediaView::searchMostViewed() {
+    searchParams->setSortBy(SearchParams::SortByViewCount);
+    search(searchParams);
+}
+
+void MediaView::setPlaylistVisible(bool visible) {
+    if (splitter->widget(0)->isVisible() == visible) return;
+    splitter->widget(0)->setVisible(visible);
+    listView->setFocus();
+}
+
+bool MediaView::isPlaylistVisible() {
+    return splitter->widget(0)->isVisible();
+}
+
+void MediaView::timerPlay() {
+    // Workaround Phonon bug on Mac OSX
+    // qDebug() << mediaObject->currentTime();
+    if (mediaObject->currentTime() <= 0 && mediaObject->state() == Phonon::PlayingState) {
+        // qDebug() << "Mac playback workaround";
+        mediaObject->pause();
+        // QTimer::singleShot(1000, mediaObject, SLOT(play()));
+        mediaObject->play();
+    }
+}
+
+void MediaView::saveSplitterState() {
+    QSettings settings;
+    settings.setValue("splitter", splitter->saveState());
+}
+
+#ifdef APP_ACTIVATION
+
+static QPushButton *continueButton;
+
+void MediaView::demoMessage() {
+    if (mediaObject->state() != Phonon::PlayingState) return;
+    mediaObject->pause();
+
+    QMessageBox msgBox(this);
+    msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+    msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::NAME));
+    msgBox.setInformativeText(tr("It allows you to test the application and see if it works for you."));
+    msgBox.setModal(true);
+    // make it a "sheet" on the Mac
+    msgBox.setWindowModality(Qt::WindowModal);
+
+    continueButton = msgBox.addButton("5", QMessageBox::RejectRole);
+    continueButton->setEnabled(false);
+    QPushButton *buyButton = msgBox.addButton(tr("Get the full version"), QMessageBox::ActionRole);
+
+    QTimeLine *timeLine = new QTimeLine(6000, this);
+    timeLine->setCurveShape(QTimeLine::LinearCurve);
+    timeLine->setFrameRange(5, 0);
+    connect(timeLine, SIGNAL(frameChanged(int)), SLOT(updateContinueButton(int)));
+    timeLine->start();
+
+    msgBox.exec();
+
+    if (msgBox.clickedButton() == buyButton) {
+        MainWindow::instance()->showActivationView();
+    } else {
+        mediaObject->play();
+        demoTimer->start(600000);
+    }
+
+    delete timeLine;
+
+}
+
+void MediaView::updateContinueButton(int value) {
+    if (value == 0) {
+        continueButton->setText(tr("Continue"));
+        continueButton->setEnabled(true);
+    } else {
+        continueButton->setText(QString::number(value));
+    }
+}
+
+#endif
+
+void MediaView::downloadVideo() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    DownloadManager::instance()->addItem(video);
+    The::globalActions()->value("downloads")->setVisible(true);
+    QString message = tr("Downloading %1").arg(video->title());
+    MainWindow::instance()->showMessage(message);
+}
+
+void MediaView::snapshot() {
+    QImage image = videoWidget->snapshot();
+    qDebug() << image.size();
+
+    const QPixmap& pixmap = QPixmap::grabWindow(videoWidget->winId());
+    // qDebug() << pixmap.size();
+    videoAreaWidget->showSnapshotPreview(pixmap);
+}
+
+void MediaView::fullscreen() {
+    videoAreaWidget->setParent(0);
+    videoAreaWidget->showFullScreen();
+}
+
+/*
+void MediaView::setSlider(QSlider *slider) {
+    this->slider = slider;
+    // slider->setEnabled(false);
+    slider->setTracking(false);
+    // connect(slider, SIGNAL(valueChanged(int)), SLOT(sliderMoved(int)));
+}
+
+void MediaView::sliderMoved(int value) {
+    qDebug() << __func__;
+    int sliderPercent = (value * 100) / (slider->maximum() - slider->minimum());
+    qDebug() << slider->minimum() << value << slider->maximum();
+    if (sliderPercent <= downloadItem->currentPercent()) {
+        qDebug() << sliderPercent << downloadItem->currentPercent();
+        mediaObject->seek(value);
+    } else {
+        seekTo(value);
+    }
+}
+
+void MediaView::seekTo(int value) {
+    qDebug() << __func__;
+    mediaObject->pause();
+    workaroundTimer->stop();
+    errorTimer->stop();
+    // mediaObject->clear();
+
+    QString tempDir = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
+    QString tempFile = tempDir + "/minitube" + QString::number(value) + ".mp4";
+    if (!QFile::remove(tempFile)) {
+        qDebug() << "Cannot remove temp file";
+    }
+    Video *videoCopy = downloadItem->getVideo()->clone();
+    QUrl streamUrl = videoCopy->getStreamUrl();
+    streamUrl.addQueryItem("begin", QString::number(value));
+    if (downloadItem) delete downloadItem;
+    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
+    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()));
+    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
+    downloadItem->start();
+
+    // slider->setMinimum(value);
+
+}
+
+*/
+
+void MediaView::findVideoParts() {
+
+    // parts
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+
+    QString query = video->title();
+
+    static QString optionalSpace = "\\s*";
+    static QString staticCounterSeparators = "[\\/\\-]";
+    QString counterSeparators = "( of | " +
+            tr("of", "Used in video parts, as in '2 of 3'") +
+            " |" + staticCounterSeparators + ")";
+
+    // numbers from 1 to 15
+    static QString counterNumber = "([1-9]|1[0-5])";
+
+    // query.remove(QRegExp(counterSeparators + optionalSpace + counterNumber));
+    query.remove(QRegExp(counterNumber + optionalSpace + counterSeparators + optionalSpace + counterNumber));
+    query.remove(wordRE("pr?t\\.?" + optionalSpace + counterNumber));
+    query.remove(wordRE("ep\\.?" + optionalSpace + counterNumber));
+    query.remove(wordRE("part" + optionalSpace + counterNumber));
+    query.remove(wordRE("episode" + optionalSpace + counterNumber));
+    query.remove(wordRE(tr("part", "This is for video parts, as in 'Cool video - part 1'") +
+                        optionalSpace + counterNumber));
+    query.remove(wordRE(tr("episode", "This is for video parts, as in 'Cool series - episode 1'") +
+                        optionalSpace + counterNumber));
+    query.remove(QRegExp("[\\(\\)\\[\\]]"));
+
+#define NUMBERS "one|two|three|four|five|six|seven|eight|nine|ten"
+
+    QRegExp englishNumberRE = QRegExp(QLatin1String(".*(") + NUMBERS + ").*", Qt::CaseInsensitive);
+    // bool numberAsWords = englishNumberRE.exactMatch(query);
+    query.remove(englishNumberRE);
+
+    QRegExp localizedNumberRE = QRegExp(QLatin1String(".*(") + tr(NUMBERS) + ").*", Qt::CaseInsensitive);
+    // if (!numberAsWords) numberAsWords = localizedNumberRE.exactMatch(query);
+    query.remove(localizedNumberRE);
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setTransient(true);
+    searchParams->setKeywords(query);
+    searchParams->setAuthor(video->author());
+
+    /*
+    if (!numberAsWords) {
+        qDebug() << "We don't have number as words";
+        // searchParams->setSortBy(SearchParams::SortByNewest);
+        // TODO searchParams->setReverseOrder(true);
+        // TODO searchParams->setMax(50);
+    }
+    */
+
+    search(searchParams);
+
+}
+
+void MediaView::shareViaTwitter() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    QUrl url("https://twitter.com/intent/tweet");
+    url.addQueryItem("via", "minitubeapp");
+    url.addQueryItem("text", video->title());
+    url.addQueryItem("url", video->webpage().toString());
+    QDesktopServices::openUrl(url);
+}
+
+void MediaView::shareViaFacebook() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    QUrl url("https://www.facebook.com/sharer.php");
+    url.addQueryItem("t", video->title());
+    url.addQueryItem("u", video->webpage().toString());
+    QDesktopServices::openUrl(url);
+}
+
+void MediaView::shareViaBuffer() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    QUrl url("http://bufferapp.com/add");
+    url.addQueryItem("via", "minitubeapp");
+    url.addQueryItem("text", video->title());
+    url.addQueryItem("url", video->webpage().toString());
+    if (!video->thumbnailUrls().isEmpty())
+        url.addQueryItem("picture", video->thumbnailUrls().first().toString());
+    QDesktopServices::openUrl(url);
+}
+
+void MediaView::shareViaEmail() {
+    Video* video = listModel->activeVideo();
+    if (!video) return;
+    QUrl url("mailto:");
+    url.addQueryItem("subject", video->title());
+    QString body = video->title() + "\n" +
+            video->webpage().toString() + "\n\n" +
+            tr("Sent from %1").arg(Constants::NAME) + "\n" +
+            Constants::WEBSITE;
+    url.addQueryItem("body", body);
+    QDesktopServices::openUrl(url);
+}
+
+void MediaView::authorPushed(QModelIndex index) {
+    Video* video = listModel->videoAt(index.row());
+    if (!video) return;
+
+    QString channel = video->authorUri();
+    if (channel.isEmpty()) channel = video->author();
+    if (channel.isEmpty()) return;
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setAuthor(channel);
+    searchParams->setSortBy(SearchParams::SortByNewest);
+
+    // go!
+    search(searchParams);
+}
diff --git a/src/mediaview.h b/src/mediaview.h
new file mode 100644 (file)
index 0000000..088b98c
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef __MEDIAVIEW_H__
+#define __MEDIAVIEW_H__
+
+#include <QtGui>
+#include <QtNetwork>
+#include <phonon/mediaobject.h>
+#include <phonon/videowidget.h>
+#include <phonon/seekslider.h>
+#include "view.h"
+#include "listmodel.h"
+#include "segmentedcontrol.h"
+#include "searchparams.h"
+#include "loadingwidget.h"
+#include "videoareawidget.h"
+
+class DownloadItem;
+class PlaylistView;
+class SidebarWidget;
+
+namespace The {
+    QMap<QString, QAction*>* globalActions();
+}
+
+class MediaView : public QWidget, public View {
+    Q_OBJECT
+
+public:
+    MediaView(QWidget *parent);
+    void initialize();
+
+    void appear();
+    void disappear();
+
+    void setMediaObject(Phonon::MediaObject *mediaObject);
+    void setSlider(Phonon::SeekSlider *slider) { this->seekSlider = slider; }
+
+public slots:
+    void search(SearchParams *searchParams);
+    void pause();
+    void stop();
+    void skip();
+    void skipBackward();
+    void skipVideo();
+    void openWebPage();
+    void copyWebPage();
+    void copyVideoLink();
+    void shareViaTwitter();
+    void shareViaFacebook();
+    void shareViaBuffer();
+    void shareViaEmail();
+    void removeSelected();
+    void moveUpSelected();
+    void moveDownSelected();
+    bool isPlaylistVisible();
+    void setPlaylistVisible(bool visible=true);
+    void saveSplitterState();
+    void downloadVideo();
+    void snapshot();
+    void fullscreen();
+    void findVideoParts();
+
+private slots:
+    // list/model
+    void itemActivated(const QModelIndex &index);
+    void selectionChanged (const QItemSelection & selected, const QItemSelection & deselected);
+    void activeRowChanged(int);
+    void selectVideos(QList<Video*> videos);
+    void gotStreamUrl(QUrl streamUrl);
+    void handleError(QString message);
+    // phonon
+    void stateChanged(Phonon::State newState, Phonon::State oldState);
+    void currentSourceChanged(const Phonon::MediaSource source);
+    void showVideoContextMenu(QPoint point);
+    void aboutToFinish();
+    // bar
+    void searchMostRelevant();
+    void searchMostRecent();
+    void searchMostViewed();
+    // timer
+    void timerPlay();
+#ifdef APP_ACTIVATION
+    void demoMessage();
+    void updateContinueButton(int);
+#endif
+    void startPlaying();
+    void downloadStatusChanged();
+    void playbackFinished();
+    void playbackResume();
+    void authorPushed(QModelIndex);
+    void searchAgain();
+
+    /*
+    void downloadProgress(int percent);
+    void sliderMoved(int value);
+    void seekTo(int value);
+    */
+
+private:
+    static QRegExp wordRE(QString s);
+
+    SearchParams *searchParams;
+
+    QSplitter *splitter;
+
+    SidebarWidget *sidebar;
+    PlaylistView *listView;
+    ListModel *listModel;
+
+    // sortBar
+    SegmentedControl *sortBar;
+    QAction *mostRelevantAction;
+    QAction *mostRecentAction;
+    QAction *mostViewedAction;
+
+    // phonon
+    Phonon::MediaObject *mediaObject;
+    Phonon::VideoWidget *videoWidget;
+    Phonon::SeekSlider *seekSlider;
+
+    // loadingWidget
+    VideoAreaWidget *videoAreaWidget;
+    LoadingWidget *loadingWidget;
+
+    bool timerPlayFlag;
+    bool reallyStopped;
+
+    QTimer *errorTimer;
+    QTimer *workaroundTimer;
+    Video *skippedVideo;
+
+#ifdef APP_ACTIVATION
+    QTimer *demoTimer;
+#endif
+
+    DownloadItem *downloadItem;
+
+};
+
+#endif // __MEDIAVIEW_H__
diff --git a/src/playlist/PrettyItemDelegate.cpp b/src/playlist/PrettyItemDelegate.cpp
deleted file mode 100644 (file)
index 846650f..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-#include "PrettyItemDelegate.h"
-#include "../ListModel.h"
-#include "../fontutils.h"
-#include "../downloaditem.h"
-#include "../iconloader/qticonloader.h"
-#include "../videodefinition.h"
-
-#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) {
-    boldFont.setBold(true);
-    smallerBoldFont = FontUtils::smallBold();
-    smallerFont = FontUtils::small();
-
-    if (downloadInfo) {
-        progressBar = new QProgressBar(qApp->activeWindow());
-        QPalette palette = progressBar->palette();
-        palette.setColor(QPalette::Window, Qt::transparent);
-        progressBar->setPalette(palette);
-        progressBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
-        progressBar->hide();
-    } else createPlayIcon();
-}
-
-void PrettyItemDelegate::createPlayIcon() {
-    playIcon = QPixmap(THUMB_WIDTH, THUMB_HEIGHT);
-    playIcon.fill(Qt::transparent);
-    QPainter painter(&playIcon);
-    QPolygon polygon;
-    polygon << QPoint(PADDING*4, PADDING*2)
-            << QPoint(THUMB_WIDTH-PADDING*4, THUMB_HEIGHT/2)
-            << QPoint(PADDING*4, THUMB_HEIGHT-PADDING*2);
-    painter.setRenderHints(QPainter::Antialiasing, true);
-    painter.setBrush(Qt::white);
-    QPen pen;
-    pen.setColor(Qt::white);
-    pen.setWidth(PADDING);
-    pen.setJoinStyle(Qt::RoundJoin);
-    pen.setCapStyle(Qt::RoundCap);
-    painter.setPen(pen);
-    painter.drawPolygon(polygon);
-}
-
-PrettyItemDelegate::~PrettyItemDelegate() { }
-
-QSize PrettyItemDelegate::sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
-    return QSize( 256, THUMB_HEIGHT+1.0);
-}
-
-void PrettyItemDelegate::paint( QPainter* painter,
-                                const QStyleOptionViewItem& option, const QModelIndex& index ) const {
-
-    int itemType = index.data(ItemTypeRole).toInt();
-    if (itemType == ItemTypeVideo) {
-        QStyleOptionViewItemV4 opt = QStyleOptionViewItemV4(option);
-        initStyleOption(&opt, index);
-        opt.text = "";
-        opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
-        paintBody(painter, opt, index);
-    } else
-        QStyledItemDelegate::paint( painter, option, index );
-
-}
-
-void PrettyItemDelegate::paintBody( QPainter* painter,
-                                    const QStyleOptionViewItem& option,
-                                    const QModelIndex& index ) const {
-
-    painter->save();
-    painter->translate( option.rect.topLeft() );
-
-
-    QRectF line(0, 0, option.rect.width(), option.rect.height());
-    if (downloadInfo) line.setWidth(line.width() / 2);
-    painter->setClipRect(line);
-
-    const bool isActive = index.data( ActiveTrackRole ).toBool();
-    const bool isSelected = option.state & QStyle::State_Selected;
-
-    // draw the "current track" highlight underneath the text
-    if (isActive && !isSelected) {
-        paintActiveOverlay(painter, line.x(), line.y(), line.width(), line.height());
-    }
-
-    // get the video metadata
-    const VideoPointer videoPointer = index.data( VideoRole ).value<VideoPointer>();
-    const Video *video = videoPointer.data();
-
-    // thumb
-    if (!video->thumbnail().isNull()) {
-        painter->drawImage(QRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT), video->thumbnail());
-
-        // play icon overlayed on the thumb
-        if (isActive)
-            paintPlayIcon(painter);
-
-        // time
-        QString timeString;
-        int duration = video->duration();
-        if ( duration > 3600 )
-            timeString = QTime().addSecs(duration).toString("h:mm:ss");
-        else
-            timeString = QTime().addSecs(duration).toString("m:ss");
-        drawTime(painter, timeString, line);
-
-    }
-
-    if (isActive) painter->setFont(boldFont);
-
-    // text color
-    if (isSelected)
-        painter->setPen(QPen(option.palette.brush(QPalette::HighlightedText), 0));
-    else
-        painter->setPen(QPen(option.palette.brush(QPalette::Text), 0));
-
-    // title
-    QString videoTitle = video->title();
-    QRectF textBox = line.adjusted(PADDING+THUMB_WIDTH, PADDING, -2 * PADDING, -PADDING);
-    textBox = painter->boundingRect( textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, videoTitle);
-    painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, videoTitle);
-
-    painter->setFont(smallerFont);
-
-    // published date
-    QString publishedString = video->published().date().toString(Qt::DefaultLocaleShortDate);
-    QSizeF stringSize(QFontMetrics(painter->font()).size( Qt::TextSingleLine, publishedString ) );
-    QPointF textLoc(PADDING+THUMB_WIDTH, PADDING*2 + textBox.height());
-    QRectF publishedTextBox(textLoc , stringSize);
-    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) {
-        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();
-    textLoc.setX(textLoc.x() + stringSize.width() + PADDING);
-    stringSize = QSizeF(QFontMetrics(painter->font()).size( Qt::TextSingleLine, authorString ) );
-    QRectF authorTextBox(textLoc , stringSize);
-    authorRects.insert(index.row(), authorTextBox.toRect());
-    painter->drawText(authorTextBox, Qt::AlignLeft | Qt::AlignTop, authorString);
-    painter->restore();
-
-    // view count
-    if (video->viewCount() >= 0) {
-        painter->save();
-        QLocale locale;
-        QString viewCountString = tr("%1 views").arg(locale.toString(video->viewCount()));
-        textLoc.setX(textLoc.x() + stringSize.width() + PADDING);
-        stringSize = QSizeF(QFontMetrics(painter->font()).size( Qt::TextSingleLine, viewCountString ) );
-        QRectF viewCountTextBox(textLoc , stringSize);
-        painter->drawText(viewCountTextBox, Qt::AlignLeft | Qt::AlignBottom, viewCountString);
-        painter->restore();
-    }
-
-    if (downloadInfo) {
-        painter->save();
-        QString definitionString = VideoDefinition::getDefinitionName(video->getDefinitionCode());
-        textLoc.setX(textLoc.x() + stringSize.width() + PADDING);
-        stringSize = QSizeF(QFontMetrics(painter->font()).size( Qt::TextSingleLine, definitionString ) );
-        QRectF viewCountTextBox(textLoc , stringSize);
-        painter->drawText(viewCountTextBox, Qt::AlignLeft | Qt::AlignBottom, definitionString);
-        painter->restore();
-    }
-
-    /*
-    QLinearGradient myGradient;
-    QPen myPen;
-    QFont myFont;
-    QPointF baseline(authorTextBox.x(), authorTextBox.y() + authorTextBox.height());
-    QPainterPath myPath;
-    myPath.addText(baseline, boldFont, authorString);
-    painter->setBrush(palette.color(QPalette::WindowText));
-    painter->setPen(palette.color(QPalette::Dark));
-    painter->setRenderHints (QPainter::Antialiasing, true);
-    painter->drawPath(myPath);
-    */
-
-    // separator
-    painter->setClipping(false);
-    painter->setPen(option.palette.color(QPalette::Midlight));
-    painter->drawLine(THUMB_WIDTH, THUMB_HEIGHT, option.rect.width(), THUMB_HEIGHT);
-    if (!video->thumbnail().isNull())
-        painter->setPen(Qt::black);
-    painter->drawLine(0, THUMB_HEIGHT, THUMB_WIDTH-1, THUMB_HEIGHT);
-
-    painter->restore();
-
-    if (downloadInfo) paintDownloadInfo(painter, option, index);
-
-}
-
-void PrettyItemDelegate::paintActiveOverlay( QPainter *painter, qreal x, qreal y, qreal w, qreal h ) const {
-
-    QPalette palette;
-    QColor highlightColor = palette.color(QPalette::Highlight);
-    QColor backgroundColor = palette.color(QPalette::Base);
-    const float animation = 0.25;
-    const int gradientRange = 16;
-
-    QColor color2 = QColor::fromHsv(
-            highlightColor.hue(),
-            (int) (backgroundColor.saturation() * (1.0f - animation) + highlightColor.saturation() * animation),
-            (int) (backgroundColor.value() * (1.0f - animation) + highlightColor.value() * animation)
-            );
-    QColor color1 = QColor::fromHsv(
-            color2.hue(),
-            qMax(color2.saturation() - gradientRange, 0),
-            qMin(color2.value() + gradientRange, 255)
-            );
-    QRect rect((int) x, (int) y, (int) w, (int) h);
-    painter->save();
-    painter->setPen(Qt::NoPen);
-    QLinearGradient linearGradient(0, 0, 0, rect.height());
-    linearGradient.setColorAt(0.0, color1);
-    linearGradient.setColorAt(1.0, color2);
-    painter->setBrush(linearGradient);
-    painter->drawRect(rect);
-    painter->restore();
-}
-
-void PrettyItemDelegate::paintPlayIcon(QPainter *painter) const {
-    painter->save();
-    painter->setOpacity(.5);
-    painter->drawPixmap(playIcon.rect(), playIcon);
-    painter->restore();
-}
-
-void PrettyItemDelegate::drawTime(QPainter *painter, QString time, QRectF line) const {
-    static const int timePadding = 4;
-    QRectF textBox = painter->boundingRect(line, Qt::AlignLeft | Qt::AlignTop, time);
-    // add padding
-    textBox.adjust(0, 0, timePadding, 0);
-    // move to bottom right corner of the thumb
-    textBox.translate(THUMB_WIDTH - textBox.width(), THUMB_HEIGHT - textBox.height());
-
-    painter->save();
-    painter->setPen(Qt::NoPen);
-    painter->setBrush(Qt::black);
-    painter->setOpacity(.5);
-    painter->drawRect(textBox);
-    painter->restore();
-
-    painter->save();
-    painter->setPen(Qt::white);
-    painter->drawText(textBox, Qt::AlignCenter, time);
-    painter->restore();
-}
-
-void PrettyItemDelegate::paintDownloadInfo( QPainter* painter,
-                                            const QStyleOptionViewItem& option,
-                                            const QModelIndex& index ) const {
-
-    // get the video metadata
-    const DownloadItemPointer downloadItemPointer = index.data(DownloadItemRole).value<DownloadItemPointer>();
-    const DownloadItem *downloadItem = downloadItemPointer.data();
-
-    painter->save();
-
-    const QRect line(0, 0, option.rect.width() / 2, option.rect.height());
-
-    painter->translate(option.rect.topLeft());
-    painter->translate(line.width(), 0);
-
-    QString message;
-    DownloadItemStatus status = downloadItem->status();
-
-    if (status == Downloading) {
-        QString downloaded = DownloadItem::formattedFilesize(downloadItem->bytesReceived());
-        QString total = DownloadItem::formattedFilesize(downloadItem->bytesTotal());
-        QString speed = DownloadItem::formattedSpeed(downloadItem->currentSpeed());
-        QString eta = DownloadItem::formattedTime(downloadItem->remainingTime());
-
-        message = tr("%1 of %2 (%3) — %4").arg(
-                downloaded,
-                total,
-                speed,
-                eta
-                );
-    } else if (status == Starting) {
-        message = tr("Preparing");
-    } else if (status == Failed) {
-        message = tr("Failed") + " — " + downloadItem->errorMessage();
-    } else if (status == Finished) {
-        message = tr("Completed");
-    } else if (status == Idle) {
-        message = tr("Stopped");
-    }
-
-    // progressBar->setPalette(option.palette);
-    if (status == Finished) {
-        progressBar->setValue(100);
-        progressBar->setEnabled(true);
-    } else if (status == Downloading) {
-        progressBar->setValue(downloadItem->currentPercent());
-        progressBar->setEnabled(true);
-    } else {
-        progressBar->setValue(0);
-        progressBar->setEnabled(false);
-    }
-
-    int progressBarWidth = line.width() - PADDING*4 - 16;
-    progressBar->setMaximumWidth(progressBarWidth);
-    progressBar->setMinimumWidth(progressBarWidth);
-    painter->save();
-    painter->translate(PADDING, PADDING);
-    progressBar->render(painter);
-    painter->restore();
-
-    bool downloadButtonHovered = false;
-    bool downloadButtonPressed = false;
-    const bool isHovered = index.data(HoveredItemRole).toBool();
-    if (isHovered) {
-        downloadButtonHovered = index.data(DownloadButtonHoveredRole).toBool();
-        downloadButtonPressed = index.data(DownloadButtonPressedRole).toBool();
-    }
-    QIcon::Mode iconMode;
-    if (downloadButtonPressed) iconMode = QIcon::Selected;
-    else if (downloadButtonHovered) iconMode = QIcon::Active;
-    else iconMode = QIcon::Normal;
-
-    if (status != Finished && status != Failed && status != Idle) {
-        if (downloadButtonHovered) message = tr("Stop downloading");
-        painter->save();
-        QIcon closeIcon = QtIconLoader::icon("window-close");
-        painter->drawPixmap(downloadButtonRect(line), closeIcon.pixmap(16, 16, iconMode));
-        painter->restore();
-    }
-
-    else if (status == Finished) {
-        if (downloadButtonHovered)
-#ifdef APP_MAC
-        message = tr("Show in %1").arg("Finder");
-#else
-        message = tr("Open parent folder");
-#endif
-        painter->save();
-        QIcon searchIcon = QtIconLoader::icon("system-search");
-        painter->drawPixmap(downloadButtonRect(line), searchIcon.pixmap(16, 16, iconMode));
-        painter->restore();
-    }
-
-    else if (status == Failed || status == Idle) {
-        if (downloadButtonHovered) message = tr("Restart downloading");
-        painter->save();
-        QIcon searchIcon = QtIconLoader::icon("view-refresh");
-        painter->drawPixmap(downloadButtonRect(line), searchIcon.pixmap(16, 16, iconMode));
-        painter->restore();
-    }
-
-    QRectF textBox = line.adjusted(PADDING, PADDING*2 + progressBar->sizeHint().height(), -2 * PADDING, -PADDING);
-    textBox = painter->boundingRect( textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, message);
-    painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, message);
-
-    painter->restore();
-
-}
-
-QRect PrettyItemDelegate::downloadButtonRect(QRect line) const {
-    return QRect(
-            line.width() - PADDING*2 - 16,
-            PADDING + progressBar->sizeHint().height() / 2 - 8,
-            16,
-            16);
-}
-
-QRect PrettyItemDelegate::authorRect(const QModelIndex& index) const {
-    return authorRects.value(index.row());
-}
diff --git a/src/playlist/PrettyItemDelegate.h b/src/playlist/PrettyItemDelegate.h
deleted file mode 100644 (file)
index 8934f57..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef PRETTYITEMDELEGATE_H
-#define PRETTYITEMDELEGATE_H
-
-#include <QModelIndex>
-#include <QStyledItemDelegate>
-
-class QPainter;
-class QProgressBar;
-
-class PrettyItemDelegate : public QStyledItemDelegate {
-
-    Q_OBJECT
-
-public:
-    PrettyItemDelegate(QObject* parent, bool downloadInfo = false);
-    ~PrettyItemDelegate();
-
-    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();
-    void paintBody( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
-    void paintDownloadInfo( QPainter* painter,
-                                        const QStyleOptionViewItem& option,
-                                        const QModelIndex& index ) const;
-
-    // active track painting
-    void paintActiveOverlay( QPainter *painter, qreal x, qreal y, qreal w, qreal h ) const;
-    void paintPlayIcon(QPainter *painter) const;
-
-    //  Paints the video duration
-    void drawTime(QPainter *painter, QString time, QRectF line) const;
-
-    static const qreal THUMB_WIDTH;
-    static const qreal THUMB_HEIGHT;
-    static const qreal PADDING;
-
-    QPixmap playIcon;
-    QFont boldFont;
-    QFont smallerFont;
-    QFont smallerBoldFont;
-
-    bool downloadInfo;
-    QProgressBar *progressBar;
-
-};
-
-#endif
diff --git a/src/playlistitemdelegate.cpp b/src/playlistitemdelegate.cpp
new file mode 100644 (file)
index 0000000..7ca439c
--- /dev/null
@@ -0,0 +1,392 @@
+#include "playlistitemdelegate.h"
+#include "listmodel.h"
+#include "fontutils.h"
+#include "downloaditem.h"
+#include "iconloader/qticonloader.h"
+#include "videodefinition.h"
+
+#include <QFontMetricsF>
+#include <QPainter>
+#include <QHash>
+
+const qreal PlaylistItemDelegate::THUMB_HEIGHT = 90.0;
+const qreal PlaylistItemDelegate::THUMB_WIDTH = 120.0;
+const qreal PlaylistItemDelegate::PADDING = 10.0;
+
+QRect lastAuthorRect;
+QHash<int, QRect> authorRects;
+
+PlaylistItemDelegate::PlaylistItemDelegate(QObject* parent, bool downloadInfo)
+    : QStyledItemDelegate(parent),
+    downloadInfo(downloadInfo) {
+    boldFont.setBold(true);
+    smallerBoldFont = FontUtils::smallBold();
+    smallerFont = FontUtils::small();
+
+    if (downloadInfo) {
+        progressBar = new QProgressBar(qApp->activeWindow());
+        QPalette palette = progressBar->palette();
+        palette.setColor(QPalette::Window, Qt::transparent);
+        progressBar->setPalette(palette);
+        progressBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+        progressBar->hide();
+    } else createPlayIcon();
+}
+
+void PlaylistItemDelegate::createPlayIcon() {
+    playIcon = QPixmap(THUMB_WIDTH, THUMB_HEIGHT);
+    playIcon.fill(Qt::transparent);
+    QPainter painter(&playIcon);
+    QPolygon polygon;
+    polygon << QPoint(PADDING*4, PADDING*2)
+            << QPoint(THUMB_WIDTH-PADDING*4, THUMB_HEIGHT/2)
+            << QPoint(PADDING*4, THUMB_HEIGHT-PADDING*2);
+    painter.setRenderHints(QPainter::Antialiasing, true);
+    painter.setBrush(Qt::white);
+    QPen pen;
+    pen.setColor(Qt::white);
+    pen.setWidth(PADDING);
+    pen.setJoinStyle(Qt::RoundJoin);
+    pen.setCapStyle(Qt::RoundCap);
+    painter.setPen(pen);
+    painter.drawPolygon(polygon);
+}
+
+PlaylistItemDelegate::~PlaylistItemDelegate() { }
+
+QSize PlaylistItemDelegate::sizeHint( const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
+    return QSize( 256, THUMB_HEIGHT+1.0);
+}
+
+void PlaylistItemDelegate::paint( QPainter* painter,
+                                const QStyleOptionViewItem& option, const QModelIndex& index ) const {
+
+    int itemType = index.data(ItemTypeRole).toInt();
+    if (itemType == ItemTypeVideo) {
+        QStyleOptionViewItemV4 opt = QStyleOptionViewItemV4(option);
+        initStyleOption(&opt, index);
+        opt.text = "";
+        opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
+        paintBody(painter, opt, index);
+    } else
+        QStyledItemDelegate::paint( painter, option, index );
+
+}
+
+void PlaylistItemDelegate::paintBody( QPainter* painter,
+                                    const QStyleOptionViewItem& option,
+                                    const QModelIndex& index ) const {
+
+    painter->save();
+    painter->translate( option.rect.topLeft() );
+
+
+    QRectF line(0, 0, option.rect.width(), option.rect.height());
+    if (downloadInfo) line.setWidth(line.width() / 2);
+    painter->setClipRect(line);
+
+    const bool isActive = index.data( ActiveTrackRole ).toBool();
+    const bool isSelected = option.state & QStyle::State_Selected;
+
+    // draw the "current track" highlight underneath the text
+    if (isActive && !isSelected) {
+        paintActiveOverlay(painter, line.x(), line.y(), line.width(), line.height());
+    }
+
+    // get the video metadata
+    const VideoPointer videoPointer = index.data( VideoRole ).value<VideoPointer>();
+    const Video *video = videoPointer.data();
+
+    // thumb
+    if (!video->thumbnail().isNull()) {
+        painter->drawImage(QRect(0, 0, THUMB_WIDTH, THUMB_HEIGHT), video->thumbnail());
+
+        // play icon overlayed on the thumb
+        if (isActive)
+            paintPlayIcon(painter);
+
+        // time
+        QString timeString;
+        int duration = video->duration();
+        if ( duration > 3600 )
+            timeString = QTime().addSecs(duration).toString("h:mm:ss");
+        else
+            timeString = QTime().addSecs(duration).toString("m:ss");
+        drawTime(painter, timeString, line);
+
+    }
+
+    if (isActive) painter->setFont(boldFont);
+
+    // text color
+    if (isSelected)
+        painter->setPen(QPen(option.palette.brush(QPalette::HighlightedText), 0));
+    else
+        painter->setPen(QPen(option.palette.brush(QPalette::Text), 0));
+
+    // title
+    QString videoTitle = video->title();
+    QRectF textBox = line.adjusted(PADDING+THUMB_WIDTH, PADDING, -2 * PADDING, -PADDING);
+    textBox = painter->boundingRect( textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, videoTitle);
+    painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, videoTitle);
+
+    painter->setFont(smallerFont);
+
+    // published date
+    QString publishedString = video->published().date().toString(Qt::DefaultLocaleShortDate);
+    QSizeF stringSize(QFontMetrics(painter->font()).size( Qt::TextSingleLine, publishedString ) );
+    QPointF textLoc(PADDING+THUMB_WIDTH, PADDING*2 + textBox.height());
+    QRectF publishedTextBox(textLoc , stringSize);
+    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) {
+        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();
+    textLoc.setX(textLoc.x() + stringSize.width() + PADDING);
+    stringSize = QSizeF(QFontMetrics(painter->font()).size( Qt::TextSingleLine, authorString ) );
+    QRectF authorTextBox(textLoc , stringSize);
+    authorRects.insert(index.row(), authorTextBox.toRect());
+    painter->drawText(authorTextBox, Qt::AlignLeft | Qt::AlignTop, authorString);
+    painter->restore();
+
+    // view count
+    if (video->viewCount() >= 0) {
+        painter->save();
+        QLocale locale;
+        QString viewCountString = tr("%1 views").arg(locale.toString(video->viewCount()));
+        textLoc.setX(textLoc.x() + stringSize.width() + PADDING);
+        stringSize = QSizeF(QFontMetrics(painter->font()).size( Qt::TextSingleLine, viewCountString ) );
+        QRectF viewCountTextBox(textLoc , stringSize);
+        painter->drawText(viewCountTextBox, Qt::AlignLeft | Qt::AlignBottom, viewCountString);
+        painter->restore();
+    }
+
+    if (downloadInfo) {
+        painter->save();
+        QString definitionString = VideoDefinition::getDefinitionName(video->getDefinitionCode());
+        textLoc.setX(textLoc.x() + stringSize.width() + PADDING);
+        stringSize = QSizeF(QFontMetrics(painter->font()).size( Qt::TextSingleLine, definitionString ) );
+        QRectF viewCountTextBox(textLoc , stringSize);
+        painter->drawText(viewCountTextBox, Qt::AlignLeft | Qt::AlignBottom, definitionString);
+        painter->restore();
+    }
+
+    /*
+    QLinearGradient myGradient;
+    QPen myPen;
+    QFont myFont;
+    QPointF baseline(authorTextBox.x(), authorTextBox.y() + authorTextBox.height());
+    QPainterPath myPath;
+    myPath.addText(baseline, boldFont, authorString);
+    painter->setBrush(palette.color(QPalette::WindowText));
+    painter->setPen(palette.color(QPalette::Dark));
+    painter->setRenderHints (QPainter::Antialiasing, true);
+    painter->drawPath(myPath);
+    */
+
+    // separator
+    painter->setClipping(false);
+    painter->setPen(option.palette.color(QPalette::Midlight));
+    painter->drawLine(THUMB_WIDTH, THUMB_HEIGHT, option.rect.width(), THUMB_HEIGHT);
+    if (!video->thumbnail().isNull())
+        painter->setPen(Qt::black);
+    painter->drawLine(0, THUMB_HEIGHT, THUMB_WIDTH-1, THUMB_HEIGHT);
+
+    painter->restore();
+
+    if (downloadInfo) paintDownloadInfo(painter, option, index);
+
+}
+
+void PlaylistItemDelegate::paintActiveOverlay( QPainter *painter, qreal x, qreal y, qreal w, qreal h ) const {
+
+    QPalette palette;
+    QColor highlightColor = palette.color(QPalette::Highlight);
+    QColor backgroundColor = palette.color(QPalette::Base);
+    const float animation = 0.25;
+    const int gradientRange = 16;
+
+    QColor color2 = QColor::fromHsv(
+            highlightColor.hue(),
+            (int) (backgroundColor.saturation() * (1.0f - animation) + highlightColor.saturation() * animation),
+            (int) (backgroundColor.value() * (1.0f - animation) + highlightColor.value() * animation)
+            );
+    QColor color1 = QColor::fromHsv(
+            color2.hue(),
+            qMax(color2.saturation() - gradientRange, 0),
+            qMin(color2.value() + gradientRange, 255)
+            );
+    QRect rect((int) x, (int) y, (int) w, (int) h);
+    painter->save();
+    painter->setPen(Qt::NoPen);
+    QLinearGradient linearGradient(0, 0, 0, rect.height());
+    linearGradient.setColorAt(0.0, color1);
+    linearGradient.setColorAt(1.0, color2);
+    painter->setBrush(linearGradient);
+    painter->drawRect(rect);
+    painter->restore();
+}
+
+void PlaylistItemDelegate::paintPlayIcon(QPainter *painter) const {
+    painter->save();
+    painter->setOpacity(.5);
+    painter->drawPixmap(playIcon.rect(), playIcon);
+    painter->restore();
+}
+
+void PlaylistItemDelegate::drawTime(QPainter *painter, QString time, QRectF line) const {
+    static const int timePadding = 4;
+    QRectF textBox = painter->boundingRect(line, Qt::AlignLeft | Qt::AlignTop, time);
+    // add padding
+    textBox.adjust(0, 0, timePadding, 0);
+    // move to bottom right corner of the thumb
+    textBox.translate(THUMB_WIDTH - textBox.width(), THUMB_HEIGHT - textBox.height());
+
+    painter->save();
+    painter->setPen(Qt::NoPen);
+    painter->setBrush(Qt::black);
+    painter->setOpacity(.5);
+    painter->drawRect(textBox);
+    painter->restore();
+
+    painter->save();
+    painter->setPen(Qt::white);
+    painter->drawText(textBox, Qt::AlignCenter, time);
+    painter->restore();
+}
+
+void PlaylistItemDelegate::paintDownloadInfo( QPainter* painter,
+                                            const QStyleOptionViewItem& option,
+                                            const QModelIndex& index ) const {
+
+    // get the video metadata
+    const DownloadItemPointer downloadItemPointer = index.data(DownloadItemRole).value<DownloadItemPointer>();
+    const DownloadItem *downloadItem = downloadItemPointer.data();
+
+    painter->save();
+
+    const QRect line(0, 0, option.rect.width() / 2, option.rect.height());
+
+    painter->translate(option.rect.topLeft());
+    painter->translate(line.width(), 0);
+
+    QString message;
+    DownloadItemStatus status = downloadItem->status();
+
+    if (status == Downloading) {
+        QString downloaded = DownloadItem::formattedFilesize(downloadItem->bytesReceived());
+        QString total = DownloadItem::formattedFilesize(downloadItem->bytesTotal());
+        QString speed = DownloadItem::formattedSpeed(downloadItem->currentSpeed());
+        QString eta = DownloadItem::formattedTime(downloadItem->remainingTime());
+
+        message = tr("%1 of %2 (%3) — %4").arg(
+                downloaded,
+                total,
+                speed,
+                eta
+                );
+    } else if (status == Starting) {
+        message = tr("Preparing");
+    } else if (status == Failed) {
+        message = tr("Failed") + " — " + downloadItem->errorMessage();
+    } else if (status == Finished) {
+        message = tr("Completed");
+    } else if (status == Idle) {
+        message = tr("Stopped");
+    }
+
+    // progressBar->setPalette(option.palette);
+    if (status == Finished) {
+        progressBar->setValue(100);
+        progressBar->setEnabled(true);
+    } else if (status == Downloading) {
+        progressBar->setValue(downloadItem->currentPercent());
+        progressBar->setEnabled(true);
+    } else {
+        progressBar->setValue(0);
+        progressBar->setEnabled(false);
+    }
+
+    int progressBarWidth = line.width() - PADDING*4 - 16;
+    progressBar->setMaximumWidth(progressBarWidth);
+    progressBar->setMinimumWidth(progressBarWidth);
+    painter->save();
+    painter->translate(PADDING, PADDING);
+    progressBar->render(painter);
+    painter->restore();
+
+    bool downloadButtonHovered = false;
+    bool downloadButtonPressed = false;
+    const bool isHovered = index.data(HoveredItemRole).toBool();
+    if (isHovered) {
+        downloadButtonHovered = index.data(DownloadButtonHoveredRole).toBool();
+        downloadButtonPressed = index.data(DownloadButtonPressedRole).toBool();
+    }
+    QIcon::Mode iconMode;
+    if (downloadButtonPressed) iconMode = QIcon::Selected;
+    else if (downloadButtonHovered) iconMode = QIcon::Active;
+    else iconMode = QIcon::Normal;
+
+    if (status != Finished && status != Failed && status != Idle) {
+        if (downloadButtonHovered) message = tr("Stop downloading");
+        painter->save();
+        QIcon closeIcon = QtIconLoader::icon("window-close");
+        painter->drawPixmap(downloadButtonRect(line), closeIcon.pixmap(16, 16, iconMode));
+        painter->restore();
+    }
+
+    else if (status == Finished) {
+        if (downloadButtonHovered)
+#ifdef APP_MAC
+        message = tr("Show in %1").arg("Finder");
+#else
+        message = tr("Open parent folder");
+#endif
+        painter->save();
+        QIcon searchIcon = QtIconLoader::icon("system-search");
+        painter->drawPixmap(downloadButtonRect(line), searchIcon.pixmap(16, 16, iconMode));
+        painter->restore();
+    }
+
+    else if (status == Failed || status == Idle) {
+        if (downloadButtonHovered) message = tr("Restart downloading");
+        painter->save();
+        QIcon searchIcon = QtIconLoader::icon("view-refresh");
+        painter->drawPixmap(downloadButtonRect(line), searchIcon.pixmap(16, 16, iconMode));
+        painter->restore();
+    }
+
+    QRectF textBox = line.adjusted(PADDING, PADDING*2 + progressBar->sizeHint().height(), -2 * PADDING, -PADDING);
+    textBox = painter->boundingRect( textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, message);
+    painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, message);
+
+    painter->restore();
+
+}
+
+QRect PlaylistItemDelegate::downloadButtonRect(QRect line) const {
+    return QRect(
+            line.width() - PADDING*2 - 16,
+            PADDING + progressBar->sizeHint().height() / 2 - 8,
+            16,
+            16);
+}
+
+QRect PlaylistItemDelegate::authorRect(const QModelIndex& index) const {
+    return authorRects.value(index.row());
+}
diff --git a/src/playlistitemdelegate.h b/src/playlistitemdelegate.h
new file mode 100644 (file)
index 0000000..5f8399b
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef PRETTYITEMDELEGATE_H
+#define PRETTYITEMDELEGATE_H
+
+#include <QModelIndex>
+#include <QStyledItemDelegate>
+
+class QPainter;
+class QProgressBar;
+
+class PlaylistItemDelegate : public QStyledItemDelegate {
+
+    Q_OBJECT
+
+public:
+    PlaylistItemDelegate(QObject* parent, bool downloadInfo = false);
+    ~PlaylistItemDelegate();
+
+    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();
+    void paintBody( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
+    void paintDownloadInfo( QPainter* painter,
+                                        const QStyleOptionViewItem& option,
+                                        const QModelIndex& index ) const;
+
+    // active track painting
+    void paintActiveOverlay( QPainter *painter, qreal x, qreal y, qreal w, qreal h ) const;
+    void paintPlayIcon(QPainter *painter) const;
+
+    //  Paints the video duration
+    void drawTime(QPainter *painter, QString time, QRectF line) const;
+
+    static const qreal THUMB_WIDTH;
+    static const qreal THUMB_HEIGHT;
+    static const qreal PADDING;
+
+    QPixmap playIcon;
+    QFont boldFont;
+    QFont smallerFont;
+    QFont smallerBoldFont;
+
+    bool downloadInfo;
+    QProgressBar *progressBar;
+
+};
+
+#endif
index d976b094728452853d3a5913a3b1aea7a88a339a..d73fd39f9ee5a0b2216eb522771a5727fe6f5eb1 100644 (file)
@@ -1,6 +1,6 @@
 #include "playlistview.h"
-#include "ListModel.h"
-#include "playlist/PrettyItemDelegate.h"
+#include "listmodel.h"
+#include "playlistitemdelegate.h"
 
 PlaylistView::PlaylistView(QWidget *parent) : QListView(parent) {
     connect(this, SIGNAL(entered(const QModelIndex &)), SLOT(itemEntered(const QModelIndex &)));
@@ -62,7 +62,7 @@ bool PlaylistView::isHoveringAuthor(QMouseEvent *event) {
     const QRect itemRect = visualRect(itemIndex);
     // qDebug() << " itemRect.x()" <<  itemRect.x();
 
-    PrettyItemDelegate *delegate = dynamic_cast<PrettyItemDelegate *>(itemDelegate());
+    PlaylistItemDelegate *delegate = dynamic_cast<PlaylistItemDelegate *>(itemDelegate());
     if (!delegate) return false;
 
     QRect rect = delegate->authorRect(itemIndex);
diff --git a/src/searchview.cpp b/src/searchview.cpp
new file mode 100644 (file)
index 0000000..ee6e972
--- /dev/null
@@ -0,0 +1,363 @@
+#include "searchview.h"
+#include "constants.h"
+#include "fontutils.h"
+#include "searchparams.h"
+#include "youtubesuggest.h"
+#include "channelsuggest.h"
+#ifdef APP_MAC
+#include "searchlineedit_mac.h"
+#else
+#include "searchlineedit.h"
+#endif
+#ifndef Q_WS_X11
+#include "extra.h"
+#endif
+#ifdef APP_ACTIVATION
+#include "activation.h"
+#endif
+#include "mainwindow.h"
+
+namespace The {
+QMap<QString, QAction*>* globalActions();
+}
+
+static const QString recentKeywordsKey = "recentKeywords";
+static const QString recentChannelsKey = "recentChannels";
+static const int PADDING = 30;
+
+SearchView::SearchView(QWidget *parent) : QWidget(parent) {
+
+    QFont biggerFont = FontUtils::big();
+    QFont smallerFont = FontUtils::smallBold();
+
+#if defined(APP_MAC) | defined(APP_WIN)
+    // speedup painting since we'll paint the whole background
+    // by ourselves anyway in paintEvent()
+    setAttribute(Qt::WA_OpaquePaintEvent);
+#endif
+
+    QBoxLayout *mainLayout = new QVBoxLayout();
+    mainLayout->setMargin(0);
+    mainLayout->setSpacing(0);
+
+    // hidden message widget
+    message = new QLabel(this);
+    message->hide();
+    mainLayout->addWidget(message);
+
+#ifdef APP_ACTIVATION
+    if (!Activation::instance().isActivated())
+        mainLayout->addWidget(Extra::buyButton(tr("Get the full version")), 0, Qt::AlignCenter);
+#endif
+
+    mainLayout->addStretch();
+    mainLayout->addSpacing(PADDING);
+
+    QBoxLayout *hLayout = new QHBoxLayout();
+    hLayout->setAlignment(Qt::AlignCenter);
+    mainLayout->addLayout(hLayout);
+
+    QLabel *logo = new QLabel(this);
+    logo->setPixmap(QPixmap(":/images/app.png"));
+    hLayout->addWidget(logo, 0, Qt::AlignTop);
+    hLayout->addSpacing(PADDING);
+
+    QVBoxLayout *layout = new QVBoxLayout();
+    layout->setAlignment(Qt::AlignCenter);
+    hLayout->addLayout(layout);
+
+    QLabel *welcomeLabel =
+            new QLabel("<h1 style='font-weight:normal'>" +
+                       tr("Welcome to <a href='%1'>%2</a>,")
+                       // .replace("<a ", "<a style='color:palette(text)'")
+                       .replace("<a href", "<a style='text-decoration:none; color:palette(text); font-weight:bold' href")
+                       .arg(Constants::WEBSITE, Constants::NAME)
+                       + "</h1>", this);
+    welcomeLabel->setOpenExternalLinks(true);
+    layout->addWidget(welcomeLabel);
+
+    layout->addSpacing(PADDING / 2);
+
+    QBoxLayout *tipLayout = new QHBoxLayout();
+    tipLayout->setSpacing(10);
+
+    //: "Enter", as in "type". The whole phrase says: "Enter a keyword to start watching videos"
+    QLabel *tipLabel = new QLabel(tr("Enter"), this);
+    tipLabel->setFont(biggerFont);
+    tipLayout->addWidget(tipLabel);
+
+    typeCombo = new QComboBox(this);
+    typeCombo->addItem(tr("a keyword"));
+    typeCombo->addItem(tr("a channel"));
+    typeCombo->setFont(biggerFont);
+    connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
+    tipLayout->addWidget(typeCombo);
+
+    tipLabel = new QLabel(tr("to start watching videos."), this);
+    tipLabel->setFont(biggerFont);
+    tipLayout->addWidget(tipLabel);
+    layout->addLayout(tipLayout);
+
+    layout->addSpacing(PADDING / 2);
+
+    QHBoxLayout *searchLayout = new QHBoxLayout();
+    searchLayout->setAlignment(Qt::AlignVCenter);
+
+    queryEdit = new SearchLineEdit(this);
+    queryEdit->setFont(biggerFont);
+    queryEdit->setMinimumWidth(queryEdit->fontInfo().pixelSize()*15);
+    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);
+    searchTypeChanged(0);
+
+    searchLayout->addWidget(queryEdit);
+    searchLayout->addSpacing(10);
+
+    watchButton = new QPushButton(tr("Watch"), this);
+    watchButton->setDefault(true);
+    watchButton->setEnabled(false);
+    watchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+    connect(watchButton, SIGNAL(clicked()), this, SLOT(watch()));
+    searchLayout->addWidget(watchButton);
+
+    layout->addItem(searchLayout);
+
+    layout->addSpacing(PADDING / 2);
+
+    QHBoxLayout *otherLayout = new QHBoxLayout();
+    otherLayout->setMargin(0);
+    otherLayout->setSpacing(10);
+
+    recentKeywordsLayout = new QVBoxLayout();
+    recentKeywordsLayout->setSpacing(5);
+    recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+    recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
+    recentKeywordsLabel->setProperty("recentHeader", true);
+    recentKeywordsLabel->setForegroundRole(QPalette::Dark);
+    recentKeywordsLabel->hide();
+    recentKeywordsLabel->setFont(smallerFont);
+    recentKeywordsLayout->addWidget(recentKeywordsLabel);
+
+    otherLayout->addLayout(recentKeywordsLayout);
+
+    // recent channels
+    recentChannelsLayout = new QVBoxLayout();
+    recentChannelsLayout->setSpacing(5);
+    recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+    recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
+    recentChannelsLabel->setProperty("recentHeader", true);
+    recentChannelsLabel->setForegroundRole(QPalette::Dark);
+    recentChannelsLabel->hide();
+    recentChannelsLabel->setFont(smallerFont);
+    recentChannelsLayout->addWidget(recentChannelsLabel);
+
+    otherLayout->addLayout(recentChannelsLayout);
+
+    layout->addLayout(otherLayout);
+
+    mainLayout->addSpacing(PADDING);
+    mainLayout->addStretch();
+
+    setLayout(mainLayout);
+
+}
+
+void SearchView::appear() {
+    updateRecentKeywords();
+    updateRecentChannels();
+    queryEdit->selectAll();
+    queryEdit->enableSuggest();
+    QTimer::singleShot(0, queryEdit, SLOT(setFocus()));
+}
+
+void SearchView::updateRecentKeywords() {
+
+    // cleanup
+    QLayoutItem *item;
+    while ((item = recentKeywordsLayout->takeAt(1)) != 0) {
+        item->widget()->close();
+        delete item;
+    }
+
+    // load
+    QSettings settings;
+    QStringList keywords = settings.value(recentKeywordsKey).toStringList();
+    recentKeywordsLabel->setVisible(!keywords.isEmpty());
+    The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
+
+    foreach (QString keyword, keywords) {
+        QString link = keyword;
+        QString display = keyword;
+        if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
+            int separator = keyword.indexOf("|");
+            if (separator > 0 && separator + 1 < keyword.length()) {
+                link = keyword.left(separator);
+                display = keyword.mid(separator+1);
+            }
+        }
+        bool needStatusTip = false;
+        if (display.length() > 24) {
+            display.truncate(24);
+            display.append("...");
+            needStatusTip = true;
+        }
+        QLabel *itemLabel = new QLabel("<a href=\"" + link
+                                       + "\" 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
+        itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
+        if (needStatusTip)
+            itemLabel->setStatusTip(link);
+        connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchKeywords(QString)));
+        recentKeywordsLayout->addWidget(itemLabel);
+    }
+
+}
+
+void SearchView::updateRecentChannels() {
+
+    // cleanup
+    QLayoutItem *item;
+    while ((item = recentChannelsLayout->takeAt(1)) != 0) {
+        item->widget()->close();
+        delete item;
+    }
+
+    // load
+    QSettings settings;
+    QStringList keywords = settings.value(recentChannelsKey).toStringList();
+    recentChannelsLabel->setVisible(!keywords.isEmpty());
+    // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
+
+    foreach (QString keyword, keywords) {
+        QString link = keyword;
+        QString display = keyword;
+        if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
+            int separator = keyword.indexOf("|");
+            if (separator > 0 && separator + 1 < keyword.length()) {
+                link = keyword.left(separator);
+                display = keyword.mid(separator+1);
+            }
+        }
+        QLabel *itemLabel = new QLabel("<a href=\"" + link
+                                       + "\" 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
+        itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
+
+        connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
+        recentChannelsLayout->addWidget(itemLabel);
+    }
+
+}
+
+void SearchView::watch() {
+    QString query = queryEdit->text();
+    watch(query);
+}
+
+void SearchView::textChanged(const QString &text) {
+    watchButton->setEnabled(!text.simplified().isEmpty());
+}
+
+void SearchView::watch(QString query) {
+
+    query = query.simplified();
+
+    // check for empty query
+    if (query.length() == 0) {
+        queryEdit->setFocus(Qt::OtherFocusReason);
+        return;
+    }
+
+    SearchParams *searchParams = new SearchParams();
+    if (typeCombo->currentIndex() == 0)
+        searchParams->setKeywords(query);
+    else {
+        // remove spaces from channel name
+        query = query.replace(" ", "");
+        searchParams->setAuthor(query);
+        searchParams->setSortBy(SearchParams::SortByNewest);
+    }
+
+    // go!
+    emit search(searchParams);
+}
+
+void SearchView::watchChannel(QString channel) {
+
+    channel = channel.simplified();
+
+    // check for empty query
+    if (channel.length() == 0) {
+        queryEdit->setFocus(Qt::OtherFocusReason);
+        return;
+    }
+
+    // remove spaces from channel name
+    channel = channel.remove(" ");
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setAuthor(channel);
+    searchParams->setSortBy(SearchParams::SortByNewest);
+
+    // go!
+    emit search(searchParams);
+}
+
+void SearchView::watchKeywords(QString query) {
+
+    query = query.simplified();
+
+    // check for empty query
+    if (query.length() == 0) {
+        queryEdit->setFocus(Qt::OtherFocusReason);
+        return;
+    }
+
+    if (typeCombo->currentIndex() == 0) {
+        queryEdit->setText(query);
+        watchButton->setEnabled(true);
+    }
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setKeywords(query);
+
+    // go!
+    emit search(searchParams);
+}
+
+void SearchView::paintEvent(QPaintEvent * /*event*/) {
+#if defined(APP_MAC) | defined(APP_WIN)
+    QBrush brush;
+    if (window()->isActiveWindow()) {
+        brush = QBrush(QColor(0xdd, 0xe4, 0xeb));
+    } else {
+        brush = palette().window();
+    }
+    QPainter painter(this);
+    painter.fillRect(0, 0, width(), height(), brush);
+#endif
+}
+
+void SearchView::searchTypeChanged(int index) {
+    if (index == 0) {
+        queryEdit->setSuggester(youtubeSuggest);
+    } else {
+        queryEdit->setSuggester(channelSuggest);
+    }
+    queryEdit->selectAll();
+    queryEdit->setFocus();
+}
diff --git a/src/searchview.h b/src/searchview.h
new file mode 100644 (file)
index 0000000..a62390d
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __SEARCHVIEW_H__
+#define __SEARCHVIEW_H__
+
+#include <QtGui>
+#include "view.h"
+
+class SearchLineEdit;
+class SearchParams;
+class YouTubeSuggest;
+class ChannelSuggest;
+
+class SearchView : public QWidget, public View {
+
+    Q_OBJECT
+
+public:
+    SearchView(QWidget *parent);
+    void updateRecentKeywords();
+    void updateRecentChannels();
+    QHash<QString, QVariant> metadata() {
+        QHash<QString, QVariant> metadata;
+        metadata.insert("description", tr("Make yourself comfortable"));
+        return metadata;
+    }
+
+public slots:
+    void appear();
+    void watch(QString query);
+    void watchChannel(QString channel);
+    void watchKeywords(QString query);
+
+signals:
+    void search(SearchParams*);
+
+protected:
+    void paintEvent(QPaintEvent *);
+
+private slots:
+    void watch();
+    void textChanged(const QString &text);
+    void searchTypeChanged(int index);
+
+private:
+    YouTubeSuggest *youtubeSuggest;
+    ChannelSuggest *channelSuggest;
+
+    QComboBox *typeCombo;
+    SearchLineEdit *queryEdit;
+    QLabel *recentKeywordsLabel;
+    QBoxLayout *recentKeywordsLayout;
+    QLabel *recentChannelsLabel;
+    QBoxLayout *recentChannelsLayout;
+    QLabel *message;
+    QPushButton *watchButton;
+
+};
+
+#endif // __SEARCHVIEW_H__
index a34cfbfc8057be0026f584572bf0642352581920..8f9db2fe424ded83a0a91f0fdf0cbcebb07815b5 100644 (file)
@@ -4,7 +4,7 @@
 #include <QWidget>
 #include "video.h"
 #include "loadingwidget.h"
-#include "ListModel.h"
+#include "listmodel.h"
 
 class VideoAreaWidget : public QWidget {
 
diff --git a/src/view.h b/src/view.h
new file mode 100644 (file)
index 0000000..0609c38
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef VIEW_H
+#define VIEW_H
+
+class View {
+
+public:
+    virtual QHash<QString, QVariant> metadata() { return QHash<QString, QVariant>(); }
+    virtual void appear() {}
+    virtual void disappear() {}
+
+};
+
+#endif // VIEW_H