ImportController.cpp 14.4 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 45
    m_controllerSwitched( false ),
    m_nbMediaToLoad( 0 ),
    m_nbMediaLoaded( 0 )
Thomas Boquet's avatar
Thomas Boquet committed
46 47 48 49 50 51
{
    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 );
52
    m_filesModel = new QFileSystemModel( this );
Thomas Boquet's avatar
Thomas Boquet committed
53 54 55
    m_stackNav->pushViewController( m_mediaListController );

    QStringList filters;
56 57 58 59
    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
60 61 62
    m_filesModel->sort( 2, Qt::AscendingOrder );
    m_filesModel->sort( 0, Qt::AscendingOrder );
    m_filesModel->setNameFilters( filters );
63
    m_filesModel->setRootPath( "/" );
64
    m_filesModel->setNameFilterDisables( false );
65 66 67

    restoreCurrentPath();

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

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

83 84 85 86 87 88 89
    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() ) );

90 91 92
    connect( m_mediaListController, SIGNAL( mediaSelected( const QUuid& ) ),
             qobject_cast<const ClipRenderer*>( m_preview->getGenericRenderer() ),
             SLOT( setClip( const QUuid& ) ) );
93 94 95 96 97 98 99 100 101 102 103 104
    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() ) );
105 106 107

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

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

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

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

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

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

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

204 205
void
ImportController::setUIMetaData( Clip* clip )
206 207
{
    QTime   time;
208
    qint64  length = clip->lengthSecond();
209 210
    time = time.addSecs( length );
    m_ui->durationValueLabel->setText( time.toString( "hh:mm:ss" ) );
211
    m_ui->nameValueLabel->setText( clip->getParent()->fileInfo()->fileName() );
212
    m_ui->nameValueLabel->setWordWrap( true );
213
    setWindowTitle( clip->getParent()->fileInfo()->fileName() + " " +
214
                    tr( "properties" ) );
215 216 217
    m_ui->resolutionValueLabel->setText( QString::number( clip->getParent()->width() )
            + " x " + QString::number( clip->getParent()->height() ) );
    m_ui->fpsValueLabel->setText( QString::number( clip->getParent()->fps() ) );
218
}
Thomas Boquet's avatar
Thomas Boquet committed
219

220
void
221
ImportController::importMedia( const QString &filePath )
Thomas Boquet's avatar
Thomas Boquet committed
222
{
223
    ++m_nbMediaToLoad;
224
    m_ui->progressBar->setMaximum( m_nbMediaToLoad );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
225
    foreach ( Media* media, m_temporaryMedias.values() )
226
        if ( media->fileInfo()->filePath() == filePath )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
227 228 229 230
            return ;
    if ( Library::getInstance()->mediaAlreadyLoaded( filePath ) == true )
        return ;

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
231
    Media*          media = new Media( filePath );
232
    connect( media, SIGNAL( snapshotComputed( const Media* ) ),
233
             this, SLOT( mediaLoaded() ) );
234
    m_temporaryMedias[media->baseClip()->uuid()] = media;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
235 236
    MetaDataManager::getInstance()->computeMediaMetadata( media );
    m_mediaListController->addMedia( media );
Thomas Boquet's avatar
Thomas Boquet committed
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 262 263 264 265 266 267 268 269 270 271 272 273 274 275
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 );
}

276 277
void
ImportController::treeViewClicked( const QModelIndex& index )
Thomas Boquet's avatar
Thomas Boquet committed
278 279 280 281
{
    if ( m_filesModel->isDir( index ) )
    {
        m_currentlyWatchedDir = m_filesModel->filePath( index );
282
        saveCurrentPath();
Thomas Boquet's avatar
Thomas Boquet committed
283 284 285 286
    }
    m_ui->forwardButton->setEnabled( true );
}

287 288
void
ImportController::treeViewDoubleClicked( const QModelIndex& index )
Thomas Boquet's avatar
Thomas Boquet committed
289
{
290 291
    if ( m_filesModel->isDir( index ) == false )
        forwardButtonClicked();
Thomas Boquet's avatar
Thomas Boquet committed
292
}
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
293

294 295
void
ImportController::reject()
296 297
{
    m_preview->stop();
298
    m_mediaListController->cleanAll();
299
    deleteTemporaryMedias();
300
    collapseAllButCurrentPath();
301
    done( Rejected );
302 303
}

