massive rewrite of project data system

This commit is contained in:
itsmattkc
2018-12-13 14:29:09 +11:00
parent 6c3197aac6
commit ac1cb9d14f
44 changed files with 2562 additions and 2158 deletions
+48 -57
View File
@@ -2,13 +2,14 @@
#include "project/effect.h"
#include "project/transition.h"
#include "io/media.h"
#include "project/footage.h"
#include "io/config.h"
#include "playback/playback.h"
#include "playback/cacher.h"
#include "panels/project.h"
#include "project/sequence.h"
#include "panels/timeline.h"
#include "project/media.h"
#include "undo.h"
extern "C" {
@@ -35,7 +36,6 @@ Clip::Clip(Sequence* s) :
use_existing_frame(false),
filter_graph(NULL),
fbo(NULL),
texture(NULL),
opts(NULL)
{
pkt = av_packet_alloc();
@@ -55,7 +55,6 @@ Clip* Clip::copy(Sequence* s) {
copy->color_g = color_g;
copy->color_b = color_b;
copy->media = media;
copy->media_type = media_type;
copy->media_stream = media_stream;
copy->autoscale = autoscale;
copy->speed = speed;
@@ -93,29 +92,23 @@ void Clip::reset() {
}
void Clip::reset_audio() {
switch (media_type) {
case MEDIA_TYPE_FOOTAGE:
case MEDIA_TYPE_TONE:
if (media == NULL || media->get_type() == MEDIA_TYPE_FOOTAGE) {
audio_reset = true;
frame_sample_index = -1;
audio_buffer_write = 0;
break;
case MEDIA_TYPE_SEQUENCE:
{
Sequence* nested_sequence = static_cast<Sequence*>(media);
frame_sample_index = -1;
audio_buffer_write = 0;
} else if (media->get_type() == MEDIA_TYPE_SEQUENCE) {
Sequence* nested_sequence = media->to_sequence();
for (int i=0;i<nested_sequence->clips.size();i++) {
Clip* c = nested_sequence->clips.at(i);
if (c != NULL) c->reset_audio();
}
}
break;
}
}
void Clip::refresh() {
// validates media if it was replaced
if (replaced && media_type == MEDIA_TYPE_FOOTAGE) {
Media* m = static_cast<Media*>(media);
if (replaced && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) {
Footage* m = media->to_footage();
media_stream = (track < 0) ? m->video_tracks.at(0)->file_index : m->audio_tracks.at(0)->file_index;
}
replaced = false;
@@ -166,7 +159,7 @@ Clip::~Clip() {
close_clip(this);
// make sure clip has closed before clip is destroyed
if (multithreaded && media_type == MEDIA_TYPE_FOOTAGE) {
if (multithreaded && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) {
cacher->wait();
}
}
@@ -210,36 +203,44 @@ long Clip::getLength() {
return timeline_out - timeline_in;
}
double Clip::getMediaFrameRate() {
Q_ASSERT(track < 0);
if (media != NULL) {
double rate = media->get_frame_rate(media_stream);
if (!qIsNaN(rate)) return rate;
}
if (sequence != NULL) return sequence->frame_rate;
}
void Clip::recalculateMaxLength() {
if (sequence != NULL) {
double fr = this->sequence->frame_rate;
fr /= speed;
switch (media_type) {
case MEDIA_TYPE_FOOTAGE:
{
Media* m = static_cast<Media*>(media);
MediaStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
if (ms != NULL && ms->infinite_length) {
calculated_length = LONG_MAX;
} else {
calculated_length = m->get_length_in_frames(fr);
}
}
break;
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = static_cast<Sequence*>(media);
calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr);
}
break;
/*case MEDIA_TYPE_SOLID:
case MEDIA_TYPE_TONE:*/
default:
calculated_length = LONG_MAX;
break;
}
calculated_length = LONG_MAX;
if (media != NULL) {
switch (media->get_type()) {
case MEDIA_TYPE_FOOTAGE:
{
Footage* m = media->to_footage();
FootageStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
if (ms != NULL && ms->infinite_length) {
calculated_length = LONG_MAX;
} else {
calculated_length = m->get_length_in_frames(fr);
}
}
break;
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = media->to_sequence();
calculated_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, fr);
}
break;
}
}
}
}
@@ -247,28 +248,18 @@ long Clip::getMaximumLength() {
return calculated_length;
}
double Clip::getMediaFrameRate() {
Q_ASSERT(track < 0);
switch (media_type) {
case MEDIA_TYPE_FOOTAGE: return static_cast<Media*>(media)->get_stream_from_file_index(track < 0, media_stream)->video_frame_rate;
case MEDIA_TYPE_SEQUENCE: return static_cast<Sequence*>(media)->frame_rate;
}
if (sequence != NULL) return sequence->frame_rate;
return qSNaN();
}
int Clip::getWidth() {
if (media == NULL && sequence != NULL) return sequence->width;
switch (media_type) {
switch (media->get_type()) {
case MEDIA_TYPE_FOOTAGE:
{
MediaStream* ms = static_cast<Media*>(media)->get_stream_from_file_index(track < 0, media_stream);
FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
if (ms != NULL) return ms->video_width;
if (sequence != NULL) return sequence->width;
}
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = static_cast<Sequence*>(media);
Sequence* s = media->to_sequence();
return s->width;
}
}
@@ -277,16 +268,16 @@ int Clip::getWidth() {
int Clip::getHeight() {
if (media == NULL && sequence != NULL) return sequence->height;
switch (media_type) {
switch (media->get_type()) {
case MEDIA_TYPE_FOOTAGE:
{
MediaStream* ms = static_cast<Media*>(media)->get_stream_from_file_index(track < 0, media_stream);
FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
if (ms != NULL) return ms->video_height;
if (sequence != NULL) return sequence->height;
}
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = static_cast<Sequence*>(media);
Sequence* s = media->to_sequence();
return s->height;
}
}
+5 -5
View File
@@ -13,9 +13,10 @@ class Effect;
class Transition;
class QOpenGLFramebufferObject;
class ComboAction;
class Media;
struct Sequence;
struct Media;
struct MediaStream;
struct Footage;
struct FootageStream;
struct AVFormatContext;
struct AVStream;
@@ -42,9 +43,9 @@ struct Clip
long get_timeline_in_with_transition();
long get_timeline_out_with_transition();
long getLength();
double getMediaFrameRate();
long getMaximumLength();
void recalculateMaxLength();
double getMediaFrameRate();
int getWidth();
int getHeight();
void refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points);
@@ -64,8 +65,7 @@ struct Clip
quint8 color_r;
quint8 color_g;
quint8 color_b;
void* media; // attached media
int media_type;
Media* media;
int media_stream;
double speed;
double cached_fr;
+57
View File
@@ -0,0 +1,57 @@
#include "footage.h"
#include <QDebug>
#include <QtMath>
#include "io/previewgenerator.h"
extern "C" {
#include <libavformat/avformat.h>
}
#include "project/clip.h"
Footage::Footage() : ready(false), preview_gen(NULL), invalid(false), in(0), out(0) {
ready_lock.lock();
}
Footage::~Footage() {
reset();
}
void Footage::reset() {
if (preview_gen != NULL) {
preview_gen->cancel();
preview_gen->wait();
}
for (int i=0;i<video_tracks.size();i++) {
delete video_tracks.at(i);
}
for (int i=0;i<audio_tracks.size();i++) {
delete audio_tracks.at(i);
}
video_tracks.clear();
audio_tracks.clear();
ready = false;
}
long Footage::get_length_in_frames(double frame_rate) {
if (length >= 0) return qFloor(((double) length / (double) AV_TIME_BASE) * frame_rate);
return 0;
}
FootageStream* Footage::get_stream_from_file_index(bool video, int index) {
if (video) {
for (int i=0;i<video_tracks.size();i++) {
if (video_tracks.at(i)->file_index == index) {
return video_tracks.at(i);
}
}
} else {
for (int i=0;i<audio_tracks.size();i++) {
if (audio_tracks.at(i)->file_index == index) {
return audio_tracks.at(i);
}
}
}
return NULL;
}
+63
View File
@@ -0,0 +1,63 @@
#ifndef FOOTAGE_H
#define FOOTAGE_H
#include <QString>
#include <QVector>
#include <QMetaType>
#include <QVariant>
#include <QMutex>
#include <QPixmap>
#define VIDEO_PROGRESSIVE 0
#define VIDEO_TOP_FIELD_FIRST 1
#define VIDEO_BOTTOM_FIELD_FIRST 2
struct Sequence;
struct Clip;
class PreviewGenerator;
class MediaThrobber;
struct FootageStream {
int file_index;
int video_width;
int video_height;
bool infinite_length;
double video_frame_rate;
int video_interlacing;
int video_auto_interlacing;
int audio_channels;
int audio_layout;
int audio_frequency;
// preview thumbnail/waveform
bool preview_done;
QImage video_preview;
QVector<char> audio_preview;
};
struct Footage {
Footage();
~Footage();
QString url;
QString name;
int64_t length;
QVector<FootageStream*> video_tracks;
QVector<FootageStream*> audio_tracks;
int save_id;
bool ready;
bool invalid;
PreviewGenerator* preview_gen;
QMutex ready_lock;
bool using_inout;
long in;
long out;
long get_length_in_frames(double frame_rate);
FootageStream* get_stream_from_file_index(bool video, int index);
void reset();
};
#endif // FOOTAGE_H
+312
View File
@@ -0,0 +1,312 @@
#include "media.h"
#include "footage.h"
#include "sequence.h"
#include "undo.h"
#include "io/config.h"
#include "panels/viewer.h"
#include "debug.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
QString get_interlacing_name(int interlacing) {
switch (interlacing) {
case VIDEO_PROGRESSIVE: return "None (Progressive)";
case VIDEO_TOP_FIELD_FIRST: return "Top Field First";
case VIDEO_BOTTOM_FIELD_FIRST: return "Bottom Field First";
default: return "Invalid";
}
}
QString get_channel_layout_name(int channels, uint64_t layout) {
switch (channels) {
case 0: return "Invalid"; break;
case 1: return "Mono"; break;
case 2: return "Stereo"; break;
default: {
char buf[50];
av_get_channel_layout_string(buf, sizeof(buf), channels, layout);
return QString(buf);
}
}
}
Media::Media(Media* iparent) :
parent(iparent),
throbber(NULL),
root(false),
type(-1)
{}
Media::~Media() {
switch (get_type()) {
case MEDIA_TYPE_FOOTAGE: delete to_footage(); break;
case MEDIA_TYPE_SEQUENCE: if (object != NULL) delete to_sequence(); break;
}
if (throbber != NULL) delete throbber;
qDeleteAll(children);
}
Footage *Media::to_footage() {
return static_cast<Footage*>(object);
}
Sequence *Media::to_sequence() {
return static_cast<Sequence*>(object);
}
void Media::set_footage(Footage *f) {
type = MEDIA_TYPE_FOOTAGE;
object = f;
}
void Media::set_sequence(Sequence *s) {
set_icon(QIcon(":/icons/sequence.png"));
type = MEDIA_TYPE_SEQUENCE;
object = s;
if (s != NULL) update_tooltip();
}
void Media::set_folder() {
if (folder_name.isEmpty()) folder_name = "New Folder";
set_icon(QIcon(":/icons/folder.png"));
type = MEDIA_TYPE_FOLDER;
object = NULL;
}
void Media::set_icon(const QIcon &ico) {
icon = ico;
}
void Media::set_parent(Media *p) {
parent = p;
}
void Media::update_tooltip(const QString& error) {
switch (type) {
case MEDIA_TYPE_FOOTAGE:
{
Footage* f = to_footage();
tooltip = "Name: " + f->name + "\nFilename: " + f->url + "\n";
if (error.isEmpty()) {
if (f->video_tracks.size() > 0) {
tooltip += "Video Dimensions: ";
for (int i=0;i<f->video_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += QString::number(f->video_tracks.at(i)->video_width) + "x" + QString::number(f->video_tracks.at(i)->video_height);
}
tooltip += "\n";
if (!f->video_tracks.at(0)->infinite_length) {
tooltip += "Frame Rate: ";
for (int i=0;i<f->video_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
if (f->video_tracks.at(i)->video_interlacing == VIDEO_PROGRESSIVE) {
tooltip += QString::number(f->video_tracks.at(i)->video_frame_rate);
} else {
tooltip += QString::number(f->video_tracks.at(i)->video_frame_rate * 2);
tooltip += " fields (" + QString::number(f->video_tracks.at(i)->video_frame_rate) + " frames)";
}
}
tooltip += "\n";
}
tooltip += "Interlacing: ";
for (int i=0;i<f->video_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += get_interlacing_name(f->video_tracks.at(i)->video_interlacing);
}
}
if (f->audio_tracks.size() > 0) {
tooltip += "\n";
tooltip += "Audio Frequency: ";
for (int i=0;i<f->audio_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += QString::number(f->audio_tracks.at(i)->audio_frequency);
}
tooltip += "\n";
tooltip += "Audio Channels: ";
for (int i=0;i<f->audio_tracks.size();i++) {
if (i > 0) {
tooltip += ", ";
}
tooltip += get_channel_layout_name(f->audio_tracks.at(i)->audio_channels, f->audio_tracks.at(i)->audio_layout);
}
// tooltip += "\n";
}
} else {
tooltip += error;
}
}
break;
case MEDIA_TYPE_SEQUENCE:
{
Sequence* s = to_sequence();
tooltip = "Name: " + s->name
+ "\nVideo Dimensions: " + QString::number(s->width) + "x" + QString::number(s->height)
+ "\nFrame Rate: " + QString::number(s->frame_rate)
+ "\nAudio Frequency: " + QString::number(s->audio_frequency)
+ "\nAudio Layout: " + get_channel_layout_name(av_get_channel_layout_nb_channels(s->audio_layout), s->audio_layout);
}
break;
}
}
void *Media::to_object() {
return object;
}
int Media::get_type() {
return type;
}
const QString &Media::get_name() {
switch (type) {
case MEDIA_TYPE_FOOTAGE: return to_footage()->name;
case MEDIA_TYPE_SEQUENCE: return to_sequence()->name;
case MEDIA_TYPE_FOLDER: return folder_name;
}
}
void Media::set_name(const QString &n) {
switch (type) {
case MEDIA_TYPE_FOOTAGE: to_footage()->name = n; break;
case MEDIA_TYPE_SEQUENCE: to_sequence()->name = n; break;
case MEDIA_TYPE_FOLDER: folder_name = n; break;
}
}
double Media::get_frame_rate(int stream) {
switch (get_type()) {
case MEDIA_TYPE_FOOTAGE: return to_footage()->get_stream_from_file_index(true, stream)->video_frame_rate;
case MEDIA_TYPE_SEQUENCE: return to_sequence()->frame_rate;
}
return qSNaN();
}
int Media::get_sampling_rate(int stream) {
switch (get_type()) {
case MEDIA_TYPE_FOOTAGE: return to_footage()->get_stream_from_file_index(false, stream)->audio_frequency;
case MEDIA_TYPE_SEQUENCE: return to_sequence()->audio_frequency;
}
return 0;
}
void Media::appendChild(Media *child) {
child->set_parent(this);
children.append(child);
}
bool Media::setData(int col, const QVariant &value) {
if (col == 0) {
QString n = value.toString();
if (!n.isEmpty() && get_name() != n) {
undo_stack.push(new MediaRename(this, value.toString()));
return true;
}
}
return false;
}
Media *Media::child(int row) {
return children.value(row);
}
int Media::childCount() const {
return children.count();
}
int Media::columnCount() const {
return 3;
}
QVariant Media::data(int column, int role) {
switch (role) {
case Qt::DecorationRole:
if (column == 0) {
return icon;
}
break;
case Qt::DisplayRole:
switch (column) {
case 0: return (root) ? "Name" : get_name();
case 1:
if (root) return "Duration";
if (get_type() == MEDIA_TYPE_SEQUENCE) {
Sequence* s = to_sequence();
return frame_to_timecode(s->getEndFrame(), config.timecode_view, s->frame_rate);
}
if (get_type() == MEDIA_TYPE_FOOTAGE) {
Footage* f = to_footage();
double r = 30;
if (f->video_tracks.size() > 0) r = f->video_tracks.at(0)->video_frame_rate;
if (!qIsNull(r)) {
long len = f->get_length_in_frames(r);
if (len > 0) return frame_to_timecode(len, config.timecode_view, r);
}
}
break;
case 2:
if (root) return "Rate";
if (get_type() == MEDIA_TYPE_SEQUENCE) return QString::number(get_frame_rate()) + " FPS";
if (get_type() == MEDIA_TYPE_FOOTAGE) {
Footage* f = to_footage();
if (f->video_tracks.size() > 0) {
double r = get_frame_rate();
if (!qIsNull(r)) return QString::number(get_frame_rate()) + " FPS";
} else if (f->audio_tracks.size() > 0) {
return QString::number(get_sampling_rate()) + " Hz";
}
}
break;
}
break;
case Qt::ToolTipRole:
return tooltip;
}
return QVariant();
}
int Media::row() const {
if (parent) {
return parent->children.indexOf(const_cast<Media*>(this));
}
return 0;
}
Media *Media::parentItem() {
return parent;
}
Media *Media::takeChild(int i) {
Media* ref = children.at(i);
children.removeAt(i);
return ref;
}
void Media::removeChild(Media* m) {
for (int i=0;i<children.size();i++) {
if (children.at(i) == m) {
children.removeAt(i);
return;
}
}
}
+67
View File
@@ -0,0 +1,67 @@
#ifndef MEDIA_H
#define MEDIA_H
#include <QList>
#include <QVariant>
#define MEDIA_TYPE_FOOTAGE 0
#define MEDIA_TYPE_SEQUENCE 1
#define MEDIA_TYPE_FOLDER 2
#define MEDIA_TYPE_SOLID 3
#define MEDIA_TYPE_TONE 4
class Footage;
class MediaThrobber;
struct Sequence;
#include <QIcon>
class Media
{
public:
Media(Media* iparent);
~Media();
Footage *to_footage();
Sequence* to_sequence();
void set_footage(Footage* f);
void set_sequence(Sequence* s);
void set_folder();
void set_icon(const QIcon &ico);
void set_parent(Media* p);
void update_tooltip(const QString& error = 0);
void *to_object();
int get_type();
const QString& get_name();
void set_name(const QString& n);
MediaThrobber* throbber;
double get_frame_rate(int stream = 0);
int get_sampling_rate(int stream = 0);
// item functions
void appendChild(Media *child);
bool setData(int col, const QVariant &value);
Media *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column, int role);
int row() const;
Media *parentItem();
Media* takeChild(int i);
void removeChild(Media* m);
bool root;
int temp_id;
int temp_id2;
private:
int type;
void* object;
// item functions
QList<Media*> children;
Media* parent;
QString folder_name;
QString tooltip;
QIcon icon;
};
#endif // MEDIA_H
+146
View File
@@ -0,0 +1,146 @@
#include "projectmodel.h"
#include "panels/panels.h"
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
#include "project/media.h"
#include "debug.h"
ProjectModel::ProjectModel(QObject *parent) : QAbstractItemModel(parent), root_item(NULL) {
clear();
}
ProjectModel::~ProjectModel() {
destroy_root();
}
void ProjectModel::destroy_root() {
if (panel_sequence_viewer != NULL) panel_sequence_viewer->viewer_widget->delete_function();
if (panel_footage_viewer != NULL) panel_footage_viewer->viewer_widget->delete_function();
if (root_item != NULL) delete root_item;
}
void ProjectModel::clear() {
destroy_root();
root_item = new Media(0);
root_item->root = true;
update_data();
}
Media *ProjectModel::get_root() {
return root_item;
}
QVariant ProjectModel::data(const QModelIndex &index, int role) const {
if (!index.isValid())
return QVariant();
return static_cast<Media*>(index.internalPointer())->data(index.column(), role);
}
Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const {
if (!index.isValid())
return Qt::ItemIsDropEnabled;
return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable;
}
QVariant ProjectModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return root_item->data(section, role);
return QVariant();
}
QModelIndex ProjectModel::index(int row, int column, const QModelIndex &parent) const {
if (!hasIndex(row, column, parent))
return QModelIndex();
Media *parentItem;
if (!parent.isValid())
parentItem = root_item;
else
parentItem = static_cast<Media*>(parent.internalPointer());
Media *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex ProjectModel::parent(const QModelIndex &index) const {
if (!index.isValid())
return QModelIndex();
Media *childItem = static_cast<Media*>(index.internalPointer());
Media *parentItem = childItem->parentItem();
if (parentItem == root_item)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
bool ProjectModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if (role != Qt::EditRole)
return false;
Media *item = static_cast<Media*>(index.internalPointer());
bool result = item->setData(index.column(), value);
if (result)
emit dataChanged(index, index);
return result;
}
int ProjectModel::rowCount(const QModelIndex &parent) const {
Media *parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid()) {
parentItem = root_item;
} else {
parentItem = static_cast<Media*>(parent.internalPointer());
}
return parentItem->childCount();
}
int ProjectModel::columnCount(const QModelIndex &parent) const {
if (parent.isValid())
return static_cast<Media*>(parent.internalPointer())->columnCount();
else
return root_item->columnCount();
}
int ProjectModel::topLevelItemCount() {
return root_item->childCount();
}
Media *ProjectModel::topLevelItem(int i) {
return root_item->child(i);
}
void ProjectModel::addTopLevelItem(Media *m) {
root_item->appendChild(m);
}
Media *ProjectModel::takeTopLevelItem(int i) {
Media* ref = root_item->child(i);
root_item->takeChild(i);
return ref;
}
void ProjectModel::removeTopLevelItem(Media *m) {
root_item->removeChild(m);
}
void ProjectModel::update_data() {
// emit dataChanged();
emit layoutChanged();
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef PROJECTMODEL_H
#define PROJECTMODEL_H
#include <QAbstractItemModel>
class Media;
class ProjectModel : public QAbstractItemModel
{
Q_OBJECT
public:
ProjectModel(QObject* parent = 0);
~ProjectModel() override;
void destroy_root();
void clear();
Media* get_root();
QVariant data(const QModelIndex &index, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
int topLevelItemCount();
Media* topLevelItem(int i);
void addTopLevelItem(Media*);
Media* takeTopLevelItem(int i);
void removeTopLevelItem(Media* m);
void update_data();
private:
Media* root_item;
};
#endif // PROJECTMODEL_H
+66 -100
View File
@@ -15,13 +15,14 @@
#include "ui/sourcetable.h"
#include "project/effect.h"
#include "project/transition.h"
#include "io/media.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;
@@ -169,7 +170,7 @@ void SetTimelineInOutCommand::undo() {
// footage viewer functions
if (seq->wrapper_sequence) {
Media* m = static_cast<Media*>(seq->clips.at(0)->media);
Footage* m = seq->clips.at(0)->media->to_footage();
m->using_inout = old_enabled;
m->in = old_in;
m->out = old_out;
@@ -189,7 +190,7 @@ void SetTimelineInOutCommand::redo() {
// footage viewer functions
if (seq->wrapper_sequence) {
Media* m = static_cast<Media*>(seq->clips.at(0)->media);
Footage* m = seq->clips.at(0)->media->to_footage();
m->using_inout = new_enabled;
m->in = new_in;
m->out = new_out;
@@ -340,7 +341,7 @@ void DeleteTransitionCommand::redo() {
mainWindow->setWindowModified(true);
}
NewSequenceCommand::NewSequenceCommand(QTreeWidgetItem *s, QTreeWidgetItem* iparent) :
NewSequenceCommand::NewSequenceCommand(Media *s, Media* iparent) :
seq(s),
parent(iparent),
done(false),
@@ -353,7 +354,7 @@ NewSequenceCommand::~NewSequenceCommand() {
void NewSequenceCommand::undo() {
if (parent == NULL) {
panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(seq));
project_model.removeTopLevelItem(seq);
} else {
parent->removeChild(seq);
}
@@ -363,45 +364,38 @@ void NewSequenceCommand::undo() {
void NewSequenceCommand::redo() {
if (parent == NULL) {
panel_project->source_table->addTopLevelItem(seq);
project_model.addTopLevelItem(seq);
} else {
parent->addChild(seq);
parent->appendChild(seq);
}
done = true;
mainWindow->setWindowModified(true);
}
AddMediaCommand::AddMediaCommand(QTreeWidgetItem* iitem, QTreeWidgetItem* iparent) :
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) {
panel_project->delete_media(item);
if (item->data(0, Qt::UserRole + 5) != 0) delete reinterpret_cast<MediaThrobber*>(item->data(0, Qt::UserRole + 5).value<quintptr>());
delete item;
}
}
void AddMediaCommand::undo() {
if (parent == NULL) {
panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item));
} else {
parent->removeChild(item);
}
parent->removeChild(item);
done = false;
mainWindow->setWindowModified(old_project_changed);
}
void AddMediaCommand::redo() {
if (parent == NULL) {
panel_project->source_table->addTopLevelItem(item);
} else {
parent->addChild(item);
}
parent->appendChild(item);
project_model.update_data();
/* Here we force the source_table to sort itself.
*
@@ -419,32 +413,33 @@ void AddMediaCommand::redo() {
* I guess I'm "supposed" to use a Model–view–viewmodel 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);
panel_project->source_table->setSortingEnabled(true);*/
done = true;
mainWindow->setWindowModified(true);
}
DeleteMediaCommand::DeleteMediaCommand(QTreeWidgetItem* i) :
DeleteMediaCommand::DeleteMediaCommand(const QModelIndex& i) :
item(i),
parent(i.parent()),
old_project_changed(mainWindow->isWindowModified())
{}
DeleteMediaCommand::~DeleteMediaCommand() {
if (done) {
panel_project->delete_media(item);
if (item->data(0, Qt::UserRole + 5) != 0) delete reinterpret_cast<MediaThrobber*>(item->data(0, Qt::UserRole + 5).value<quintptr>());
delete item;
Media* m = static_cast<Media*>(item.internalPointer());
delete m;
}
}
void DeleteMediaCommand::undo() {
if (parent == NULL) {
panel_project->source_table->addTopLevelItem(item);
Media* m = static_cast<Media*>(item.internalPointer());
if (!parent.isValid()) {
project_model.addTopLevelItem(m);
} else {
parent->addChild(item);
static_cast<Media*>(parent.internalPointer())->appendChild(m);
}
mainWindow->setWindowModified(old_project_changed);
@@ -452,14 +447,14 @@ void DeleteMediaCommand::undo() {
}
void DeleteMediaCommand::redo() {
parent = item->parent();
if (parent == NULL) {
panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item));
Media* m = static_cast<Media*>(item.internalPointer());
if (!parent.isValid()) {
project_model.removeTopLevelItem(m);
} else {
parent->removeChild(item);
static_cast<Media*>(parent.internalPointer())->removeChild(m);
}
project_model.update_data();
mainWindow->setWindowModified(true);
done = true;
}
@@ -601,25 +596,24 @@ void CheckboxCommand::redo() {
mainWindow->setWindowModified(true);
}
ReplaceMediaCommand::ReplaceMediaCommand(QTreeWidgetItem* i, QString s) :
ReplaceMediaCommand::ReplaceMediaCommand(Media* i, QString s) :
item(i),
new_filename(s),
old_project_changed(mainWindow->isWindowModified())
{
media = get_footage_from_tree(item);
old_filename = media->url;
old_filename = item->to_footage()->url;
}
void ReplaceMediaCommand::replace(QString& filename) {
// close any clips currently using this media
QVector<Sequence*> all_sequences = panel_project->list_all_project_sequences();
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);
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 == media && c->open) {
if (c != NULL && c->media == item && c->open) {
close_clip(c);
if (c->media_type == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
c->replaced = true;
}
}
@@ -643,11 +637,9 @@ void ReplaceMediaCommand::redo() {
mainWindow->setWindowModified(true);
}
ReplaceClipMediaCommand::ReplaceClipMediaCommand(void *a, void *b, int c, int d, bool e) :
ReplaceClipMediaCommand::ReplaceClipMediaCommand(Media *a, Media *b, bool e) :
old_media(a),
new_media(b),
old_type(c),
new_type(d),
new_media(b),
preserve_clip_ins(e),
old_project_changed(mainWindow->isWindowModified())
{}
@@ -661,7 +653,7 @@ void ReplaceClipMediaCommand::replace(bool undo) {
Clip* c = clips.at(i);
if (c->open) {
close_clip(c);
if (c->media_type == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
}
if (undo) {
@@ -669,16 +661,14 @@ void ReplaceClipMediaCommand::replace(bool undo) {
c->clip_in = old_clip_ins.at(i);
}
c->media = old_media;
c->media_type = old_type;
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->media_type = new_type;
c->media = new_media;
}
c->replaced = true;
@@ -695,6 +685,7 @@ void ReplaceClipMediaCommand::undo() {
void ReplaceClipMediaCommand::redo() {
replace(false);
update_ui(true);
mainWindow->setWindowModified(true);
}
@@ -737,61 +728,40 @@ MediaMove::MediaMove(SourceTable *s) : table(s), old_project_changed(mainWindow-
void MediaMove::undo() {
for (int i=0;i<items.size();i++) {
if (to == NULL) {
table->takeTopLevelItem(table->indexOfTopLevelItem(items.at(i)));
} else {
to->removeChild(items.at(i));
}
}
for (int i=0;i<items.size();i++) {
if (froms.at(i) == NULL) {
table->addTopLevelItem(items.at(i));
} else {
froms.at(i)->addChild(items.at(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++) {
QTreeWidgetItem* parent = items.at(i)->parent();
Media* parent = items.at(i)->parentItem();
froms[i] = parent;
if (parent == NULL) {
table->takeTopLevelItem(table->indexOfTopLevelItem(items.at(i)));
} else {
parent->removeChild(items.at(i));
}
if (to == NULL) {
table->addTopLevelItem(items.at(i));
} else {
to->addChild(items.at(i));
}
}
for (int i=0;i<items.size();i++) {
if (to == NULL) {
table->addTopLevelItem(items.at(i));
} else {
to->addChild(items.at(i));
}
}
parent->removeChild(items.at(i));
to->appendChild(items.at(i));
}
project_model.update_data();
mainWindow->setWindowModified(true);
}
MediaRename::MediaRename() : done(true), old_project_changed(mainWindow->isWindowModified()) {}
MediaRename::MediaRename(Media* iitem, QString ito) :
item(iitem),
from(iitem->get_name()),
to(ito),
old_project_changed(mainWindow->isWindowModified())
{}
void MediaRename::undo() {
item->setText(0, from);
done = false;
mainWindow->setWindowModified(old_project_changed);
item->set_name(from);
mainWindow->setWindowModified(old_project_changed);
}
void MediaRename::redo() {
if (!done) {
item->setText(0, to);
}
mainWindow->setWindowModified(true);
item->set_name(to);
mainWindow->setWindowModified(true);
}
KeyframeMove::KeyframeMove() : old_project_changed(mainWindow->isWindowModified()) {}
@@ -1138,7 +1108,7 @@ void SetEnableCommand::redo() {
mainWindow->setWindowModified(true);
}
EditSequenceCommand::EditSequenceCommand(QTreeWidgetItem* i, Sequence *s) :
EditSequenceCommand::EditSequenceCommand(Media* i, Sequence *s) :
item(i),
seq(s),
old_project_changed(mainWindow->isWindowModified()),
@@ -1175,11 +1145,8 @@ void EditSequenceCommand::redo() {
}
void EditSequenceCommand::update() {
// update name
item->setText(0, seq->name);
// update tooltip
set_sequence_of_tree(item, seq);
item->set_sequence(seq);
for (int i=0;i<seq->clips.size();i++) {
// TODO shift in/out/clipin points to match new frame rate
@@ -1237,9 +1204,8 @@ void CloseAllClipsCommand::redo() {
closeActiveClips(sequence, true);
}
UpdateFootageTooltip::UpdateFootageTooltip(QTreeWidgetItem *i, Media *m) :
item(i),
media(m)
UpdateFootageTooltip::UpdateFootageTooltip(Media *i) :
item(i)
{}
void UpdateFootageTooltip::undo() {
@@ -1247,7 +1213,7 @@ void UpdateFootageTooltip::undo() {
}
void UpdateFootageTooltip::redo() {
update_footage_tooltip(item, media);
item->update_tooltip();
}
MoveEffectCommand::MoveEffectCommand() :
+31 -36
View File
@@ -1,7 +1,7 @@
#ifndef UNDO_H
#define UNDO_H
class QTreeWidgetItem;
class Media;
class QCheckBox;
class LabelSlider;
class Effect;
@@ -12,7 +12,7 @@ class Transition;
class EffectGizmo;
struct Clip;
struct Sequence;
struct Media;
struct Footage;
struct EffectMeta;
#include "project/marker.h"
@@ -166,39 +166,39 @@ private:
class NewSequenceCommand : public QUndoCommand {
public:
NewSequenceCommand(QTreeWidgetItem *s, QTreeWidgetItem* iparent);
NewSequenceCommand(Media *s, Media* iparent);
~NewSequenceCommand();
void undo();
void redo();
private:
QTreeWidgetItem* seq;
QTreeWidgetItem* parent;
Media* seq;
Media* parent;
bool done;
bool old_project_changed;
};
class AddMediaCommand : public QUndoCommand {
public:
AddMediaCommand(QTreeWidgetItem* iitem, QTreeWidgetItem* iparent);
AddMediaCommand(Media* iitem, Media* iparent);
~AddMediaCommand();
void undo();
void redo();
private:
QTreeWidgetItem* item;
QTreeWidgetItem* parent;
Media* item;
Media* parent;
bool done;
bool old_project_changed;
};
class DeleteMediaCommand : public QUndoCommand {
public:
DeleteMediaCommand(QTreeWidgetItem* i);
DeleteMediaCommand(const QModelIndex& i);
~DeleteMediaCommand();
void undo();
void redo();
private:
QTreeWidgetItem* item;
QTreeWidgetItem* parent;
const QModelIndex& item;
const QModelIndex& parent;
bool old_project_changed;
bool done;
};
@@ -258,29 +258,26 @@ private:
class ReplaceMediaCommand : public QUndoCommand {
public:
ReplaceMediaCommand(QTreeWidgetItem*, QString);
ReplaceMediaCommand(Media*, QString);
void undo();
void redo();
private:
QTreeWidgetItem *item;
Media *item;
QString old_filename;
QString new_filename;
bool old_project_changed;
Media* media;
bool old_project_changed;
void replace(QString& filename);
};
class ReplaceClipMediaCommand : public QUndoCommand {
public:
ReplaceClipMediaCommand(void*, void*, int, int, bool);
ReplaceClipMediaCommand(Media *, Media *, bool);
void undo();
void redo();
QVector<Clip*> clips;
private:
void* old_media;
void* new_media;
int old_type;
int new_type;
Media* old_media;
Media* new_media;
bool preserve_clip_ins;
bool old_project_changed;
QVector<int> old_clip_ins;
@@ -304,27 +301,26 @@ private:
class MediaMove : public QUndoCommand {
public:
MediaMove(SourceTable* s);
QVector<QTreeWidgetItem*> items;
QTreeWidgetItem* to;
QVector<Media*> items;
Media* to;
void undo();
void redo();
private:
QVector<QTreeWidgetItem*> froms;
QVector<Media*> froms;
SourceTable* table;
bool old_project_changed;
};
class MediaRename : public QUndoCommand {
public:
MediaRename();
QTreeWidgetItem* item;
QString from;
QString to;
void undo();
void redo();
MediaRename(Media* iitem, QString to);
void undo();
void redo();
private:
bool done;
bool old_project_changed;
bool old_project_changed;
Media* item;
QString from;
QString to;
};
class KeyframeMove : public QUndoCommand {
@@ -486,7 +482,7 @@ private:
class EditSequenceCommand : public QUndoCommand {
public:
EditSequenceCommand(QTreeWidgetItem *i, Sequence* s);
EditSequenceCommand(Media *i, Sequence* s);
void undo();
void redo();
void update();
@@ -498,7 +494,7 @@ public:
int audio_frequency;
int audio_layout;
private:
QTreeWidgetItem* item;
Media* item;
Sequence* seq;
bool old_project_changed;
@@ -542,12 +538,11 @@ public:
class UpdateFootageTooltip : public QUndoCommand {
public:
UpdateFootageTooltip(QTreeWidgetItem* i, Media* m);
UpdateFootageTooltip(Media* i);
void undo();
void redo();
private:
QTreeWidgetItem* item;
Media* media;
Media* item;
};
class MoveEffectCommand : public QUndoCommand {