~ubuntu-branches/ubuntu/precise/minitube/precise

« back to all changes in this revision

Viewing changes to .pc/proper-tempfiles/src/MediaView.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jakob Haufe
  • Date: 2011-10-12 23:06:30 UTC
  • mfrom: (1.1.10 sid)
  • Revision ID: james.westby@ubuntu.com-20111012230630-dr2kp3ijuhh252y8
Tags: 1.5-2
Do proper temporary file creation (Closes: #644935).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "MediaView.h"
 
2
#include "playlist/PrettyItemDelegate.h"
 
3
#include "networkaccess.h"
 
4
#include "videowidget.h"
 
5
#include "minisplitter.h"
 
6
#include "constants.h"
 
7
#include "downloadmanager.h"
 
8
#include "downloaditem.h"
 
9
#include "MainWindow.h"
 
10
 
 
11
namespace The {
 
12
    NetworkAccess* http();
 
13
}
 
14
 
 
15
namespace The {
 
16
    QMap<QString, QAction*>* globalActions();
 
17
    QMap<QString, QMenu*>* globalMenus();
 
18
    QNetworkAccessManager* networkAccessManager();
 
19
}
 
20
 
 
21
MediaView::MediaView(QWidget *parent) : QWidget(parent) {
 
22
 
 
23
    reallyStopped = false;
 
24
    downloadItem = 0;
 
25
 
 
26
    QBoxLayout *layout = new QHBoxLayout();
 
27
    layout->setMargin(0);
 
28
 
 
29
    splitter = new MiniSplitter(this);
 
30
    splitter->setChildrenCollapsible(false);
 
31
 
 
32
    sortBar = new THBlackBar(this);
 
33
    mostRelevantAction = new QAction(tr("Most relevant"), this);
 
34
    QKeySequence keySequence(Qt::CTRL + Qt::Key_1);
 
35
    mostRelevantAction->setShortcut(keySequence);
 
36
    mostRelevantAction->setStatusTip(mostRelevantAction->text() + " (" + keySequence.toString(QKeySequence::NativeText) + ")");
 
37
    addAction(mostRelevantAction);
 
38
    connect(mostRelevantAction, SIGNAL(triggered()), this, SLOT(searchMostRelevant()), Qt::QueuedConnection);
 
39
    sortBar->addAction(mostRelevantAction);
 
40
    mostRecentAction = new QAction(tr("Most recent"), this);
 
41
    keySequence = QKeySequence(Qt::CTRL + Qt::Key_2);
 
42
    mostRecentAction->setShortcut(keySequence);
 
43
    mostRecentAction->setStatusTip(mostRecentAction->text() + " (" + keySequence.toString(QKeySequence::NativeText) + ")");
 
44
    addAction(mostRecentAction);
 
45
    connect(mostRecentAction, SIGNAL(triggered()), this, SLOT(searchMostRecent()), Qt::QueuedConnection);
 
46
    sortBar->addAction(mostRecentAction);
 
47
    mostViewedAction = new QAction(tr("Most viewed"), this);
 
48
    keySequence = QKeySequence(Qt::CTRL + Qt::Key_3);
 
49
    mostViewedAction->setShortcut(keySequence);
 
50
    mostViewedAction->setStatusTip(mostViewedAction->text() + " (" + keySequence.toString(QKeySequence::NativeText) + ")");
 
51
    addAction(mostViewedAction);
 
52
    connect(mostViewedAction, SIGNAL(triggered()), this, SLOT(searchMostViewed()), Qt::QueuedConnection);
 
53
    sortBar->addAction(mostViewedAction);
 
54
 
 
55
    listView = new QListView(this);
 
56
    listView->setItemDelegate(new PrettyItemDelegate(this));
 
57
    listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
 
58
 
 
59
    // dragndrop
 
60
    listView->setDragEnabled(true);
 
61
    listView->setAcceptDrops(true);
 
62
    listView->setDropIndicatorShown(true);
 
63
    listView->setDragDropMode(QAbstractItemView::DragDrop);
 
64
 
 
65
    // cosmetics
 
66
    listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
 
67
    listView->setFrameShape( QFrame::NoFrame );
 
68
    listView->setAttribute(Qt::WA_MacShowFocusRect, false);
 
69
    listView->setMinimumSize(320,240);
 
70
    listView->setUniformItemSizes(true);
 
71
 
 
72
    // respond to the user doubleclicking a playlist item
 
73
    connect(listView, SIGNAL(activated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &)));
 
74
 
 
75
    listModel = new ListModel(this);
 
76
    connect(listModel, SIGNAL(activeRowChanged(int)), this, SLOT(activeRowChanged(int)));
 
77
    // needed to restore the selection after dragndrop
 
78
    connect(listModel, SIGNAL(needSelectionFor(QList<Video*>)), this, SLOT(selectVideos(QList<Video*>)));
 
79
    listView->setModel(listModel);
 
80
 
 
81
    connect(listView->selectionModel(),
 
82
            SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )),
 