304 305
void
ImportController::accept()
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
306
{
307
    m_mediaListController->cleanAll();
308
    m_preview->stop();
309
    collapseAllButCurrentPath();
310 311
    foreach ( Media* media, m_temporaryMedias.values() )
        Library::getInstance()->addMedia( media );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
312
    m_temporaryMedias.clear();
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
313 314
    done( Accepted );
}
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
315

316 317 318 319 320 321 322 323
void
ImportController::deleteTemporaryMedias()
{
    foreach ( Media* media, m_temporaryMedias.values() )
        delete media;
    m_temporaryMedias.clear();
}

324 325 326 327 328 329 330 331 332 333 334 335
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 );
    }
336
    m_ui->forwardButton->setEnabled( true );
337 338
}

339 340
void
ImportController::mediaDeletion( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
341 342
{
    m_mediaListController->removeMedia( uuid );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
343 344
    if ( m_temporaryMedias.contains( uuid ) == true )
        delete m_temporaryMedias.take( uuid );
345

Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
346
    if ( uuid == m_currentUuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
347
    {
348
        setUIMetaData( static_cast<Media*>( 0 ) );
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
349
        m_currentUuid = QUuid();
350
        m_preview->stop();
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
351
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
352 353
}

354 355
void
ImportController::clipDeletion( const QUuid& uuid )
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
356
{
357
    m_clipListController->removeClip( uuid );
358
    foreach( Media* media, m_temporaryMedias.values() )
359
    {
360
        if ( media != NULL && media->clip( uuid ) )
361 362
            media->removeClip( uuid );
    }
Geoffroy Lacarriere's avatar
Geoffroy Lacarriere committed
363
}
364

365 366
void
ImportController::showClipList( const QUuid& uuid )
367
{
368 369 370
    if ( m_temporaryMedias.contains( uuid ) == false )
        return ;
    Media* media = m_temporaryMedias[uuid];
371
    if ( media->clipsCount() == 0 )
372
        return ;
373

374
    m_clipListController = new ImportMediaListController( m_stackNav );
375 376 377 378
    connect( m_clipListController, SIGNAL( clipSelected( const QUuid& ) ),
             this, SLOT( clipSelection( const QUuid& ) ) );
    connect( m_clipListController, SIGNAL( clipDeleted( const QUuid& ) ),
             this, SLOT( clipDeletion( const QUuid& ) ) );
379 380 381 382 383 384 385
    m_clipListController->addClipsFromMedia( media );
    if ( !m_currentUuid.isNull() )
        m_savedUuid = m_currentUuid;
    m_controllerSwitched = true;
    m_stackNav->pushViewController( m_clipListController );
}

386 387
void
ImportController::restoreContext()
388
{
389
    if ( m_clipListController->nbDeletions() != 0 )
390
    {
391 392
        if ( !m_savedUuid.isNull() && m_mediaListController->cell( m_savedUuid ) != NULL )
        {
393
            MediaCellView*  cell = m_mediaListController->cell( m_savedUuid );
394 395
            cell->decrementClipCount( m_clipListController->nbDeletions() );
        }
396
    }
397 398 399
    if ( !m_savedUuid.isNull() )
        m_currentUuid = m_savedUuid;
    m_controllerSwitched = false;
400
}
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

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();
}
418 419

void
420
ImportController::mediaLoaded()
421
{
422 423 424 425 426
    ++m_nbMediaLoaded;
    if ( m_nbMediaLoaded == m_nbMediaToLoad )
    {
        m_nbMediaLoaded = 0;
        m_nbMediaToLoad = 0;
427
        m_ui->progressBar->hide();
428 429
    }
    else
430 431 432 433 434
    {
        if ( m_nbMediaToLoad > 3 )
            m_ui->progressBar->show();
        m_ui->progressBar->setValue( m_nbMediaLoaded );
    }
435 436

}
437 438 439 440

void
ImportController::failedToLoad( Media *media )
{
441
    m_ui->errorLabel->setText( tr( "Failed to load %1").arg(
442
            media->fileInfo()->fileName() ) );
443 444 445
    m_ui->errorLabelImg->show();
    m_ui->errorLabel->show();
    QTimer::singleShot( 3000, this, SLOT( hideErrors() ) );
446
    mediaDeletion( media->baseClip()->uuid() );
447
}
448 449 450 451 452 453 454

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