ImportController.cpp 13.1 KB
Newer Older
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
1 2 3
/*****************************************************************************
 * ImportController.cpp
 *****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2008-2010 VideoLAN
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
5 6 7
 *
 * Authors: Geoffroy Lacarriere <geoffroylaca@gmail.com>
 *          Thomas Boquet <thomas.boquet@gmail.com>
8
 *          Clement Chavance <chavance.c@gmail.com>
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
9
 *          Hugo Beauzée-Luyssen <hugo@vlmc.org>
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

Thomas Boquet's avatar
Thomas Boquet committed
26
#include "ui_ImportController.h"
27

Thomas Boquet's avatar
Thomas Boquet committed
28
#include "ClipRenderer.h"
29
#include "ImportController.h"
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
30
#include "Library.h"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
31
#include "MetaDataManager.h"
32
#include "MediaCellView.h"
33 34

#include <QPalette>
35
#include <QSettings>
36
#include <QTime>
37
#include <QTimer>
Thomas Boquet's avatar
Thomas Boquet committed
38 39 40

ImportController::ImportController(QWidget *parent) :
    QDialog(parent),
41 42
    m_ui(new Ui::ImportController),
    m_clipListController( 0 ),
43 44
    m_nbMediaToLoad( 0 ),
    m_nbMediaLoaded( 0 )
Thomas Boquet's avatar
Thomas Boquet committed
45 46 47 48
{
    m_ui->setupUi(this);
    m_preview = new PreviewWidget( new ClipRenderer, m_ui->previewContainer );
    m_stackNav = new StackViewController( m_ui->stackViewContainer, false );
49
    m_mediaListController = new MediaListViewController( m_stackNav );
Thomas Boquet's avatar
Thomas Boquet committed
50
    m_tag = new TagWidget( m_ui->tagContainer, 6 );
51
    m_filesModel = new QFileSystemModel( this );
Thomas Boquet's avatar
Thomas Boquet committed
52 53 54
    m_stackNav->pushViewController( m_mediaListController );

    QStringList filters;
55 56 57 58
    filters << Media::AudioExtensions.split(' ', QString::SkipEmptyParts)
            << Media::VideoExtensions.split(' ', QString::SkipEmptyParts)
            << Media::ImageExtensions.split(' ', QString::SkipEmptyParts);
    m_filesModel->setFilter( QDir::AllDirs | QDir::AllEntries | QDir::NoDotAndDotDot );
Thomas Boquet's avatar
Thomas Boquet committed
59 60 61
    m_filesModel->sort( 2, Qt::AscendingOrder );
    m_filesModel->sort( 0, Qt::AscendingOrder );
    m_filesModel->setNameFilters( filters );
62
    m_filesModel->setRootPath( "/" );
63
    m_filesModel->setNameFilterDisables( false );
64 65 66

    restoreCurrentPath();

Thomas Boquet's avatar
Thomas Boquet committed
67
    m_ui->treeView->setModel( m_filesModel );
68
    m_ui->treeView->setHeaderHidden( true );
69
    m_ui->treeView->setCurrentIndex( m_filesModel->index( m_currentlyWatchedDir ) );
Thomas Boquet's avatar
Thomas Boquet committed
70
    m_ui->treeView->setExpanded( m_ui->treeView->currentIndex() , true );
71 72
    m_ui->treeView->header()->setStretchLastSection( false );
    m_ui->treeView->header()->setResizeMode( QHeaderView::ResizeToContents );
Thomas Boquet's avatar
Thomas Boquet committed
73 74 75
    m_ui->treeView->setColumnHidden( 1, true );
    m_ui->treeView->setColumnHidden( 2, true );
    m_ui->treeView->setColumnHidden( 3, true );
76
    m_ui->forwardButton->setEnabled( true );
Thomas Boquet's avatar
Thomas Boquet committed
77

78
    m_ui->progressBar->setHidden( true );
79 80
    m_ui->errorLabelImg->hide();
    m_ui->errorLabel->hide();
81

82 83 84 85 86 87 88
    connect( m_ui->treeView, SIGNAL( clicked( QModelIndex ) ),
             this, SLOT( treeViewClicked( QModelIndex ) ) );
    connect( m_ui->treeView, SIGNAL( doubleClicked( QModelIndex ) ),
             this, SLOT( treeViewDoubleClicked( QModelIndex ) ) );
    connect( m_ui->forwardButton, SIGNAL( clicked() ),
             this, SLOT( forwardButtonClicked() ) );

89 90 91
    connect( m_mediaListController, SIGNAL( mediaSelected( const QUuid& ) ),
             qobject_cast<const ClipRenderer*>( m_preview->getGenericRenderer() ),
             SLOT( setClip( const QUuid& ) ) );
92 93 94 95 96 97 98 99 100 101 102 103
    connect( this, SIGNAL( mediaSelected( Media* ) ),
             m_tag, SLOT( mediaSelected( Media* ) ) );

    connect( m_mediaListController, SIGNAL( mediaSelected( const QUuid& ) ),
             this, SLOT( mediaSelection( const QUuid& ) ) );
    connect( m_mediaListController, SIGNAL( mediaDeleted( const QUuid& ) ),
             this, SLOT( mediaDeletion( const QUuid& ) ) );

    connect( m_mediaListController, SIGNAL( showClipListAsked( const QUuid& ) ),
             this, SLOT( showClipList( const QUuid& ) ) );
    connect( m_stackNav, SIGNAL( previousButtonPushed() ),
             this, SLOT( restoreContext() ) );
104 105 106

    connect( MetaDataManager::getInstance(), SIGNAL( failedToCompute( Media* ) ),
             this, SLOT( failedToLoad( Media* ) ) );
Thomas Boquet's avatar
Thomas Boquet committed
107 108 109 110
}

ImportController::~ImportController()
{
111
    delete m_preview;
Thomas Boquet's avatar
Thomas Boquet committed
112 113 114 115 116
    delete m_ui;
    delete m_stackNav;
    delete m_tag;
}

117 118
void
ImportController::changeEvent( QEvent *e )
Thomas Boquet's avatar
Thomas Boquet committed
119 120
{
    QDialog::changeEvent( e );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
121 122 123 124 125 126 127
    switch ( e->type() )
    {
        case QEvent::LanguageChange:
            m_ui->retranslateUi( this );
            break;
        default:
            break;
Thomas Boquet's avatar
Thomas Boquet committed
128 129 130
    }
}

131 132
void
ImportController::mediaSelection( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
133
{
134 135 136 137 138 139 140
    if ( m_currentUuid == uuid )
        return ;

    setUIMetaData( m_temporaryMedias[uuid] );
    m_preview->stop();
    m_currentUuid = uuid;
    emit mediaSelected( m_temporaryMedias[uuid] );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
141 142
}

143 144
void
ImportController::clipSelection( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
145
{
146 147
    if ( uuid == m_currentUuid )
        return ;
148
    Clip*   clip;
149

150
    foreach( Media* media, m_temporaryMedias.values() )
151
    {
152
        if ( ( clip = media->clip( uuid ) ) != NULL )
153
            break;
154
    }
155
    if ( clip == NULL )
156
        return ;
157
    setUIMetaData( clip );
158
    m_preview->stop();
159
    emit clipSelected( clip );
Thomas Boquet's avatar
Thomas Boquet committed
160 161
}

162 163
void
ImportController::setUIMetaData( Media* media )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
164
{
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
165 166 167 168
    if ( media != NULL )
    {
        //Duration
        QTime   duration;
169
        duration = duration.addMSecs( media->lengthMS() );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
170 171
        m_ui->durationValueLabel->setText( duration.toString( "hh:mm:ss" ) );
        //Filename || title
172
        m_ui->nameValueLabel->setText( media->fileInfo()->fileName() );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
173
        m_ui->nameValueLabel->setWordWrap( true );
174
        setWindowTitle( media->fileInfo()->fileName() + " " + tr( "properties" ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
175
        //Resolution
176 177
        m_ui->resolutionValueLabel->setText( QString::number( media->width() )
                                        + " x " + QString::number( media->height() ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
178
        //FPS
179
        m_ui->fpsValueLabel->setText( QString::number( media->fps() ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
180 181 182
    }
    else
    {
183 184 185 186
        m_ui->durationValueLabel->setText( "--:--:--" );
        m_ui->nameValueLabel->setText( "none" );
        m_ui->resolutionValueLabel->setText( "-- x --" );
        m_ui->fpsValueLabel->setText( "--" );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
187
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
188 189
}

190 191
void
ImportController::setUIMetaData( Clip* clip )
192 193
{
    QTime   time;
194
    qint64  length = clip->lengthSecond();
195 196
    time = time.addSecs( length );
    m_ui->durationValueLabel->setText( time.toString( "hh:mm:ss" ) );
197
    m_ui->nameValueLabel->setText( clip->getParent()->fileInfo()->fileName() );
198
    m_ui->nameValueLabel->setWordWrap( true );
199
    setWindowTitle( clip->getParent()->fileInfo()->fileName() + " " +
200
                    tr( "properties" ) );
201 202 203
    m_ui->resolutionValueLabel->setText( QString::number( clip->getParent()->width() )
            + " x " + QString::number( clip->getParent()->height() ) );
    m_ui->fpsValueLabel->setText( QString::number( clip->getParent()->fps() ) );
204
}
Thomas Boquet's avatar
Thomas Boquet committed
205

206
void
207
ImportController::importMedia( const QString &filePath )
Thomas Boquet's avatar
Thomas Boquet committed
208
{
209
    ++m_nbMediaToLoad;
210
    m_ui->progressBar->setMaximum( m_nbMediaToLoad );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
211
    foreach ( Media* media, m_temporaryMedias.values() )
212
        if ( media->fileInfo()->filePath() == filePath )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
213 214 215 216
            return ;
    if ( Library::getInstance()->mediaAlreadyLoaded( filePath ) == true )
        return ;

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
217
    Media*          media = new Media( filePath );
218
    connect( media, SIGNAL( snapshotComputed( const Media* ) ),
219
             this, SLOT( mediaLoaded() ) );
220
    m_temporaryMedias[media->baseClip()->uuid()] = media;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
221
    MetaDataManager::getInstance()->computeMediaMetadata( media );
222
    m_mediaListController->newMediaLoaded( media );
Thomas Boquet's avatar
Thomas Boquet committed
223 224
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
void
ImportController::importDir( const QString &path )
{
    QDir            dir( path );
    QFileInfoList   files = dir.entryInfoList( QDir::NoDotAndDotDot | QDir::Readable
                                               | QDir::AllEntries );

    foreach ( QFileInfo fInfo, files )
    {
        if ( fInfo.isDir() == true )
            importDir( fInfo.absolutePath() );
        else
        {
            QString ext = fInfo.suffix();

            if ( Media::AudioExtensions.contains( ext ) ||
                 Media::VideoExtensions.contains( ext ) ||
                 Media::ImageExtensions.contains( ext ) )
            {
                importMedia( fInfo.absoluteFilePath() );
            }
        }
    }
}

void
ImportController::forwardButtonClicked()
{
    QModelIndex     index = m_ui->treeView->selectionModel()->currentIndex();
    QString         filePath = m_filesModel->fileInfo( index ).filePath();

    if ( !m_filesModel->isDir( index ) )
        importMedia( filePath );
    else
        importDir( filePath );
}

262 263
void
ImportController::treeViewClicked( const QModelIndex& index )
Thomas Boquet's avatar
Thomas Boquet committed
264 265 266 267
{
    if ( m_filesModel->isDir( index ) )
    {
        m_currentlyWatchedDir = m_filesModel->filePath( index );
268
        saveCurrentPath();
Thomas Boquet's avatar
Thomas Boquet committed
269 270 271 272
    }
    m_ui->forwardButton->setEnabled( true );
}

273 274
void
ImportController::treeViewDoubleClicked( const QModelIndex& index )
Thomas Boquet's avatar
Thomas Boquet committed
275
{
276 277
    if ( m_filesModel->isDir( index ) == false )
        forwardButtonClicked();
Thomas Boquet's avatar
Thomas Boquet committed
278
}
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
279

280 281
void
ImportController::reject()
282 283
{
    m_preview->stop();
284
    m_mediaListController->clear();
285
    deleteTemporaryMedias();
286
    collapseAllButCurrentPath();
287
    done( Rejected );
288 289
}

290 291
void
ImportController::accept()
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
292
{
293
    m_mediaListController->clear();
294
    m_preview->stop();
295
    collapseAllButCurrentPath();
296 297
    foreach ( Media* media, m_temporaryMedias.values() )
        Library::getInstance()->addMedia( media );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
298
    m_temporaryMedias.clear();
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
299 300
    done( Accepted );
}
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
301

302 303 304 305 306 307 308 309
void
ImportController::deleteTemporaryMedias()
{
    foreach ( Media* media, m_temporaryMedias.values() )
        delete media;
    m_temporaryMedias.clear();
}

310 311 312 313 314 315 316 317 318 319 320 321
void
ImportController::collapseAllButCurrentPath()
{
    m_ui->treeView->collapseAll();
    QStringList paths;
    for ( QDir directory( m_currentlyWatchedDir ); !directory.isRoot(); directory.cdUp() )
        paths.prepend( directory.absolutePath() );
    while ( paths.count() > 0 )
    {
        m_ui->treeView->setCurrentIndex( m_filesModel->index( paths.takeFirst() ) );
        m_ui->treeView->setExpanded( m_ui->treeView->currentIndex() , true );
    }
322
    m_ui->forwardButton->setEnabled( true );
323 324
}

325 326
void
ImportController::mediaDeletion( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
327
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
328 329
    if ( m_temporaryMedias.contains( uuid ) == true )
        delete m_temporaryMedias.take( uuid );
330

Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
331
    if ( uuid == m_currentUuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
332
    {
333
        setUIMetaData( static_cast<Media*>( 0 ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
334
        m_currentUuid = QUuid();
335
        m_preview->stop();
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
336
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
337 338
}

339 340
void
ImportController::clipDeletion( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
341
{
342
    foreach( Media* media, m_temporaryMedias.values() )
343
    {
344
        if ( media != NULL && media->clip( uuid ) )
345 346
            media->removeClip( uuid );
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
347
}
348

349 350
void
ImportController::showClipList( const QUuid& uuid )
351
{
352 353 354
    if ( m_temporaryMedias.contains( uuid ) == false )
        return ;
    Media* media = m_temporaryMedias[uuid];
355
    if ( media->clipsCount() == 0 )
356
        return ;
357

358
    m_clipListController = new MediaListViewController( m_stackNav );
359 360 361 362
    connect( m_clipListController, SIGNAL( clipSelected( const QUuid& ) ),
             this, SLOT( clipSelection( const QUuid& ) ) );
    connect( m_clipListController, SIGNAL( clipDeleted( const QUuid& ) ),
             this, SLOT( clipDeletion( const QUuid& ) ) );
363 364
    foreach ( Clip* clip, media->clips().values() )
        m_clipListController->newClipAdded( clip );
365 366 367 368 369
    if ( !m_currentUuid.isNull() )
        m_savedUuid = m_currentUuid;
    m_stackNav->pushViewController( m_clipListController );
}

370 371
void
ImportController::restoreContext()
372
{
373 374
    qDebug() << "FIXME: update clip count";
    m_currentUuid = m_savedUuid;
375
}
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

void
ImportController::saveCurrentPath()
{
    QSettings s;
    s.setValue( "ImportPreviouslySelectPath", m_currentlyWatchedDir );
    s.sync();
}

void
ImportController::restoreCurrentPath()
{
    QSettings s;
    QVariant path = s.value( "ImportPreviouslySelectPath", QDir::homePath() );
    QFileInfo info = path.toString();
    m_currentlyWatchedDir = info.absoluteFilePath();
}
393 394

void
395
ImportController::mediaLoaded()
396
{
397 398 399 400 401
    ++m_nbMediaLoaded;
    if ( m_nbMediaLoaded == m_nbMediaToLoad )
    {
        m_nbMediaLoaded = 0;
        m_nbMediaToLoad = 0;
402
        m_ui->progressBar->hide();
403 404
    }
    else
405 406 407 408 409
    {
        if ( m_nbMediaToLoad > 3 )
            m_ui->progressBar->show();
        m_ui->progressBar->setValue( m_nbMediaLoaded );
    }
410 411

}
412 413 414 415

void
ImportController::failedToLoad( Media *media )
{
416
    m_ui->errorLabel->setText( tr( "Failed to load %1").arg(
417
            media->fileInfo()->fileName() ) );
418 419 420
    m_ui->errorLabelImg->show();
    m_ui->errorLabel->show();
    QTimer::singleShot( 3000, this, SLOT( hideErrors() ) );
421
    mediaDeletion( media->baseClip()->uuid() );
422
}
423 424 425 426 427 428 429

void
ImportController::hideErrors()
{
    m_ui->errorLabelImg->hide();
    m_ui->errorLabel->hide();
}