Commands.cpp 13 KB
Newer Older
1 2 3
/*****************************************************************************
 * Commands.cpp: Contains all the implementation of VLMC commands.
 *****************************************************************************
4
 * Copyright (C) 2008-2016 VideoLAN
5
 *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
6
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *          Ludovic Fauvet <etix@l0cal.com>
 *
 * 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.
 *****************************************************************************/

24 25 26
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
27

28
#include "Commands.h"
29
#include "Project/Project.h"
30
#include "Main/Core.h"
31
#include "Media/Clip.h"
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
32
#include "Media/Media.h"
33
#include "EffectsEngine/EffectHelper.h"
34 35
#include "Workflow/SequenceWorkflow.h"
#include "Workflow/MainWorkflow.h"
36
#include "AbstractUndoStack.h"
luyikei's avatar
luyikei committed
37
#include "Backend/IFilter.h"
38

39 40 41
Commands::Generic::Generic() :
        m_valid( true )
{
42 43
    //This is connected using a direct connection to ensure the view can be refreshed
    //just after the signal has been emited.
44 45 46

    //FIXME: there is no signal retranslateRequired in QUndoStack class
    //       <3 qt4 connects
47 48
    // connect( Core::instance()->undoStack(), SIGNAL( retranslateRequired() ),
    //          this, SLOT( retranslate() ), Qt::DirectConnection );
49
}
50

51 52 53
void
Commands::Generic::invalidate()
{
54
    setText( tr( "Invalid action" ) );
55
    m_valid = false;
56
    emit invalidated();
57 58 59 60 61 62 63
}

bool
Commands::Generic::isValid() const
{
    return m_valid;
}
64

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
65
#ifndef HAVE_GUI
66 67 68 69 70 71 72 73 74 75 76 77 78
void
Commands::Generic::setText( const QString& text )
{
    m_text = text;
}

QString
Commands::Generic::text() const
{
    return m_text;
}
#endif

79 80 81 82 83 84 85 86 87 88 89 90 91 92
void
Commands::Generic::redo()
{
    if ( m_valid == true )
        internalRedo();
}

void
Commands::Generic::undo()
{
    if ( m_valid == true )
        internalUndo();
}

93 94 95 96 97 98 99
Commands::Clip::Add::Add( std::shared_ptr<SequenceWorkflow> const& workflow,
                          const QUuid& uuid, quint32 trackId, qint32 pos, bool isAudioClip ) :
        m_workflow( workflow ),
        m_uuid( uuid ),
        m_trackId( trackId ),
        m_pos( pos ),
        m_isAudioClip( isAudioClip )
100
{
101
    retranslate();
102 103
}

104 105
void
Commands::Clip::Add::internalRedo()
106
{
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    if ( m_clip )
    {
        auto ret = m_workflow->addClip( m_clip, m_trackId, m_pos );
        if ( ret == true )
            emit Core::instance()->workflow()->clipAdded( m_clip->uuid().toString() );
        else
            invalidate();
    }
    else
    {
        auto ret = m_workflow->addClip( m_uuid, m_trackId, m_pos, m_isAudioClip );
        if ( QUuid( ret ).isNull() == false )
        {
            m_clip = m_workflow->clip( ret );
            emit Core::instance()->workflow()->clipAdded( ret );
        }
        else
            invalidate();
    }
126 127
}

128 129
void
Commands::Clip::Add::internalUndo()
130
{
131 132 133 134 135
    m_clip = m_workflow->removeClip( m_uuid );
    if ( m_clip )
        emit Core::instance()->workflow()->clipRemoved( m_uuid.toString() );
    else
        invalidate();
136 137
}

138 139 140
void
Commands::Clip::Add::retranslate()
{
141
    setText( tr( "Adding clip to track %1" ).arg( m_trackId ) );
142 143
}

144 145 146 147 148
std::shared_ptr<Clip>
Commands::Clip::Add::newClip()
{
    return m_clip;
}
149

150 151 152 153 154 155 156 157 158
Commands::Clip::Move::Move(  std::shared_ptr<SequenceWorkflow> const& workflow,
                             const QString& uuid, quint32 trackId, qint64 pos ) :
    m_workflow( workflow ),
    //We have to find an actual clip to ensure that it exists
    m_clip( workflow->clip( uuid ) ),
    m_newTrackId( trackId ),
    m_oldTrackId( workflow->trackId( uuid ) ),
    m_newPos( pos ),
    m_oldPos( workflow->position( uuid ) )
