ImportController.cpp 14.6 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>
Thomas Boquet's avatar
Thomas Boquet committed
36 37 38

ImportController::ImportController(QWidget *parent) :
    QDialog(parent),
39 40
    m_ui(new Ui::ImportController),
    m_clipListController( 0 ),
41 42 43
    m_controllerSwitched( false ),
    m_nbMediaToLoad( 0 ),
    m_nbMediaLoaded( 0 )
Thomas Boquet's avatar
Thomas Boquet committed
44 45 46 47 48 49
{
    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 );
50
    m_filesModel = new QFileSystemModel( this );
Thomas Boquet's avatar
Thomas Boquet committed
51 52 53
    m_stackNav->pushViewController( m_mediaListController );

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

    restoreCurrentPath();

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

76
    m_ui->progressBar->setHidden( true );
77

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    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_preview, SIGNAL( addClip( Clip* ) ),
             m_mediaListController, SLOT( clipAdded( Clip* ) ) ); //StackViewController
    connect( m_stackNav, SIGNAL( previousButtonPushed() ),
             this, SLOT( restoreContext() ) );
101 102 103

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

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

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

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

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

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

172
void
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
173
ImportController::updateMediaRequested( Media *media )
174
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
175
    if ( m_temporaryMedias.contains( media->getUuid() ) == false )
176
        return ;
177 178 179 180 181 182 183 184 185
    ImportMediaCellView*    cell = m_mediaListController->cell( media->getUuid() );
    if ( cell == NULL )
        return;
    cell->setThumbnail( media->getSnapshot() );
    cell->setLength( media->getLengthMS() );
}

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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
239 240 241 242 243
    Media*          media = new Media( filePath );
    connect( media, SIGNAL( metaDataComputed( Media* ) ),
             this, SLOT( updateMediaRequested( Media* ) ) );
    connect( media, SIGNAL( snapshotComputed( Media* ) ),
             this, SLOT( updateMediaRequested( Media* ) ) );
244 245
    connect( media, SIGNAL( snapshotComputed( Media* ) ),
             this, SLOT( mediaLoaded() ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
246 247 248
    m_temporaryMedias[media->getUuid()] = media;
    MetaDataManager::getInstance()->computeMediaMetadata( media );
    m_mediaListController->addMedia( media );
Thomas Boquet's avatar
Thomas Boquet committed
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 276 277 278 279 280 281 282 283 284 285 286 287
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 );
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}
449 450 451 452 453 454

void
ImportController::failedToLoad( Media *media )
{
    mediaDeletion( media->getUuid() );
}