ImportController.cpp 14.9 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
    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 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    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() ) );
103 104 105

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

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

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

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

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

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

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

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
241
    Media*          media = new Media( filePath );
242 243 244 245 246
    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* ) ),
247
             this, SLOT( mediaLoaded() ) );
248
    m_temporaryMedias[media->uuid()] = media;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
249 250
    MetaDataManager::getInstance()->computeMediaMetadata( media );
    m_mediaListController->addMedia( media );
Thomas Boquet's avatar
Thomas Boquet committed
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 289
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 );
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}
451 452 453 454

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

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