Files
oak-editor/project/undo.cpp
T

1298 lines
32 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "undo.h"
#include <QTreeWidgetItem>
#include <QMessageBox>
#include <QCheckBox>
#include "project/clip.h"
#include "project/sequence.h"
#include "panels/panels.h"
#include "panels/project.h"
#include "panels/effectcontrols.h"
#include "panels/viewer.h"
#include "panels/timeline.h"
#include "playback/playback.h"
#include "ui/sourcetable.h"
#include "project/effect.h"
#include "project/transition.h"
#include "project/footage.h"
#include "playback/cacher.h"
#include "ui/labelslider.h"
#include "ui/viewerwidget.h"
#include "project/marker.h"
#include "mainwindow.h"
#include "io/clipboard.h"
#include "project/media.h"
#include "debug.h"
QUndoStack undo_stack;
ComboAction::ComboAction() {}
ComboAction::~ComboAction() {
for (int i=0;i<commands.size();i++) {
delete commands.at(i);
}
}
void ComboAction::undo() {
for (int i=commands.size()-1;i>=0;i--) {
commands.at(i)->undo();
}
for (int i=0;i<post_commands.size();i++) {
post_commands.at(i)->undo();
}
}
void ComboAction::redo() {
for (int i=0;i<commands.size();i++) {
commands.at(i)->redo();
}
for (int i=0;i<post_commands.size();i++) {
post_commands.at(i)->redo();
}
}
void ComboAction::append(QUndoCommand* u) {
commands.append(u);
}
void ComboAction::appendPost(QUndoCommand* u) {
post_commands.append(u);
}
MoveClipAction::MoveClipAction(Clip *c, long iin, long iout, long iclip_in, int itrack) :
clip(c),
old_in(c->timeline_in),
old_out(c->timeline_out),
old_clip_in(c->clip_in),
old_track(c->track),
new_in(iin),
new_out(iout),
new_clip_in(iclip_in),
new_track(itrack),
old_project_changed(mainWindow->isWindowModified())
{}
void MoveClipAction::undo() {
clip->timeline_in = old_in;
clip->timeline_out = old_out;
clip->clip_in = old_clip_in;
clip->track = old_track;
mainWindow->setWindowModified(old_project_changed);
}
void MoveClipAction::redo() {
clip->timeline_in = new_in;
clip->timeline_out = new_out;
clip->clip_in = new_clip_in;
clip->track = new_track;
mainWindow->setWindowModified(true);
}
DeleteClipAction::DeleteClipAction(Sequence* s, int clip) :
seq(s),
index(clip),
old_project_changed(mainWindow->isWindowModified())
{}
DeleteClipAction::~DeleteClipAction() {
if (ref != NULL) delete ref;
}
void DeleteClipAction::undo() {
// restore ref to clip
seq->clips[index] = ref;
ref = NULL;
// restore links to this clip
for (int i=linkClipIndex.size()-1;i>=0;i--) {
seq->clips.at(linkClipIndex.at(i))->linked.insert(linkLinkIndex.at(i), index);
}
mainWindow->setWindowModified(old_project_changed);
}
void DeleteClipAction::redo() {
// remove ref to clip
ref = seq->clips.at(index);
if (ref->open) {
close_clip(ref);
}
seq->clips[index] = NULL;
// delete link to this clip
linkClipIndex.clear();
linkLinkIndex.clear();
for (int i=0;i<seq->clips.size();i++) {
Clip* c = seq->clips.at(i);
if (c != NULL) {
for (int j=0;j<c->linked.size();j++) {
if (c->linked.at(j) == index) {
linkClipIndex.append(i);
linkLinkIndex.append(j);
c->linked.removeAt(j);
}
}
}
}
mainWindow->setWindowModified(true);
}
ChangeSequenceAction::ChangeSequenceAction(Sequence* s) :
new_sequence(s)
{}
void ChangeSequenceAction::undo() {
set_sequence(old_sequence);
}
void ChangeSequenceAction::redo() {
old_sequence = sequence;
set_sequence(new_sequence);
}
SetTimelineInOutCommand::SetTimelineInOutCommand(Sequence *s, bool enabled, long in, long out) :
seq(s),
new_enabled(enabled),
new_in(in),
new_out(out),
old_project_changed(mainWindow->isWindowModified())
{}
void SetTimelineInOutCommand::undo() {
seq->using_workarea = old_enabled;
seq->workarea_in = old_in;
seq->workarea_out = old_out;
// footage viewer functions
if (seq->wrapper_sequence) {
Footage* m = seq->clips.at(0)->media->to_footage();
m->using_inout = old_enabled;
m->in = old_in;
m->out = old_out;
}
mainWindow->setWindowModified(old_project_changed);
}
void SetTimelineInOutCommand::redo() {
old_enabled = seq->using_workarea;
old_in = seq->workarea_in;
old_out = seq->workarea_out;
seq->using_workarea = new_enabled;
seq->workarea_in = new_in;
seq->workarea_out = new_out;
// footage viewer functions
if (seq->wrapper_sequence) {
Footage* m = seq->clips.at(0)->media->to_footage();
m->using_inout = new_enabled;
m->in = new_in;
m->out = new_out;
}
mainWindow->setWindowModified(true);
}
AddEffectCommand::AddEffectCommand(Clip* c, Effect* e, const EffectMeta *m) :
clip(c),
meta(m),
ref(e),
done(false),
old_project_changed(mainWindow->isWindowModified())
{}
AddEffectCommand::~AddEffectCommand() {
if (!done && ref != NULL) delete ref;
}
void AddEffectCommand::undo() {
clip->effects.last()->close();
clip->effects.removeLast();
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void AddEffectCommand::redo() {
if (ref == NULL) {
ref = create_effect(clip, meta);
}
clip->effects.append(ref);
done = true;
mainWindow->setWindowModified(true);
}
AddTransitionCommand::AddTransitionCommand(Clip* c, Clip *s, Transition* copy, const EffectMeta *itransition, int itype, int ilength) :
clip(c),
secondary(s),
transition_to_copy(copy),
transition(itransition),
type(itype),
length(ilength),
old_project_changed(mainWindow->isWindowModified())
{}
void AddTransitionCommand::undo() {
clip->sequence->hard_delete_transition(clip, type);
if (secondary != NULL) secondary->sequence->hard_delete_transition(secondary, (type == TA_OPENING_TRANSITION) ? TA_CLOSING_TRANSITION : TA_OPENING_TRANSITION);
if (type == TA_OPENING_TRANSITION) {
clip->opening_transition = old_ptransition;
if (secondary != NULL) secondary->closing_transition = old_stransition;
} else {
clip->closing_transition = old_ptransition;
if (secondary != NULL) secondary->opening_transition = old_stransition;
}
mainWindow->setWindowModified(old_project_changed);
}
void AddTransitionCommand::redo() {
if (type == TA_OPENING_TRANSITION) {
old_ptransition = clip->opening_transition;
clip->opening_transition = (transition_to_copy == NULL) ? create_transition(clip, secondary, transition) : transition_to_copy->copy(clip, NULL);
if (secondary != NULL) {
old_stransition = secondary->closing_transition;
secondary->closing_transition = clip->opening_transition;
}
if (length > 0) {
clip->get_opening_transition()->set_length(length);
}
} else {
old_ptransition = clip->closing_transition;
clip->closing_transition = (transition_to_copy == NULL) ? create_transition(clip, secondary, transition) : transition_to_copy->copy(clip, NULL);
if (secondary != NULL) {
old_stransition = secondary->opening_transition;
secondary->opening_transition = clip->closing_transition;
}
if (length > 0) {
clip->get_closing_transition()->set_length(length);
}
}
mainWindow->setWindowModified(true);
}
ModifyTransitionCommand::ModifyTransitionCommand(Clip* c, int itype, long ilength) :
clip(c),
type(itype),
new_length(ilength),
old_project_changed(mainWindow->isWindowModified())
{}
void ModifyTransitionCommand::undo() {
Transition* t = (type == TA_OPENING_TRANSITION) ? clip->get_opening_transition() : clip->get_closing_transition();
t->set_length(old_length);
mainWindow->setWindowModified(old_project_changed);
}
void ModifyTransitionCommand::redo() {
Transition* t = (type == TA_OPENING_TRANSITION) ? clip->get_opening_transition() : clip->get_closing_transition();
old_length = t->get_true_length();
t->set_length(new_length);
mainWindow->setWindowModified(true);
}
DeleteTransitionCommand::DeleteTransitionCommand(Sequence* s, int transition_index) :
seq(s),
index(transition_index),
transition(NULL),
otc(NULL),
ctc(NULL),
old_project_changed(mainWindow->isWindowModified())
{}
DeleteTransitionCommand::~DeleteTransitionCommand() {
if (transition != NULL) delete transition;
}
void DeleteTransitionCommand::undo() {
seq->transitions[index] = transition;
if (otc != NULL) otc->opening_transition = index;
if (ctc != NULL) ctc->closing_transition = index;
transition = NULL;
mainWindow->setWindowModified(old_project_changed);
}
void DeleteTransitionCommand::redo() {
for (int i=0;i<seq->clips.size();i++) {
Clip* c = seq->clips.at(i);
if (c != NULL) {
if (c->opening_transition == index) {
otc = c;
c->opening_transition = -1;
}
if (c->closing_transition == index) {
ctc = c;
c->closing_transition = -1;
}
}
}
transition = seq->transitions.at(index);
seq->transitions[index] = NULL;
mainWindow->setWindowModified(true);
}
NewSequenceCommand::NewSequenceCommand(Media *s, Media* iparent) :
seq(s),
parent(iparent),
done(false),
old_project_changed(mainWindow->isWindowModified())
{}
NewSequenceCommand::~NewSequenceCommand() {
if (!done) delete seq;
}
void NewSequenceCommand::undo() {
if (parent == NULL) {
project_model.removeTopLevelItem(seq);
} else {
parent->removeChild(seq);
}
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void NewSequenceCommand::redo() {
if (parent == NULL) {
project_model.addTopLevelItem(seq);
} else {
parent->appendChild(seq);
}
done = true;
mainWindow->setWindowModified(true);
}
AddMediaCommand::AddMediaCommand(Media* iitem, Media* iparent) :
item(iitem),
parent(iparent),
done(false),
old_project_changed(mainWindow->isWindowModified())
{
if (parent == NULL) parent = project_model.get_root();
}
AddMediaCommand::~AddMediaCommand() {
if (!done) {
delete item;
}
}
void AddMediaCommand::undo() {
parent->removeChild(item);
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void AddMediaCommand::redo() {
parent->appendChild(item);
project_model.update_data();
/* Here we force the source_table to sort itself.
*
* For some reason, sometimes when you add items to the QTreeWidget,
* (usually upon first import) they appear at the bottom, regardless
* of where they should be placed alphabetically. Then when this
* function is "undone", and it tries to remove this item from the
* QTreeWidget, it immediately sorts and then removes THE WRONG ONE.
* If this happens to be a sequence, the sequence data doesn't save
* and is then lost forever (outside of autorecoveries).
*
* The following 2 lines seem to force the source_table to re-sort
* correctly and therefore works around this problem. But holy shit.
*
* I guess I'm "supposed" to use a Modelviewviewmodel instead,
* which I'll probably have to switch to soon anyway. So perhaps
* this will be a non-issue soon.
panel_project->source_table->setSortingEnabled(false);
panel_project->source_table->setSortingEnabled(true);*/
done = true;
mainWindow->setWindowModified(true);
}
DeleteMediaCommand::DeleteMediaCommand(const QModelIndex& i) :
item(i),
parent(i.parent()),
old_project_changed(mainWindow->isWindowModified())
{}
DeleteMediaCommand::~DeleteMediaCommand() {
if (done) {
Media* m = static_cast<Media*>(item.internalPointer());
delete m;
}
}
void DeleteMediaCommand::undo() {
Media* m = static_cast<Media*>(item.internalPointer());
if (!parent.isValid()) {
project_model.addTopLevelItem(m);
} else {
static_cast<Media*>(parent.internalPointer())->appendChild(m);
}
mainWindow->setWindowModified(old_project_changed);
done = false;
}
void DeleteMediaCommand::redo() {
Media* m = static_cast<Media*>(item.internalPointer());
if (!parent.isValid()) {
project_model.removeTopLevelItem(m);
} else {
static_cast<Media*>(parent.internalPointer())->removeChild(m);
}
project_model.update_data();
mainWindow->setWindowModified(true);
done = true;
}
RippleCommand::RippleCommand(Sequence *s, long ipoint, long ilength) :
seq(s),
point(ipoint),
length(ilength),
old_project_changed(mainWindow->isWindowModified())
{}
void RippleCommand::undo() {
for (int i=0;i<rippled.size();i++) {
Clip* c = rippled.at(i);
c->timeline_in -= length;
c->timeline_out -= length;
}
mainWindow->setWindowModified(old_project_changed);
}
void RippleCommand::redo() {
rippled.clear();
for (int j=0;j<seq->clips.size();j++) {
Clip* c = seq->clips.at(j);
bool found = false;
for (int i=0;i<ignore.size();i++) {
if (ignore.at(i) == c) {
found = true;
break;
}
}
if (!found) {
if (c != NULL && c->timeline_in >= point) {
c->timeline_in += length;
c->timeline_out += length;
rippled.append(c);
}
}
}
mainWindow->setWindowModified(true);
}
AddClipCommand::AddClipCommand(Sequence* s, QVector<Clip*>& add) :
seq(s),
clips(add),
old_project_changed(mainWindow->isWindowModified())
{}
AddClipCommand::~AddClipCommand() {
for (int i=0;i<clips.size();i++) {
delete clips.at(i);
}
for (int i=0;i<undone_clips.size();i++) {
delete undone_clips.at(i);
}
}
void AddClipCommand::undo() {
for (int i=0;i<clips.size();i++) {
Clip* c = seq->clips.last();
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
undone_clips.prepend(c);
if (c->open) close_clip(c);
seq->clips.removeLast();
}
mainWindow->setWindowModified(old_project_changed);
}
void AddClipCommand::redo() {
if (undone_clips.size() > 0) {
for (int i=0;i<undone_clips.size();i++) {
seq->clips.append(undone_clips.at(i));
}
undone_clips.clear();
} else {
int linkOffset = seq->clips.size();
for (int i=0;i<clips.size();i++) {
Clip* original = clips.at(i);
Clip* copy = original->copy(seq);
copy->linked.resize(original->linked.size());
for (int j=0;j<original->linked.size();j++) {
copy->linked[j] = original->linked.at(j) + linkOffset;
}
if (original->opening_transition > -1) copy->opening_transition = original->get_opening_transition()->copy(copy, NULL);
if (original->closing_transition > -1) copy->closing_transition = original->get_closing_transition()->copy(copy, NULL);
seq->clips.append(copy);
}
}
mainWindow->setWindowModified(true);
}
LinkCommand::LinkCommand() : link(true), old_project_changed(mainWindow->isWindowModified()) {}
void LinkCommand::undo() {
for (int i=0;i<clips.size();i++) {
Clip* c = s->clips.at(clips.at(i));
if (link) {
c->linked.clear();
} else {
c->linked = old_links.at(i);
}
}
mainWindow->setWindowModified(old_project_changed);
}
void LinkCommand::redo() {
old_links.clear();
for (int i=0;i<clips.size();i++) {
Clip* c = s->clips.at(clips.at(i));
if (link) {
for (int j=0;j<clips.size();j++) {
if (i != j) {
c->linked.append(clips.at(j));
}
}
} else {
old_links.append(c->linked);
c->linked.clear();
}
}
mainWindow->setWindowModified(true);
}
CheckboxCommand::CheckboxCommand(QCheckBox* b) : box(b), checked(box->isChecked()), done(true), old_project_changed(mainWindow->isWindowModified()) {}
CheckboxCommand::~CheckboxCommand() {}
void CheckboxCommand::undo() {
box->setChecked(!checked);
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void CheckboxCommand::redo() {
if (!done) {
box->setChecked(checked);
}
mainWindow->setWindowModified(true);
}
ReplaceMediaCommand::ReplaceMediaCommand(Media* i, QString s) :
item(i),
new_filename(s),
old_project_changed(mainWindow->isWindowModified())
{
old_filename = item->to_footage()->url;
}
void ReplaceMediaCommand::replace(QString& filename) {
// close any clips currently using this media
QVector<Media*> all_sequences = panel_project->list_all_project_sequences();
for (int i=0;i<all_sequences.size();i++) {
Sequence* s = all_sequences.at(i)->to_sequence();
for (int j=0;j<s->clips.size();j++) {
Clip* c = s->clips.at(j);
if (c != NULL && c->media == item && c->open) {
close_clip(c);
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
c->replaced = true;
}
}
}
// replace media
QStringList files;
files.append(filename);
panel_project->process_file_list(false, files, NULL, item);
}
void ReplaceMediaCommand::undo() {
replace(old_filename);
mainWindow->setWindowModified(old_project_changed);
}
void ReplaceMediaCommand::redo() {
replace(new_filename);
mainWindow->setWindowModified(true);
}
ReplaceClipMediaCommand::ReplaceClipMediaCommand(Media *a, Media *b, bool e) :
old_media(a),
new_media(b),
preserve_clip_ins(e),
old_project_changed(mainWindow->isWindowModified())
{}
void ReplaceClipMediaCommand::replace(bool undo) {
if (!undo) {
old_clip_ins.clear();
}
for (int i=0;i<clips.size();i++) {
Clip* c = clips.at(i);
if (c->open) {
close_clip(c);
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
}
if (undo) {
if (!preserve_clip_ins) {
c->clip_in = old_clip_ins.at(i);
}
c->media = old_media;
} else {
if (!preserve_clip_ins) {
old_clip_ins.append(c->clip_in);
c->clip_in = 0;
}
c->media = new_media;
}
c->replaced = true;
c->refresh();
}
}
void ReplaceClipMediaCommand::undo() {
replace(true);
mainWindow->setWindowModified(old_project_changed);
}
void ReplaceClipMediaCommand::redo() {
replace(false);
update_ui(true);
mainWindow->setWindowModified(true);
}
EffectDeleteCommand::EffectDeleteCommand() : done(false), old_project_changed(mainWindow->isWindowModified()) {}
EffectDeleteCommand::~EffectDeleteCommand() {
if (done) {
for (int i=0;i<deleted_objects.size();i++) {
delete deleted_objects.at(i);
}
}
}
void EffectDeleteCommand::undo() {
for (int i=0;i<clips.size();i++) {
Clip* c = clips.at(i);
c->effects.insert(fx.at(i), deleted_objects.at(i));
}
panel_effect_controls->reload_clips();
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void EffectDeleteCommand::redo() {
deleted_objects.clear();
for (int i=0;i<clips.size();i++) {
Clip* c = clips.at(i);
int fx_id = fx.at(i) - i;
Effect* e = c->effects.at(fx_id);
e->close();
deleted_objects.append(e);
c->effects.removeAt(fx_id);
}
panel_effect_controls->reload_clips();
done = true;
mainWindow->setWindowModified(true);
}
MediaMove::MediaMove(SourceTable *s) : table(s), old_project_changed(mainWindow->isWindowModified()) {}
void MediaMove::undo() {
for (int i=0;i<items.size();i++) {
to->removeChild(items.at(i));
froms.at(i)->appendChild(items.at(i));
}
mainWindow->setWindowModified(old_project_changed);
}
void MediaMove::redo() {
if (to == NULL) to = project_model.get_root();
froms.resize(items.size());
for (int i=0;i<items.size();i++) {
Media* parent = items.at(i)->parentItem();
froms[i] = parent;
parent->removeChild(items.at(i));
to->appendChild(items.at(i));
}
project_model.update_data();
mainWindow->setWindowModified(true);
}
MediaRename::MediaRename(Media* iitem, QString ito) :
item(iitem),
from(iitem->get_name()),
to(ito),
old_project_changed(mainWindow->isWindowModified())
{}
void MediaRename::undo() {
item->set_name(from);
mainWindow->setWindowModified(old_project_changed);
}
void MediaRename::redo() {
item->set_name(to);
mainWindow->setWindowModified(true);
}
KeyframeMove::KeyframeMove() : old_project_changed(mainWindow->isWindowModified()) {}
void KeyframeMove::undo() {
for (int i=0;i<rows.size();i++) {
rows.at(i)->keyframe_times[keyframes.at(i)] -= movement;
}
mainWindow->setWindowModified(old_project_changed);
}
void KeyframeMove::redo() {
for (int i=0;i<rows.size();i++) {
rows.at(i)->keyframe_times[keyframes.at(i)] += movement;
}
mainWindow->setWindowModified(true);
}
KeyframeDelete::KeyframeDelete() :
disable_keyframes_on_row(NULL),
old_project_changed(mainWindow->isWindowModified()),
sorted(false)
{}
void KeyframeDelete::undo() {
if (disable_keyframes_on_row != NULL) disable_keyframes_on_row->setKeyframing(true);
int data_index = deleted_keyframe_data.size()-1;
for (int i=rows.size()-1;i>=0;i--) {
EffectRow* row = rows.at(i);
int keyframe_index = keyframes.at(i);
row->keyframe_times.insert(keyframe_index, deleted_keyframe_times.at(i));
row->keyframe_types.insert(keyframe_index, deleted_keyframe_types.at(i));
for (int j=row->fieldCount()-1;j>=0;j--) {
row->field(j)->keyframe_data.insert(keyframe_index, deleted_keyframe_data.at(data_index));
data_index--;
}
}
mainWindow->setWindowModified(old_project_changed);
}
void KeyframeDelete::redo() {
if (!sorted) {
deleted_keyframe_times.resize(rows.size());
deleted_keyframe_types.resize(rows.size());
deleted_keyframe_data.clear();
}
for (int i=0;i<keyframes.size();i++) {
EffectRow* row = rows.at(i);
int keyframe_index = keyframes.at(i);
if (!sorted) {
deleted_keyframe_times[i] = (row->keyframe_times.at(keyframe_index));
deleted_keyframe_types[i] = (row->keyframe_types.at(keyframe_index));
}
row->keyframe_times.removeAt(keyframe_index);
row->keyframe_types.removeAt(keyframe_index);
for (int j=0;j<row->fieldCount();j++) {
if (!sorted) deleted_keyframe_data.append(row->field(j)->keyframe_data.at(keyframe_index));
row->field(j)->keyframe_data.removeAt(keyframe_index);
}
// correct following indices
if (!sorted) {
for (int j=i+1;j<keyframes.size();j++) {
if (rows.at(j) == row && keyframes.at(j) > keyframe_index) {
keyframes[j]--;
}
}
}
}
if (disable_keyframes_on_row != NULL) disable_keyframes_on_row->setKeyframing(false);
mainWindow->setWindowModified(true);
sorted = true;
}
KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
old_project_changed(mainWindow->isWindowModified()),
row(r),
index(i),
time(t),
just_made_keyframe(justMadeKeyframe),
done(true)
{
enable_keyframes = !row->isKeyframing();
if (index != -1) old_values.resize(row->fieldCount());
new_values.resize(row->fieldCount());
for (int i=0;i<row->fieldCount();i++) {
EffectField* field = row->field(i);
if (index != -1) {
if (field->type == EFFECT_FIELD_DOUBLE) {
old_values[i] = static_cast<LabelSlider*>(field->ui_element)->getPreviousValue();
} else {
old_values[i] = field->keyframe_data.at(index);
}
}
new_values[i] = field->get_current_data();
}
}
void KeyframeSet::undo() {
if (enable_keyframes) row->setKeyframing(false);
bool append = (index == -1 || just_made_keyframe);
if (append) {
row->keyframe_times.removeLast();
row->keyframe_types.removeLast();
}
for (int i=0;i<row->fieldCount();i++) {
if (append) {
row->field(i)->keyframe_data.removeLast();
} else {
row->field(i)->keyframe_data[index] = old_values.at(i);
}
}
mainWindow->setWindowModified(old_project_changed);
done = false;
}
void KeyframeSet::redo() {
bool append = (index == -1 || (just_made_keyframe && !done));
if (append) {
row->keyframe_times.append(time);
row->keyframe_types.append((row->keyframe_types.size() > 0) ? row->keyframe_types.last() : EFFECT_KEYFRAME_LINEAR);
}
for (int i=0;i<row->fieldCount();i++) {
if (append) {
row->field(i)->keyframe_data.append(new_values.at(i));
} else {
row->field(i)->keyframe_data[index] = new_values.at(i);
}
}
row->setKeyframing(true);
mainWindow->setWindowModified(true);
done = true;
}
EffectFieldUndo::EffectFieldUndo(EffectField* f) :
field(f),
done(true),
old_project_changed(mainWindow->isWindowModified())
{
old_val = field->get_previous_data();
new_val = field->get_current_data();
}
void EffectFieldUndo::undo() {
field->set_current_data(old_val);
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void EffectFieldUndo::redo() {
if (!done) {
field->set_current_data(new_val);
}
mainWindow->setWindowModified(true);
}
SetAutoscaleAction::SetAutoscaleAction() :
old_project_changed(mainWindow->isWindowModified())
{}
void SetAutoscaleAction::undo() {
for (int i=0;i<clips.size();i++) {
clips.at(i)->autoscale = !clips.at(i)->autoscale;
}
panel_sequence_viewer->viewer_widget->update();
mainWindow->setWindowModified(old_project_changed);
}
void SetAutoscaleAction::redo() {
for (int i=0;i<clips.size();i++) {
clips.at(i)->autoscale = !clips.at(i)->autoscale;
}
panel_sequence_viewer->viewer_widget->update();
mainWindow->setWindowModified(true);
}
AddMarkerAction::AddMarkerAction(Sequence* s, long t, QString n) :
seq(s),
time(t),
name(n),
old_project_changed(mainWindow->isWindowModified())
{}
void AddMarkerAction::undo() {
if (index == -1) {
seq->markers.removeLast();
} else {
seq->markers[index].name = old_name;
}
mainWindow->setWindowModified(old_project_changed);
}
void AddMarkerAction::redo() {
index = -1;
for (int i=0;i<seq->markers.size();i++) {
if (seq->markers.at(i).frame == time) {
index = i;
break;
}
}
if (index == -1) {
Marker m;
m.frame = time;
seq->markers.append(m);
} else {
old_name = seq->markers.at(index).name;
seq->markers[index].name = name;
}
mainWindow->setWindowModified(true);
}
MoveMarkerAction::MoveMarkerAction(Marker* m, long o, long n) :
marker(m),
old_time(o),
new_time(n),
old_project_changed(mainWindow->isWindowModified())
{}
void MoveMarkerAction::undo() {
marker->frame = old_time;
mainWindow->setWindowModified(old_project_changed);
}
void MoveMarkerAction::redo() {
marker->frame = new_time;
mainWindow->setWindowModified(true);
}
DeleteMarkerAction::DeleteMarkerAction(Sequence* s) :
seq(s),
sorted(false),
old_project_changed(mainWindow->isWindowModified())
{}
void DeleteMarkerAction::undo() {
for (int i=markers.size()-1;i>=0;i--) {
seq->markers.insert(markers.at(i), copies.at(i));
}
mainWindow->setWindowModified(old_project_changed);
}
void DeleteMarkerAction::redo() {
for (int i=0;i<markers.size();i++) {
// correct future removals
if (!sorted) {
copies.append(seq->markers.at(markers.at(i)));
for (int j=i+1;j<markers.size();j++) {
if (markers.at(j) > markers.at(i)) {
markers[j]--;
}
}
}
seq->markers.removeAt(markers.at(i));
}
sorted = true;
mainWindow->setWindowModified(true);
}
SetSpeedAction::SetSpeedAction(Clip* c, double speed) :
clip(c),
old_speed(c->speed),
new_speed(speed),
old_project_changed(mainWindow->isWindowModified())
{}
void SetSpeedAction::undo() {
clip->speed = old_speed;
clip->recalculateMaxLength();
mainWindow->setWindowModified(old_project_changed);
}
void SetSpeedAction::redo() {
clip->speed = new_speed;
clip->recalculateMaxLength();
mainWindow->setWindowModified(true);
}
SetBool::SetBool(bool* b, bool setting) :
boolean(b),
old_setting(*b),
new_setting(setting),
old_project_changed(mainWindow->isWindowModified())
{}
void SetBool::undo() {
*boolean = old_setting;
mainWindow->setWindowModified(old_project_changed);
}
void SetBool::redo() {
*boolean = new_setting;
mainWindow->setWindowModified(true);
}
SetSelectionsCommand::SetSelectionsCommand(Sequence* s) :
seq(s),
done(true),
old_project_changed(mainWindow->isWindowModified())
{}
void SetSelectionsCommand::undo() {
seq->selections = old_data;
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void SetSelectionsCommand::redo() {
if (!done) {
seq->selections = new_data;
done = true;
}
mainWindow->setWindowModified(true);
}
SetEnableCommand::SetEnableCommand(Clip* c, bool enable) :
clip(c),
old_val(c->enabled),
new_val(enable),
old_project_changed(mainWindow->isWindowModified())
{}
void SetEnableCommand::undo() {
clip->enabled = old_val;
mainWindow->setWindowModified(old_project_changed);
}
void SetEnableCommand::redo() {
clip->enabled = new_val;
mainWindow->setWindowModified(true);
}
EditSequenceCommand::EditSequenceCommand(Media* i, Sequence *s) :
item(i),
seq(s),
old_project_changed(mainWindow->isWindowModified()),
old_name(s->name),
old_width(s->width),
old_height(s->height),
old_frame_rate(s->frame_rate),
old_audio_frequency(s->audio_frequency),
old_audio_layout(s->audio_layout)
{}
void EditSequenceCommand::undo() {
seq->name = old_name;
seq->width = old_width;
seq->height = old_height;
seq->frame_rate = old_frame_rate;
seq->audio_frequency = old_audio_frequency;
seq->audio_layout = old_audio_layout;
update();
mainWindow->setWindowModified(old_project_changed);
}
void EditSequenceCommand::redo() {
seq->name = name;
seq->width = width;
seq->height = height;
seq->frame_rate = frame_rate;
seq->audio_frequency = audio_frequency;
seq->audio_layout = audio_layout;
update();
mainWindow->setWindowModified(true);
}
void EditSequenceCommand::update() {
// update tooltip
item->set_sequence(seq);
for (int i=0;i<seq->clips.size();i++) {
// TODO shift in/out/clipin points to match new frame rate
// BUT ALSO copy/paste must need a similar routine, no?
// See if one exists or if you have to make one, make it
// re-usable
seq->clips.at(i)->refresh();
}
if (sequence == seq) {
set_sequence(seq);
}
}
SetInt::SetInt(int* pointer, int new_value) :
p(pointer),
oldval(*pointer),
newval(new_value),
old_project_changed(mainWindow->isWindowModified())
{}
void SetInt::undo() {
*p = oldval;
mainWindow->setWindowModified(old_project_changed);
}
void SetInt::redo() {
*p = newval;
mainWindow->setWindowModified(true);
}
SetString::SetString(QString* pointer, QString new_value) :
p(pointer),
oldval(*pointer),
newval(new_value),
old_project_changed(mainWindow->isWindowModified())
{}
void SetString::undo() {
*p = oldval;
mainWindow->setWindowModified(old_project_changed);
}
void SetString::redo() {
*p = newval;
mainWindow->setWindowModified(true);
}
void CloseAllClipsCommand::undo() {
redo();
}
void CloseAllClipsCommand::redo() {
closeActiveClips(sequence, true);
}
UpdateFootageTooltip::UpdateFootageTooltip(Media *i) :
item(i)
{}
void UpdateFootageTooltip::undo() {
redo();
}
void UpdateFootageTooltip::redo() {
item->update_tooltip();
}
MoveEffectCommand::MoveEffectCommand() :
old_project_changed(mainWindow->isWindowModified())
{}
void MoveEffectCommand::undo() {
clip->effects.move(to, from);
mainWindow->setWindowModified(old_project_changed);
}
void MoveEffectCommand::redo() {
clip->effects.move(from, to);
mainWindow->setWindowModified(true);
}
RemoveClipsFromClipboard::RemoveClipsFromClipboard(int index) :
pos(index),
old_project_changed(mainWindow->isWindowModified()),
done(false)
{}
RemoveClipsFromClipboard::~RemoveClipsFromClipboard() {
if (done) {
delete clip;
}
}
void RemoveClipsFromClipboard::undo() {
clipboard.insert(pos, clip);
done = false;
}
void RemoveClipsFromClipboard::redo() {
clip = static_cast<Clip*>(clipboard.at(pos));
clipboard.removeAt(pos);
done = true;
}
RenameClipCommand::RenameClipCommand() :
old_project_changed(mainWindow->isWindowModified())
{}
void RenameClipCommand::undo() {
for (int i=0;i<clips.size();i++) {
clips.at(i)->name = old_names.at(i);
}
}
void RenameClipCommand::redo() {
old_names.resize(clips.size());
for (int i=0;i<clips.size();i++) {
old_names[i] = clips.at(i)->name;
clips.at(i)->name = new_name;
}
}
SetPointer::SetPointer(void **pointer, void *data) :
p(pointer),
new_data(data),
old_changed(mainWindow->isWindowModified())
{}
void SetPointer::undo() {
*p = old_data;
mainWindow->setWindowModified(old_changed);
}
void SetPointer::redo() {
old_data = *p;
*p = new_data;
mainWindow->setWindowModified(true);
}
void ReloadEffectsCommand::undo() {
redo();
}
void ReloadEffectsCommand::redo() {
panel_effect_controls->reload_clips();
}