ImportController.cpp 14.8 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 33

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

ImportController::ImportController(QWidget *parent) :
    QDialog(parent),
40 41
    m_ui(new Ui::ImportController),
    m_clipListController( 0 ),
42 43 44
    m_controllerSwitched( false ),
    m_nbMediaToLoad( 0 ),
    m_nbMediaLoaded( 0 )
Thomas Boquet's avatar
Thomas Boquet committed
45 46 47 48 49 50
{
    m_ui->setupUi(this);
    m_preview = new PreviewWidget( new ClipRenderer, m_ui->previewContainer );
    m_stackNav = new StackViewController( m_ui->stackViewContainer, false );
    m_mediaListController = new ImportMediaListController( m_stackNav );
    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 64 65

    restoreCurrentPath();

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

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

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
    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() ) );

    connect( this, SIGNAL( mediaSelected( Media* ) ),
             m_preview->getGenericRenderer(), SLOT( setMedia( Media* ) ) );
    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() ) );
102 103 104

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

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

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

129 130
void
ImportController::mediaSelection( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
131
{
132 133 134
    if ( m_mediaListController->contains( uuid ) )
    {
        if ( !m_currentUuid.isNull() && m_mediaListController->contains( m_currentUuid ) )
135 136
            m_mediaListController->cell( m_currentUuid )->setPalette( this->palette() );
        QPalette p = m_mediaListController->cell( uuid )->palette();
137
        p.setColor( QPalette::Window, QColor( Qt::darkBlue ) );
138
        m_mediaListController->cell( uuid )->setPalette( p );
139

140
        setUIMetaData( m_temporaryMedias[uuid] );
141 142 143
        if ( uuid != NULL && uuid != m_currentUuid )
            m_preview->stop();
        m_currentUuid = uuid;
144
        emit mediaSelected( m_temporaryMedias[uuid] );
145
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
146 147
}

148 149
void
ImportController::clipSelection( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
150
{
151
    if ( !m_currentUuid.isNull() && !m_controllerSwitched )
152
        m_clipListController->cell( m_currentUuid )->setPalette( palette() );
153 154
    else
        m_controllerSwitched = false;
155
    QPalette p = m_clipListController->cell( uuid )->palette();
156
    p.setColor( QPalette::Window, QColor( Qt::darkBlue ) );
157
    m_clipListController->cell( uuid )->setPalette( p );
158
    Clip*   clip;
159
    foreach( Media* media, m_temporaryMedias.values() )
160
    {
161 162
        if ( ( clip = media->clip( uuid ) ) != 0 )
            break;
163
    }
164 165
    if ( clip == 0 )
        return ;
166
    setUIMetaData( clip );
167 168 169 170
    if ( uuid != m_currentUuid )
        m_preview->stop();
    emit clipSelected( clip );
    m_currentUuid = uuid;
Thomas Boquet's avatar
Thomas Boquet committed
171 172
}

173
void
174
ImportController::updateMediaRequested( const Media *media )
175
{
176
    if ( m_temporaryMedias.contains( media->uuid() ) == false )
177
        return ;
178
    ImportMediaCellView*    cell = m_mediaListController->cell( media->uuid() );
179 180
    if ( cell == NULL )
        return;
181 182
    cell->setThumbnail( media->snapshot() );
    cell->setLength( media->lengthMS() );
183 184 185 186
}

void
ImportController::setUIMetaData( Media* media )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
187
{
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
188 189 190 191
    if ( media != NULL )
    {
        //Duration
        QTime   duration;
192
        duration = duration.addMSecs( media->lengthMS() );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
193 194
        m_ui->durationValueLabel->setText( duration.toString( "hh:mm:ss" ) );
        //Filename || title
195
        m_ui->nameValueLabel->setText( media->fileInfo()->fileName() );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
196
        m_ui->nameValueLabel->setWordWrap( true );
197
        setWindowTitle( media->fileInfo()->fileName() + " " + tr( "properties" ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
198
        //Resolution
199 200
        m_ui->resolutionValueLabel->setText( QString::number( media->width() )
                                        + " x " + QString::number( media->height() ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
201
        //FPS
202
        m_ui->fpsValueLabel->setText( QString::number( media->fps() ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
203 204 205
    }
    else
    {
206 207 208 209
        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
210
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
211 212
}

213 214
void
ImportController::setUIMetaData( Clip* clip )
215 216
{
    QTime   time;
217
    qint64  length = clip->lengthSecond();
218 219
    time = time.addSecs( length );
    m_ui->durationValueLabel->setText( time.toString( "hh:mm:ss" ) );
220
    m_ui->nameValueLabel->setText( clip->getParent()->fileInfo()->fileName() );
221
    m_ui->nameValueLabel->setWordWrap( true );
222
    setWindowTitle( clip->getParent()->fileInfo()->fileName() + " " +
223
                    tr( "properties" ) );
224 225 226
    m_ui->resolutionValueLabel->setText( QString::number( clip->getParent()->width() )
            + " x " + QString::number( clip->getParent()->height() ) );
    m_ui->fpsValueLabel->setText( QString::number( clip->getParent()->fps() ) );
227
}
Thomas Boquet's avatar
Thomas Boquet committed
228

229
void
230
ImportController::importMedia( const QString &filePath )
Thomas Boquet's avatar
Thomas Boquet committed
231
{
232
    ++m_nbMediaToLoad;
233
    m_ui->progressBar->setMaximum( m_nbMediaToLoad );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
234
    foreach ( Media* media, m_temporaryMedias.values() )
235
        if ( media->fileInfo()->filePath() == filePath )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
236 237 238 239
            return ;
    if ( Library::getInstance()->mediaAlreadyLoaded( filePath ) == true )
        return ;

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
240
    Media*          media = new Media( filePath );
241 242 243 244 245
    connect( media, SIGNAL( metaDataComputed( const Media* ) ),
             this, SLOT( updateMediaRequested( const Media* ) ) );
    connect( media, SIGNAL( snapshotComputed( const Media* ) ),
             this, SLOT( updateMediaRequested( const Media* ) ) );
    connect( media, SIGNAL( snapshotComputed( const Media* ) ),
246
             this, SLOT( mediaLoaded() ) );
247
    m_temporaryMedias[media->uuid()] = media;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
248 249
    MetaDataManager::getInstance()->computeMediaMetadata( media );
    m_mediaListController->addMedia( media );
Thomas Boquet's avatar
Thomas Boquet committed
250 251
}

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
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 );
}

289 290
void
ImportController::treeViewClicked( const QModelIndex& index )
Thomas Boquet's avatar
Thomas Boquet committed
291 292 293 294
{
    if ( m_filesModel->isDir( index ) )
    {
        m_currentlyWatchedDir = m_filesModel->filePath( index );
295
        saveCurrentPath();
Thomas Boquet's avatar
Thomas Boquet committed
296 297 298 299
    }
    m_ui->forwardButton->setEnabled( true );
}

300 301
void
ImportController::treeViewDoubleClicked( const QModelIndex& index )
Thomas Boquet's avatar
Thomas Boquet committed
302
{
303 304
    if ( m_filesModel->isDir( index ) == false )
        forwardButtonClicked();
Thomas Boquet's avatar
Thomas Boquet committed
305
}
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
306

307 308
void
ImportController::reject()
309 310
{
    m_preview->stop();
311
    m_mediaListController->cleanAll();
312
    deleteTemporaryMedias();
313
    collapseAllButCurrentPath();
314
    done( Rejected );
315 316
}

317 318
void
ImportController::accept()
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
319
{
320
    m_mediaListController->cleanAll();
321
    m_preview->stop();
322
    collapseAllButCurrentPath();
323 324
    foreach ( Media* media, m_temporaryMedias.values() )
        Library::getInstance()->addMedia( media );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
325
    m_temporaryMedias.clear();
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
326 327
    done( Accepted );
}
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
328

329 330 331 332 333 334 335 336
void
ImportController::deleteTemporaryMedias()
{
    foreach ( Media* media, m_temporaryMedias.values() )
        delete media;
    m_temporaryMedias.clear();
}

337 338 339 340 341 342 343 344 345 346 347 348
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 );
    }
349
    m_ui->forwardButton->setEnabled( true );
350 351
}

352 353
void
ImportController::mediaDeletion( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
354 355
{
    m_mediaListController->removeMedia( uuid );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
356 357
    if ( m_temporaryMedias.contains( uuid ) == true )
        delete m_temporaryMedias.take( uuid );
358

Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
359
    if ( uuid == m_currentUuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
360
    {
361
        setUIMetaData( static_cast<Media*>( 0 ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
362
        m_currentUuid = QUuid();
363
        m_preview->stop();
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
364
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
365 366
}

367 368
void
ImportController::clipDeletion( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
369
{
370
    m_clipListController->removeClip( uuid );
371
    foreach( Media* media, m_temporaryMedias.values() )
372
    {
373
        if ( media != NULL && media->clip( uuid ) )
374 375
            media->removeClip( uuid );
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
376
}
377

378 379
void
ImportController::showClipList( const QUuid& uuid )
380
{
381 382 383 384
    if ( m_temporaryMedias.contains( uuid ) == false )
        return ;
    Media* media = m_temporaryMedias[uuid];
    if ( media->clips()->size() == 0 )
385
        return ;
386

387
    m_clipListController = new ImportMediaListController( m_stackNav );
388 389 390 391
    connect( m_clipListController, SIGNAL( clipSelected( const QUuid& ) ),
             this, SLOT( clipSelection( const QUuid& ) ) );
    connect( m_clipListController, SIGNAL( clipDeleted( const QUuid& ) ),
             this, SLOT( clipDeletion( const QUuid& ) ) );
392 393 394 395 396 397 398
    m_clipListController->addClipsFromMedia( media );
    if ( !m_currentUuid.isNull() )
        m_savedUuid = m_currentUuid;
    m_controllerSwitched = true;
    m_stackNav->pushViewController( m_clipListController );
}

399 400
void
ImportController::restoreContext()
401
{
402
    if ( m_clipListController->nbDeletions() != 0 )
403
    {
404 405 406 407 408
        if ( !m_savedUuid.isNull() && m_mediaListController->cell( m_savedUuid ) != NULL )
        {
            ImportMediaCellView* cell = m_mediaListController->cell( m_savedUuid );
            cell->decrementClipCount( m_clipListController->nbDeletions() );
        }
409
    }
410 411 412
    if ( !m_savedUuid.isNull() )
        m_currentUuid = m_savedUuid;
    m_controllerSwitched = false;
413
}
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430

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();
}
431 432

void
433
ImportController::mediaLoaded()
434
{
435 436 437 438 439
    ++m_nbMediaLoaded;
    if ( m_nbMediaLoaded == m_nbMediaToLoad )
    {
        m_nbMediaLoaded = 0;
        m_nbMediaToLoad = 0;
440
        m_ui->progressBar->hide();
441 442
    }
    else
443 444 445 446 447
    {
        if ( m_nbMediaToLoad > 3 )
            m_ui->progressBar->show();
        m_ui->progressBar->setValue( m_nbMediaLoaded );
    }
448 449

}
450 451 452 453

void
ImportController::failedToLoad( Media *media )
{
454
    m_ui->errorLabel->setText( tr( "Failed to load %1").arg(
455
            media->fileInfo()->fileName() ) );
456 457 458
    m_ui->errorLabelImg->show();
    m_ui->errorLabel->show();
    QTimer::singleShot( 3000, this, SLOT( hideErrors() ) );
459
    mediaDeletion( media->uuid() );
460
}
461 462 463 464 465 466 467

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