83
            this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & )));
 
84
 
 
85
    playlistWidget = new PlaylistWidget(this, sortBar, listView);
 
86
 
 
87
    splitter->addWidget(playlistWidget);
 
88
 
 
89
    videoAreaWidget = new VideoAreaWidget(this);
 
90
    videoAreaWidget->setMinimumSize(320,240);
 
91
 
 
92
#ifdef APP_MAC
 
93
    // mouse autohide does not work on the Mac (no mouseMoveEvent)
 
94
    videoWidget = new Phonon::VideoWidget(this);
 
95
#else
 
96
    videoWidget = new VideoWidget(this);
 
97
#endif
 
98
 
 
99
    videoAreaWidget->setVideoWidget(videoWidget);
 
100
    videoAreaWidget->setListModel(listModel);
 
101
 
 
102
    loadingWidget = new LoadingWidget(this);
 
103
    videoAreaWidget->setLoadingWidget(loadingWidget);
 
104
 
 
105
    splitter->addWidget(videoAreaWidget);
 
106
 
 
107
    layout->addWidget(splitter);
 
108
    setLayout(layout);
 
109
 
 
110
    // restore splitter state
 
111
    QSettings settings;
 
112
    splitter->restoreState(settings.value("splitter").toByteArray());
 
113
 
 
114
    errorTimer = new QTimer(this);
 
115
    errorTimer->setSingleShot(true);
 
116
    errorTimer->setInterval(3000);
 
117
    connect(errorTimer, SIGNAL(timeout()), SLOT(skipVideo()));
 
118
 
 
119
    workaroundTimer = new QTimer(this);
 
120
    workaroundTimer->setSingleShot(true);
 
121
    workaroundTimer->setInterval(3000);
 
122
    connect(workaroundTimer, SIGNAL(timeout()), SLOT(timerPlay()));
 
123
 
 
124
#ifdef APP_DEMO
 
125
    demoTimer = new QTimer(this);
 
126
    demoTimer->setSingleShot(true);
 
127
    connect(demoTimer, SIGNAL(timeout()), SLOT(demoMessage()));
 
128
#endif
 
129
 
 
130
}
 
131
 
 
132
void MediaView::initialize() {
 
133
    connect(videoAreaWidget, SIGNAL(doubleClicked()), The::globalActions()->value("fullscreen"), SLOT(trigger()));
 
134
    videoAreaWidget->setContextMenuPolicy(Qt::CustomContextMenu);
 
135
    connect(videoAreaWidget, SIGNAL(customContextMenuRequested(QPoint)),
 
136
            this, SLOT(showVideoContextMenu(QPoint)));
 
137
}
 
138
 
 
139
void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
 
140
    this->mediaObject = mediaObject;
 
141
    Phonon::createPath(this->mediaObject, videoWidget);
 
142
    connect(mediaObject, SIGNAL(finished()), this, SLOT(playbackFinished()));
 
143
    connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
 
144
            this, SLOT(stateChanged(Phonon::State, Phonon::State)));
 
145
    connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
 
146
            this, SLOT(currentSourceChanged(Phonon::MediaSource)));
 
147
    // connect(mediaObject, SIGNAL(bufferStatus(int)), loadingWidget, SLOT(bufferStatus(int)));
 
148
}
 
