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

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

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

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
230
    Media*          media = new Media( filePath );
231
    connect( media, SIGNAL( snapshotComputed( const Media* ) ),
232
             this, SLOT( mediaLoaded() ) );
233
    m_temporaryMedias[media->baseClip()->uuid()] = media;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
234
235
    MetaDataManager::getInstance()->computeMediaMetadata( media );
    m_mediaListController->addMedia( media );
Thomas Boquet's avatar
Thomas Boquet committed
236
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
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 );
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}
436
437
438
439

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

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