159
{
160 161 162 163 164 165
    retranslate();
}

void
Commands::Clip::Move::retranslate()
{
166
    if ( m_oldTrackId != m_newTrackId )
167
        setText( tr( "Moving clip from track %1 to %2" ).arg(
168
                QString::number( m_oldTrackId ), QString::number( m_newTrackId ) ) );
169 170
    else
        setText( QObject::tr( "Moving clip" ) );
171 172
}

173 174
void
Commands::Clip::Move::internalRedo()
175
{
176
    if ( !m_clip )
177
    {
178 179
        invalidate();
        return;
180
    }
181 182 183
    auto ret = m_workflow->moveClip( m_clip->uuid(), m_newTrackId, m_newPos );
    if ( ret == true )
        emit Core::instance()->workflow()->clipMoved( m_clip->uuid().toString() );
184
    else
185
        invalidate();
186 187
}

188 189
void
Commands::Clip::Move::internalUndo()
190
{
191
    if ( !m_clip )
192
    {
193 194
        invalidate();
        return;
195
    }
196 197 198
    auto ret = m_workflow->moveClip( m_clip->uuid(), m_oldTrackId, m_oldPos );
    if ( ret == true )
        emit Core::instance()->workflow()->clipMoved( m_clip->uuid().toString() );
199
    else
200
        invalidate();
201 202
}

203 204 205 206 207 208
Commands::Clip::Remove::Remove( std::shared_ptr<SequenceWorkflow> const& workflow,
                                const QUuid& uuid ) :
        m_workflow( workflow ),
        m_clip( workflow->clip( uuid ) ),
        m_trackId( workflow->trackId( uuid ) ),
        m_pos( workflow->position( uuid ) )
209
{
210
    retranslate();
211
}
212

213 214 215 216 217 218 219 220
void
Commands::Clip::Remove::retranslate()
{
   setText( tr( "Removing clip " ) );
}

void
Commands::Clip::Remove::internalRedo()
221
{
222 223 224 225 226 227 228 229 230 231
    if ( !m_clip )
    {
        invalidate();
        return;
    }
    m_clip = m_workflow->removeClip( m_clip->uuid() );
    if ( m_clip )
        emit Core::instance()->workflow()->clipRemoved( m_clip->uuid().toString() );
    else
        invalidate();
232
}
233

234 235
void
Commands::Clip::Remove::internalUndo()
236
{
237 238 239 240 241 242 243 244 245 246
    if ( !m_clip )
    {
        invalidate();
        return;
    }
    auto ret = m_workflow->addClip( m_clip, m_trackId, m_pos );
    if ( ret == true )
        emit Core::instance()->workflow()->clipAdded( m_clip->uuid().toString() );
    else
        invalidate();
247 248
}

249 250 251 252
Commands::Clip::Resize::Resize( std::shared_ptr<SequenceWorkflow> const& workflow,
                                const QUuid& uuid, qint64 newBegin, qint64 newEnd, qint64 newPos ) :
    m_workflow( workflow ),
    m_clip( workflow->clip( uuid ) ),
253
    m_newBegin( newBegin ),
254
    m_newEnd( newEnd ),
255
    m_newPos( newPos )
256
{
257 258 259 260 261 262 263 264 265
    if ( !m_clip )
    {
        invalidate();
        retranslate();
        return;
    }
    m_oldBegin = m_clip->begin();
    m_oldEnd = m_clip->end();
    m_oldPos = workflow->trackId( uuid );
266 267 268 269 270 271 272
    retranslate();
}

void
Commands::Clip::Resize::retranslate()
{
    setText( tr( "Resizing clip" ) );
273 274
}

275 276
void
Commands::Clip::Resize::internalRedo()
277
{
278 279 280 281 282
    bool ret = m_workflow->resizeClip( m_clip->uuid(), m_newBegin, m_newEnd, m_newPos );
    if ( ret == true )
        emit Core::instance()->workflow()->clipResized( m_clip->uuid().toString() );
    else
        invalidate();
283 284
}

285 286
void
Commands::Clip::Resize::internalUndo()
287
{
288 289 290 291 292
    bool ret = m_workflow->resizeClip( m_clip->uuid(), m_oldBegin, m_oldEnd, m_oldPos );
    if ( ret == true )
        emit Core::instance()->workflow()->clipResized( m_clip->uuid().toString() );
    else
        invalidate();
293
}
294