149
 
 
150
void MediaView::search(SearchParams *searchParams) {
 
151
    reallyStopped = false;
 
152
 
 
153
#ifdef APP_DEMO
 
154
    demoTimer->stop();
 
155
#endif
 
156
 
 
157
    videoAreaWidget->clear();
 
158
    workaroundTimer->stop();
 
159
    errorTimer->stop();
 
160
 
 
161
    mediaObject->pause();
 
162
    if (downloadItem) {
 
163
        delete downloadItem;
 
164
        downloadItem = 0;
 
165
    }
 
166
 
 
167
    this->searchParams = searchParams;
 
168
 
 
169
    // start serching for videos
 
170
    listModel->search(searchParams);
 
171
 
 
172
    // this implies that the enum and the bar action order is the same
 
173
    sortBar->setCheckedAction(searchParams->sortBy()-1);
 
174
 
 
175
    listView->setFocus();
 
176
 
 
177
 
 
178
    QString keyword = searchParams->keywords();
 
179
    QString display = keyword;
 
180
    if (keyword.startsWith("http://") || keyword.startsWith("https://")) {
 
181
        int separator = keyword.indexOf("|");
 
182
        if (separator > 0 && separator + 1 < keyword.length()) {
 
183
            display = keyword.mid(separator+1);
 
184
        }
 
185
 
 
186
        // also hide sidebar
 
187
        playlistWidget->hide();
 
188
    } else playlistWidget->show();
 
189
    // tr("You're watching \"%1\"").arg(searchParams->keywords())
 
190
 
 
191
}
 
192
 
 
193
void MediaView::disappear() {
 
194
    timerPlayFlag = true;
 
195
}
 
196
 
 
197
void MediaView::handleError(QString message) {
 
198
    // if (message.indexOf("movie atom") != -1 || message.indexOf("Could not open") != -1) {
 
199
        QTimer::singleShot(1000, this, SLOT(startPlaying()));
 
200
        return;
 
201
    // }
 
202
 
 
203
    /*
 
204
    videoAreaWidget->showError(message);
 
205
    skippedVideo = listModel->activeVideo();
 
206
    // recover from errors by skipping to the next video
 
207
    errorTimer->start(2000);
 
208
    */
 
209
}
 
210
 
 
211
void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/)
 
212
{
 
213
 
 
214
    // qDebug() << "Phonon state: " << newState << oldState;
 
215
    // slider->setEnabled(newState == Phonon::PlayingState);
 
216
 
 
217
    switch (newState) {
 
218
 
 
219
    case Phonon::ErrorState:
 
220
        qDebug() << "Phonon error:" << mediaObject->errorString() << mediaObject->errorType();
 
221
        if (mediaObject->errorType() == Phonon::FatalError)
 
222
            handleError(mediaObject->errorString());
 
223
        break;
 
224
 
 
225
    case Phonon::PlayingState:
 
226
        // qDebug("playing");
 
227
        videoAreaWidget->showVideo();
 
228
        break;
 
229
 
 
230
    case Phonon::StoppedState:
 
231
        // qDebug("stopped");
 
232
        // play() has already been called when setting the source
 
233
        // but Phonon on Linux needs a little more help to start playback
 
234
        // if (!reallyStopped) mediaObject->play();
 
235
 
 
236
#ifdef APP_MAC
 
237
        // Workaround for Mac playback start problem
 
238
        if (!timerPlayFlag) {
 
239
            // workaroundTimer->start();
 
240
        }
 
241
#endif
 
242
 
 
243
        break;
 
244
 
 
245
         case Phonon::PausedState:
 
246
        qDebug("paused");
 
247
        break;
 
248
 
 
249
         case Phonon::BufferingState:
 
250
        qDebug("buffering");
 
251
        break;
 
252
 
 
253
         case Phonon::LoadingState:
 
254
        qDebug("loading");
 
255
        break;
 
256
 
 
257
         default:
 
258
        ;
 
259
    }
 
260
}
 
261
 
 
262
void MediaView::pause() {
 
263
    // qDebug() << "pause() called" << mediaObject->state();
 
264
    switch( mediaObject->state() ) {
 
265
    case Phonon::PlayingState:
 
266
        mediaObject->pause();
 
267
        break;
 
268
    default:
 
269
        mediaObject->play();
 
270
        break;
 
271
    }
 
272
}
 
273
 
 
274
void MediaView::stop() {
 
275
    listModel->abortSearch();
 
276
    reallyStopped = true;
 
277
    mediaObject->stop();
 
278
    videoAreaWidget->clear();
 
279
    workaroundTimer->stop();
 
280
    errorTimer->stop();
 
281
    listView->selectionModel()->clearSelection();
 
282
    if (downloadItem) {
 
283
        downloadItem->stop();
 
284
        delete downloadItem;
 
285
        downloadItem = 0;
 
286
    }
 
287
}
 
