ImportController.cpp 15 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    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() ) );
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
    if ( m_mediaListController->contains( uuid ) )
    {
        if ( !m_currentUuid.isNull() && m_mediaListController->contains( m_currentUuid ) )
137
138
            m_mediaListController->cell( m_currentUuid )->setPalette( this->palette() );
        QPalette p = m_mediaListController->cell( uuid )->palette();
139
        p.setColor( QPalette::Window, QColor( Qt::darkBlue ) );
140
        m_mediaListController->cell( uuid )->setPalette( p );
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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();
}
434
435

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

}
453
454
455
456

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

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