295 296 297 298 299
Commands::Clip::Split::Split( std::shared_ptr<SequenceWorkflow> const& workflow,
                              const QUuid& uuid, qint64 newClipPos, qint64 newClipBegin ) :
    m_workflow( workflow ),
    m_toSplit( workflow->clip( uuid ) ),
    m_trackId( workflow->trackId( uuid ) ),
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
300
    m_newClip( nullptr ),
301
    m_newClipPos( newClipPos ),
302
    m_newClipBegin( newClipBegin )
303
{
304 305 306 307 308 309
    if ( !m_toSplit )
    {
        invalidate();
        retranslate();
        return;
    }
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
310 311
    m_newClip = std::shared_ptr<::Clip>( m_toSplit->media()->cut( newClipBegin - m_toSplit->begin(),
                                                                  m_toSplit->end() - m_toSplit->begin() ) );
312
    m_oldEnd = m_toSplit->end();
313
    retranslate();
314 315
}

316 317 318 319 320 321 322 323
void
Commands::Clip::Split::retranslate()
{
    setText( tr("Splitting clip") );
}

void
Commands::Clip::Split::internalRedo()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
324
{
luyikei's avatar
luyikei committed
325 326 327 328 329
    if ( !m_toSplit )
    {
        invalidate();
        return;
    }
330 331
    //If we don't remove 1, the clip will end exactly at the starting frame (ie. they will
    //be rendering at the same time)
luyikei's avatar
luyikei committed
332 333 334
    bool ret = m_workflow->resizeClip( m_toSplit->uuid(), m_toSplit->begin(),
                                       m_newClipBegin - 1, m_workflow->position( m_toSplit->uuid() ) );
    if ( ret == false )
335 336 337 338
    {
        invalidate();
        return;
    }
luyikei's avatar
luyikei committed
339 340

    ret = m_workflow->addClip( m_newClip, m_trackId, m_newClipPos );
341 342 343 344 345
    if ( ret == true )
        emit Core::instance()->workflow()->clipAdded( m_newClip->uuid().toString() );
    else
        invalidate();
    emit Core::instance()->workflow()->clipResized( m_toSplit->uuid().toString() );
346 347
}

348 349
void
Commands::Clip::Split::internalUndo()
350
{
351 352 353 354 355 356
    m_newClip = m_workflow->removeClip( m_newClip->uuid() );
    if ( !m_newClip )
    {
        invalidate();
        return;
    }
luyikei's avatar
luyikei committed
357 358 359 360 361
    else
        emit Core::instance()->workflow()->clipRemoved( m_newClip->uuid().toString() );
    m_workflow->resizeClip( m_toSplit->uuid(), m_toSplit->begin(),
                            m_oldEnd, m_workflow->position( m_toSplit->uuid() ) );
    emit Core::instance()->workflow()->clipResized( m_toSplit->uuid().toString() );
362
}
363

364 365 366 367
Commands::Clip::Link::Link( std::shared_ptr<SequenceWorkflow> const& workflow,
                            const QUuid& clipA, const QUuid& clipB )
    : m_workflow( workflow )
    , m_clipA( clipA )
luyikei's avatar
luyikei committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381
    , m_clipB( clipB )
{
    retranslate();
}

void
Commands::Clip::Link::retranslate()
{
    setText( tr( "Linking clip" ) );
}

void
Commands::Clip::Link::internalRedo()
{
382 383 384 385 386
    auto ret = m_workflow->linkClips( m_clipA, m_clipB );
    if ( ret == true )
        emit Core::instance()->workflow()->clipLinked( m_clipA.toString(), m_clipB.toString() );
    else
        invalidate();
luyikei's avatar
luyikei committed
387 388 389 390 391
}

void
Commands::Clip::Link::internalUndo()
{
392 393 394 395 396
    auto ret = m_workflow->unlinkClips( m_clipA, m_clipB );
    if ( ret == true )
        emit Core::instance()->workflow()->clipUnlinked( m_clipA.toString(), m_clipB.toString() );
    else
        invalidate();
luyikei's avatar
luyikei committed
397 398
}

luyikei's avatar
luyikei committed
399
Commands::Effect::Add::Add( std::shared_ptr<EffectHelper> const& helper, Backend::IInput* target )
luyikei's avatar
luyikei committed
400 401
    : m_helper( helper )
    , m_target( target )
402
{
403 404 405 406 407 408
    retranslate();
}