288
 
 
289
void MediaView::activeRowChanged(int row) {
 
290
    if (reallyStopped) return;
 
291
 
 
292
    Video *video = listModel->videoAt(row);
 
293
    if (!video) return;
 
294
 
 
295
    // now that we have a new video to play
 
296
    // stop all the timers
 
297
    workaroundTimer->stop();
 
298
    errorTimer->stop();
 
299
 
 
300
    mediaObject->pause();
 
301
    if (downloadItem) {
 
302
        downloadItem->stop();
 
303
        delete downloadItem;
 
304
        downloadItem = 0;
 
305
    }
 
306
    // slider->setMinimum(0);
 
307
 
 
308
    // immediately show the loading widget
 
309
    videoAreaWidget->showLoading(video);
 
310
 
 
311
    connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl)));
 
312
    // TODO handle signal in a proper slot and impl item error status
 
313
    connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)));
 
314
 
 
315
    video->loadStreamUrl();
 
316
 
 
317
    // reset the timer flag
 
318
    timerPlayFlag = false;
 
319
 
 
320
    // video title in the statusbar
 
321
    QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
 
322
    if (mainWindow) mainWindow->statusBar()->showMessage(video->title());
 
323
 
 
324
    The::globalActions()->value("download")->setEnabled(DownloadManager::instance()->itemForVideo(video) == 0);
 
325
 
 
326
    // ensure active item is visible
 
327
    // int row = listModel->activeRow();
 
328
    if (row != -1) {
 
329
        QModelIndex index = listModel->index(row, 0, QModelIndex());
 
330
        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
 
331
    }
 
332
 
 
333
    // see you in gotStreamUrl...
 
334
 
 
335
}
 
336
 
 
337
void MediaView::gotStreamUrl(QUrl streamUrl) {
 
338
    if (reallyStopped) return;
 
339
 
 
340
    Video *video = static_cast<Video *>(sender());
 
341
    if (!video) {
 
342
        qDebug() << "Cannot get sender";
 
343
        return;
 
344
    }
 
345
    video->disconnect(this);
 
346
 
 
347
 
 
348
    QString tempDir = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
 
349
#ifdef Q_WS_X11
 
350
    QString tempFile = tempDir + "/minitube-" + getenv("USERNAME") + ".mp4";
 
351
#else
 
352
    QString tempFile = tempDir + "/minitube.mp4";
 
353
#endif
 
354
    if (QFile::exists(tempFile) && !QFile::remove(tempFile)) {
 
355
        qDebug() << "Cannot remove temp file";
 
356
    }
 
357
 
 
358
    Video *videoCopy = video->clone();
 
359
    if (downloadItem) {
 
360
        downloadItem->stop();
 
361
        delete downloadItem;
 
362
    }
 
363
    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
 
364
    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()));
 
365
    // connect(downloadItem, SIGNAL(progress(int)), SLOT(downloadProgress(int)));
 
366
    connect(downloadItem, SIGNAL(bufferProgress(int)), loadingWidget, SLOT(bufferStatus(int)));
 
367
    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
 
368
    connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)));
 
369
    connect(downloadItem, SIGNAL(error(QString)), SLOT(handleError(QString)));
 
370
    downloadItem->start();
 
371
 
 
372
}
 
373
 
 
374
/*
 
375
void MediaView::downloadProgress(int percent) {
 
376
    MainWindow* mainWindow = dynamic_cast<MainWindow*>(window());
 
377
 
 
378
    mainWindow->getSeekSlider()->setStyleSheet(" QSlider::groove:horizontal {"
 
379
        "border: 1px solid #999999;"
 
380
        // "border-left: 50px solid rgba(255, 0, 0, 128);"
 
381
        "height: 8px;"
 
382
        "background: qlineargradient(x1:0, y1:0, x2:.5, y2:0, stop:0 rgba(255, 0, 0, 92), stop:"
 
383
        + QString::number(percent/100.0) +
 
384
 
 
385
        " rgba(255, 0, 0, 92), stop:" + QString::number((percent+1)/100.0) + " transparent, stop:1 transparent);"
 
386
        "margin: 2px 0;"
 
387
    "}"
 
388
    "QSlider::handle:horizontal {"
 
389
        "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);"
 
390
        "border: 1px solid #5c5c5c;"
 
391
        "width: 16px;"
 
392
        "height: 16px;"
 
393
        "margin: -2px 0;"
 
394
        "border-radius: 8px;"
 
395
    "}"
 
396
 
 
397
    );
 
398
}
 
399
 
 
400
*/
 
401
 
 
402
void MediaView::downloadStatusChanged() {
 
403
    switch(downloadItem->status()) {
 
404
    case Downloading:
 
405
        startPlaying();
 
406
        break;
 
407
    case Starting:
 
408
        // qDebug() << "Starting";
 
409
        break;
 
410
    case Finished:
 
411
        // qDebug() << "Finished" << mediaObject->state();
 
412
        // if (mediaObject->state() == Phonon::StoppedState) startPlaying();
 
413
        break;
 
414
    case Failed:
 
415
        // qDebug() << "Failed";
 
416
    case Idle:
 
417
        // qDebug() << "Idle";
 
418
        break;
 
419
    }
 
420
}
 
421
 
 
422
void MediaView::startPlaying() {
 
423
    if (reallyStopped) return;
 
424
    if (!downloadItem) {
 
425
        skip();
 
426
        return;
 
427
    }
 
428
 
 
429
    // go!
 
430
    qDebug() << "Playing" << downloadItem->currentFilename();
 
431
    mediaObject->setCurrentSource(downloadItem->currentFilename());
 
432
    mediaObject->play();
 
433
 
 
434
    // ensure we always have 10 videos ahead
 
435
    listModel->searchNeeded();
 
436
 
 
437
    // ensure active item is visible
 
438
    int row = listModel->activeRow();
 
439
    if (row != -1) {
 
440
        QModelIndex index = listModel->index(row, 0, QModelIndex());
 
441
        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
 
442
    }
 
443
 
 
444
#ifdef APP_DEMO
 
445
    demoTimer->start(30000);
 
446
#endif
 
447
 
 
448
}
 
449
 
 
450
void MediaView::itemActivated(const QModelIndex &index) {
 
451
    if (listModel->rowExists(index.row()))
 
452
        listModel->setActiveRow(index.row());
 
453
    // the user doubleclicked on the "Search More" item
 
454
    else listModel->searchMore();
 
455
}
 
456
 
 
457
void MediaView::currentSourceChanged(const Phonon::MediaSource /* source */ ) {
 
458
 
 
459
}
 
460
 
 
461
void MediaView::skipVideo() {
 
462
    // skippedVideo is useful for DELAYED skip operations
 
463
    // in order to be sure that we're skipping the video we wanted
 
464
    // and not another one
 
465
    if (skippedVideo) {
 
466
        if (listModel->activeVideo() != skippedVideo) {
 
467
            qDebug() << "Skip of video canceled";
 
468
            return;
 
469
        }
 
470
        int nextRow = listModel->rowForVideo(skippedVideo);
 
471
        nextRow++;
 
472
        if (nextRow == -1) return;
 
473
        listModel->setActiveRow(nextRow);
 
474
    }
 
475
}
 
476
 
 
477
void MediaView::skip() {
 
478
    int nextRow = listModel->nextRow();
 
479
    if (nextRow == -1) return;
 
480
    listModel->setActiveRow(nextRow);
 
481
}
 
482
 
 
483
void MediaView::playbackFinished() {
 
484
    // qDebug() << "finished" << mediaObject->currentTime() << mediaObject->totalTime();
 
485
    // add 10 secs for imprecise Phonon backends (VLC, Xine)
 
486
    if (mediaObject->currentTime() + 10000 < mediaObject->totalTime()) {
 
487
        // mediaObject->seek(mediaObject->currentTime());
 
488
        QTimer::singleShot(3000, this, SLOT(playbackResume()));
 
489
    } else skip();
 
490
}
 
491
 
 
492
void MediaView::playbackResume() {
 
493
    mediaObject->seek(mediaObject->currentTime());
 
494
    mediaObject->play();
 
495
}
 
496
 
 
497
void MediaView::openWebPage() {
 
498
    Video* video = listModel->activeVideo();
 
499
    if (!video) return;
 
500
    mediaObject->pause();
 
501
    QDesktopServices::openUrl(video->webpage());
 
502
}
 
503
 
 
504
void MediaView::copyWebPage() {
 
505
    Video* video = listModel->activeVideo();
 
506
    if (!video) return;
 
507
    QString address = video->webpage().toString();
 
508
    address.remove("&feature=youtube_gdata");
 
509
    QApplication::clipboard()->setText(address);
 
510
    QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
 
511
    QString message = tr("You can now paste the YouTube link into another application");
 
512
    if (mainWindow) mainWindow->statusBar()->showMessage(message);
 
513
}
 