void
Commands::Effect::Add::retranslate()
{
409
    setText( tr( "Adding effect %1" ).arg( QString::fromStdString( m_helper->filterInfo()->name() ) ) );
410 411 412
}

void
413
Commands::Effect::Add::internalRedo()
414
{
luyikei's avatar
luyikei committed
415
    m_target->attach( *m_helper->filter() );
416 417 418
}

void
419
Commands::Effect::Add::internalUndo()
420
{
luyikei's avatar
luyikei committed
421
    m_target->detach( *m_helper->filter() );
422 423
}

luyikei's avatar
luyikei committed
424
Commands::Effect::Move::Move( std::shared_ptr<EffectHelper> const& helper, std::shared_ptr<Backend::IInput> const& from, Backend::IInput* to,
luyikei's avatar
luyikei committed
425 426 427 428 429
                              qint64 pos)
    : m_helper( helper )
    , m_from( from )
    , m_to( to )
    , m_newPos( pos )
430 431
{
    m_oldPos = helper->begin();
432
    m_oldEnd = helper->end();
luyikei's avatar
luyikei committed
433
    m_newEnd = helper->end() - helper->begin() + pos;
434 435 436 437 438 439
    retranslate();
}

void
Commands::Effect::Move::retranslate()
{
440
    setText( tr( "Moving effect %1" ).arg( QString::fromStdString( m_helper->filterInfo()->name() ) ) );
441 442 443
}

void
444
Commands::Effect::Move::internalRedo()
445
{
luyikei's avatar
luyikei committed
446
    if ( m_from->sameClip( *m_to ) == false )
447
    {
luyikei's avatar
luyikei committed
448 449
        m_from->detach( *m_helper->filter() );
        m_to->attach( *m_helper->filter() );
luyikei's avatar
luyikei committed
450
        m_helper->setBoundaries( m_newPos, m_newEnd );
451

452 453
    }
    else
luyikei's avatar
luyikei committed
454
        m_helper->setBoundaries( m_newPos, m_newEnd );
455 456 457
}

void
458
Commands::Effect::Move::internalUndo()
459
{
luyikei's avatar
luyikei committed
460
    if ( m_from->sameClip( *m_to ) == false )
461
    {
luyikei's avatar
luyikei committed
462 463
        m_to->detach( *m_helper->filter() );
        m_from->attach( *m_helper->filter() );
luyikei's avatar
luyikei committed
464
        m_helper->setBoundaries( m_oldPos, m_oldEnd );
465 466
    }
    else
luyikei's avatar
luyikei committed
467
        m_helper->setBoundaries( m_oldPos, m_oldEnd );
468
}
469

470
Commands::Effect::Resize::Resize( std::shared_ptr<EffectHelper> const& helper, qint64 newBegin, qint64 newEnd )
luyikei's avatar
luyikei committed
471 472 473
    : m_helper( helper )
    , m_newBegin( newBegin )
    , m_newEnd( newEnd )
474 475 476
{
    m_oldBegin = helper->begin();
    m_oldEnd = helper->end();
477 478 479 480 481 482
    retranslate();
}

void
Commands::Effect::Resize::retranslate()
{
483
    setText( tr( "Resizing effect %1" ).arg( QString::fromStdString( m_helper->filterInfo()->name() ) ) );
484 485 486
}

void
487
Commands::Effect::Resize::internalRedo()
488 489 490 491 492
{
    m_helper->setBoundaries( m_newBegin, m_newEnd );
}

void
493
Commands::Effect::Resize::internalUndo()
494 495 496
{
    m_helper->setBoundaries( m_oldBegin, m_oldEnd );
}
497

498
Commands::Effect::Remove::Remove( std::shared_ptr<EffectHelper> const& helper )
luyikei's avatar
luyikei committed
499
    : m_helper( helper )
500
    , m_target( helper->filter()->input() )
501
{
luyikei's avatar
luyikei committed
502

503 504 505 506 507
}

void
Commands::Effect::Remove::retranslate()
{
508
    setText( tr( "Deleting effect %1" ).arg( QString::fromStdString( m_helper->filterInfo()->name() ) ) );
509 510 511
}

void
512
Commands::Effect::Remove::internalRedo()
513
{
luyikei's avatar
luyikei committed
514
    m_target->detach( *m_helper->filter() );
515 516 517
}

void
518
Commands::Effect::Remove::internalUndo()
519
{
520
    m_helper->setTarget( m_target.get() );
521
}