514
 
 
515
void MediaView::copyVideoLink() {
 
516
    Video* video = listModel->activeVideo();
 
517
    if (!video) return;
 
518
    QApplication::clipboard()->setText(video->getStreamUrl().toEncoded());
 
519
    QString message = tr("You can now paste the video stream URL into another application")
 
520
                      + ". " + tr("The link will be valid only for a limited time.");
 
521
    QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
 
522
    if (mainWindow) mainWindow->statusBar()->showMessage(message);
 
523
}
 
524
 
 
525
void MediaView::removeSelected() {
 
526
    if (!listView->selectionModel()->hasSelection()) return;
 
527
    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
 
528
    listModel->removeIndexes(indexes);
 
529
}
 
530
 
 
531
void MediaView::selectVideos(QList<Video*> videos) {
 
532
    foreach (Video *video, videos) {
 
533
        QModelIndex index = listModel->indexForVideo(video);
 
534
        listView->selectionModel()->select(index, QItemSelectionModel::Select);
 
535
        listView->scrollTo(index, QAbstractItemView::EnsureVisible);
 
536
    }
 
537
}
 
538
 
 
539
void MediaView::selectionChanged(const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/) {
 
540
    const bool gotSelection = listView->selectionModel()->hasSelection();
 
541
    The::globalActions()->value("remove")->setEnabled(gotSelection);
 
542
    The::globalActions()->value("moveUp")->setEnabled(gotSelection);
 
543
    The::globalActions()->value("moveDown")->setEnabled(gotSelection);
 
544
}
 
545
 
 
546
void MediaView::moveUpSelected() {
 
547
    if (!listView->selectionModel()->hasSelection()) return;
 
548
 
 
549
    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
 
550
    qStableSort(indexes.begin(), indexes.end());
 
551
    listModel->move(indexes, true);
 
552
 
 
553
    // set current index after row moves to something more intuitive
 
554
    int row = indexes.first().row();
 
555
    listView->selectionModel()->setCurrentIndex(listModel->index(row>1?row:1), QItemSelectionModel::NoUpdate);
 
556
}
 
557
 
 
558
void MediaView::moveDownSelected() {
 
559
    if (!listView->selectionModel()->hasSelection()) return;
 
560
 
 
561
    QModelIndexList indexes = listView->selectionModel()->selectedIndexes();
 
562
    qStableSort(indexes.begin(), indexes.end(), qGreater<QModelIndex>());
 
563
    listModel->move(indexes, false);
 
564
 
 
565
    // set current index after row moves to something more intuitive (respect 1 static item on bottom)
 
566
    int row = indexes.first().row()+1, max = listModel->rowCount() - 2;
 
567
    listView->selectionModel()->setCurrentIndex(listModel->index(row>max?max:row), QItemSelectionModel::NoUpdate);
 
568
}
 
569
 
 
570
void MediaView::showVideoContextMenu(QPoint point) {
 
571
    The::globalMenus()->value("video")->popup(videoWidget->mapToGlobal(point));
 
572
}
 
573
 
 
574
void MediaView::searchMostRelevant() {
 
575
    searchParams->setSortBy(SearchParams::SortByRelevance);
 
576
    search(searchParams);
 
577
}
 
578
 
 
579
void MediaView::searchMostRecent() {
 
580
    searchParams->setSortBy(SearchParams::SortByNewest);
 
581
    search(searchParams);
 
582
}
 
583
 
 
584
void MediaView::searchMostViewed() {
 
585
    searchParams->setSortBy(SearchParams::SortByViewCount);
 
586
    search(searchParams);
 
587
}
 
588
 
 
589
void MediaView::setPlaylistVisible(bool visible) {
 
590
    playlistWidget->setVisible(visible);
 
591
}
 
592
 
 
593
void MediaView::timerPlay() {
 
594
    // Workaround Phonon bug on Mac OSX
 
595
    // qDebug() << mediaObject->currentTime();
 
596
    if (mediaObject->currentTime() <= 0 && mediaObject->state() == Phonon::PlayingState) {
 
597
        // qDebug() << "Mac playback workaround";
 
598
        mediaObject->pause();
 
599
        // QTimer::singleShot(1000, mediaObject, SLOT(play()));
 
600
        mediaObject->play();
 
601
    }
 
602
}
 
603
 
 
604
void MediaView::saveSplitterState() {
 
605
    QSettings settings;
 
606
    settings.setValue("splitter", splitter->saveState());
 
607
}
 
608
 
 
609
#ifdef APP_DEMO
 
610
void MediaView::demoMessage() {
 
611
    if (mediaObject->state() != Phonon::PlayingState) return;
 
612
    mediaObject->pause();
 
613
 
 
614
    QMessageBox msgBox(this);
 
615
    msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
 
616
    msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::APP_NAME));
 
617
    msgBox.setInformativeText(tr("It allows you to test the application and see if it works for you."));
 
618
    msgBox.setModal(true);
 
619
    // make it a "sheet" on the Mac
 
620
    msgBox.setWindowModality(Qt::WindowModal);
 
621
 
 
622
    QPushButton *quitButton = msgBox.addButton(tr("Continue"), QMessageBox::RejectRole);
 
623
    QPushButton *buyButton = msgBox.addButton(tr("Get the full version"), QMessageBox::ActionRole);
 
624
 
 
625
    msgBox.exec();
 
626
 
 
627
    if (msgBox.clickedButton() == buyButton) {
 
628
        QDesktopServices::openUrl(QString(Constants::WEBSITE) + "#download");
 
629
    } else {
 
630
        mediaObject->play();
 
631
        demoTimer->start(300000);
 
632
    }
 
633
}
 
634
#endif
 
635
 
 
636
void MediaView::downloadVideo() {
 
637
    Video* video = listModel->activeVideo();
 
638
    if (!video) return;
 
639
 
 
640
    DownloadManager::instance()->addItem(video);
 
641
 
 
642
    // TODO animate
 
643
 
 
644
    The::globalActions()->value("downloads")->setVisible(true);
 
645
 
 
646
    // The::globalActions()->value("download")->setEnabled(DownloadManager::instance()->itemForVideo(video) == 0);
 
647
 
 
648
    QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(window());
 
649
    QString message = tr("Downloading %1").arg(video->title());
 
650
    if (mainWindow) mainWindow->statusBar()->showMessage(message);
 
651
}
 
652
 
 
653
void MediaView::fullscreen() {
 
654
    videoAreaWidget->setParent(0);
 
655
    videoAreaWidget->showFullScreen();
 
656
}
 
657
 
 
658
/*
 
659
void MediaView::setSlider(QSlider *slider) {
 
660
    this->slider = slider;
 
661
    // slider->setEnabled(false);
 
662
    slider->setTracking(false);
 
663
    // connect(slider, SIGNAL(valueChanged(int)), SLOT(sliderMoved(int)));
 
664
}
 
665
 
 
666
void MediaView::sliderMoved(int value) {
 
667
    qDebug() << __func__;
 
668
    int sliderPercent = (value * 100) / (slider->maximum() - slider->minimum());
 
669
    qDebug() << slider->minimum() << value << slider->maximum();
 
670
    if (sliderPercent <= downloadItem->currentPercent()) {
 
671
        qDebug() << sliderPercent << downloadItem->currentPercent();
 
672
        mediaObject->seek(value);
 
673
    } else {
 
674
        seekTo(value);
 
675
    }
 
676
}
 
677
 
 
678
void MediaView::seekTo(int value) {
 
679
    qDebug() << __func__;
 
680
    mediaObject->pause();
 
681
    workaroundTimer->stop();
 
682
    errorTimer->stop();
 
683
    // mediaObject->clear();
 
684
 
 
685
    QString tempDir = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
 
686
    QString tempFile = tempDir + "/minitube" + QString::number(value) + ".mp4";
 
687
    if (!QFile::remove(tempFile)) {
 
688
        qDebug() << "Cannot remove temp file";
 
689
    }
 
690
    Video *videoCopy = downloadItem->getVideo()->clone();
 
691
    QUrl streamUrl = videoCopy->getStreamUrl();
 
692
    streamUrl.addQueryItem("begin", QString::number(value));
 
693
    if (downloadItem) delete downloadItem;
 
694
    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
 
695
    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()));
 
696
    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
 
697
    downloadItem->start();
 
698
 
 
699
    // slider->setMinimum(value);
 
700
 
 
701
}
 
702
 
 
703
*/