From 72fe20d857e858d8b9f845c6367737fb24e1352a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Mon, 5 Nov 2018 20:07:43 +1100 Subject: [PATCH] ACTUALLY fixed urgent sequence deletion bug --- io/media.cpp | 5 ++++- io/media.h | 2 ++ io/previewgenerator.cpp | 23 ++++++++++++++--------- panels/project.cpp | 21 +++++++++++++-------- panels/project.h | 4 ++-- panels/project.ui | 3 --- project/undo.cpp | 36 +++++++++++++++++++++++++++++++++--- ui/sourcetable.cpp | 1 + ui/timelinewidget.cpp | 2 +- 9 files changed, 70 insertions(+), 27 deletions(-) diff --git a/io/media.cpp b/io/media.cpp index f2b3f55de..d2293f399 100644 --- a/io/media.cpp +++ b/io/media.cpp @@ -10,7 +10,7 @@ extern "C" { #include "project/clip.h" -Media::Media() : ready(false), preview_gen(NULL) { +Media::Media() : ready(false), preview_gen(NULL), throbber(NULL) { ready_lock.lock(); } @@ -23,6 +23,9 @@ void Media::reset() { preview_gen->cancel(); preview_gen->wait(); } + if (throbber != NULL) { + delete throbber; + } for (int i=0;istreams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { AVCodec* codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id); - codec_ctx[i] = avcodec_alloc_context3(codec); - avcodec_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar); - avcodec_open2(codec_ctx[i], codec, NULL); - if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec_ctx[i]->channel_layout == 0) { - codec_ctx[i]->channel_layout = av_get_default_channel_layout(fmt_ctx->streams[i]->codecpar->channels); - } + if (codec != NULL) { + codec_ctx[i] = avcodec_alloc_context3(codec); + avcodec_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar); + avcodec_open2(codec_ctx[i], codec, NULL); + if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec_ctx[i]->channel_layout == 0) { + codec_ctx[i]->channel_layout = av_get_default_channel_layout(fmt_ctx->streams[i]->codecpar->channels); + } + } } - } + } + AVPacket* packet = av_packet_alloc(); bool done = true; bool end_of_file = false; - // get the ball rolling - av_read_frame(fmt_ctx, packet); + // get the ball rolling + do { + av_read_frame(fmt_ctx, packet); + } while (codec_ctx[packet->stream_index] == NULL); avcodec_send_packet(codec_ctx[packet->stream_index], packet); while (!end_of_file) { diff --git a/panels/project.cpp b/panels/project.cpp index 29203f305..740df78db 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -198,7 +198,8 @@ void Project::new_sequence(ComboAction *ca, Sequence *s, bool open, QTreeWidgetI void Project::start_preview_generator(QTreeWidgetItem* item, Media* media, bool replacing) { // set up throbber animation - MediaThrobber* throbber = new MediaThrobber(item); + MediaThrobber* throbber = new MediaThrobber(item); + item->setData(0, Qt::UserRole + 5, reinterpret_cast(throbber)); PreviewGenerator* pg = new PreviewGenerator(item, media, replacing); media->preview_gen = pg; @@ -212,6 +213,7 @@ QString Project::get_file_name_from_path(const QString& path) { QTreeWidgetItem* Project::new_item() { QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setData(0, Qt::UserRole + 5, NULL); item->setFlags(item->flags() | Qt::ItemIsEditable); return item; } @@ -425,7 +427,6 @@ void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetI // check file extension (assume it's not a int lastcharindex = file.lastIndexOf("."); - dout << "INFO:" << file << lastcharindex; bool found = true; if (lastcharindex != -1 && lastcharindex > file.lastIndexOf('/')) { // image_sequence_formats @@ -441,6 +442,8 @@ void Project::process_file_list(bool recursive, QStringList& files, QTreeWidgetI lastcharindex = file.length(); } + if (lastcharindex == 0) lastcharindex++; + if (found && file[lastcharindex-1].isDigit()) { bool is_img_sequence = false; @@ -696,6 +699,7 @@ void Project::clear() { while (ui->treeWidget->topLevelItemCount() > 0) { QTreeWidgetItem* item = ui->treeWidget->topLevelItem(0); if (get_type_from_tree(item) != MEDIA_TYPE_SEQUENCE) delete_media(item); // already deleted + if (item->data(0, Qt::UserRole + 5) != NULL) delete reinterpret_cast(item->data(0, Qt::UserRole + 5).value()); delete item; } } @@ -1440,7 +1444,7 @@ QVector Project::list_all_project_sequences() { #define THROBBER_LIMIT 20 #define THROBBER_SIZE 50 -MediaThrobber::MediaThrobber(QTreeWidgetItem* i) : pixmap(":/icons/throbber.png"), animation(0), item(i) { +MediaThrobber::MediaThrobber(QTreeWidgetItem *i) : pixmap(":/icons/throbber.png"), animation(0), item(i) { // set up throbber animation_update(); animator.setInterval(20); @@ -1452,17 +1456,17 @@ void MediaThrobber::animation_update() { if (animation == THROBBER_LIMIT) { animation = 0; } - item->setIcon(0, QIcon(pixmap.copy(THROBBER_SIZE*animation, 0, THROBBER_SIZE, THROBBER_SIZE))); - animation++; + item->setIcon(0, QIcon(pixmap.copy(THROBBER_SIZE*animation, 0, THROBBER_SIZE, THROBBER_SIZE))); + animation++; } void MediaThrobber::stop(int icon_type, bool replace) { animator.stop(); switch (icon_type) { - case ICON_TYPE_VIDEO: item->setIcon(0, QIcon(":/icons/videosource.png")); break; - case ICON_TYPE_AUDIO: item->setIcon(0, QIcon(":/icons/audiosource.png")); break; - case ICON_TYPE_ERROR: item->setIcon(0, QIcon::fromTheme("dialog-error")); break; + case ICON_TYPE_VIDEO: item->setIcon(0, QIcon(":/icons/videosource.png")); break; + case ICON_TYPE_AUDIO: item->setIcon(0, QIcon(":/icons/audiosource.png")); break; + case ICON_TYPE_ERROR: item->setIcon(0, QIcon::fromTheme("dialog-error")); break; } // refresh all clips @@ -1481,6 +1485,7 @@ void MediaThrobber::stop(int icon_type, bool replace) { update_ui(replace); panel_project->source_table->viewport()->update(); + item->setData(0, Qt::UserRole + 5, NULL); deleteLater(); } diff --git a/panels/project.h b/panels/project.h index a642b2b30..03da87be4 100644 --- a/panels/project.h +++ b/panels/project.h @@ -108,7 +108,7 @@ private slots: class MediaThrobber : public QObject { Q_OBJECT public: - MediaThrobber(QTreeWidgetItem*); + MediaThrobber(QTreeWidgetItem*); public slots: void stop(int, bool replace); private slots: @@ -116,7 +116,7 @@ private slots: private: QPixmap pixmap; int animation; - QTreeWidgetItem* item; + QTreeWidgetItem* item; QTimer animator; }; diff --git a/panels/project.ui b/panels/project.ui index 84ca9eb7b..025479f87 100644 --- a/panels/project.ui +++ b/panels/project.ui @@ -59,9 +59,6 @@ true - - true - false diff --git a/project/undo.cpp b/project/undo.cpp index 415f2d853..999b8ccbb 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -21,6 +21,7 @@ #include "ui/viewerwidget.h" #include "project/marker.h" #include "mainwindow.h" +#include "debug.h" QUndoStack undo_stack; @@ -350,13 +351,24 @@ AddMediaCommand::AddMediaCommand(QTreeWidgetItem* iitem, QTreeWidgetItem* iparen AddMediaCommand::~AddMediaCommand() { if (!done) { panel_project->delete_media(item); + if (item->data(0, Qt::UserRole + 5) != NULL) delete reinterpret_cast(item->data(0, Qt::UserRole + 5).value()); delete item; } } void AddMediaCommand::undo() { if (parent == NULL) { - panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item)); + bool found = false; + for (int i=0;isource_table->topLevelItemCount();i++) { + if (panel_project->source_table->topLevelItem(i) == item) { + dout << "item at index is:" << panel_project->source_table->topLevelItem(i)->text(0); + QTreeWidgetItem* deleted_item = panel_project->source_table->takeTopLevelItem(i); + dout << "wanted to take" << item->text(0) << "took" << deleted_item->text(0); + found = true; + break; + } + } + dout << "took:" << found; } else { parent->removeChild(item); } @@ -369,8 +381,25 @@ void AddMediaCommand::redo() { panel_project->source_table->addTopLevelItem(item); } else { parent->addChild(item); - } - done = true; + } + + /* 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. + */ + panel_project->source_table->setSortingEnabled(false); + panel_project->source_table->setSortingEnabled(true); + + done = true; mainWindow->setWindowModified(true); } @@ -382,6 +411,7 @@ DeleteMediaCommand::DeleteMediaCommand(QTreeWidgetItem* i) : DeleteMediaCommand::~DeleteMediaCommand() { if (done) { panel_project->delete_media(item); + if (item->data(0, Qt::UserRole + 5) != NULL) delete reinterpret_cast(item->data(0, Qt::UserRole + 5).value()); delete item; } } diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index 4cc170e41..08f856375 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -19,6 +19,7 @@ SourceTable::SourceTable(QWidget* parent) : QTreeWidget(parent) { editing_item = NULL; + setSortingEnabled(true); sortByColumn(0, Qt::AscendingOrder); rename_timer.setInterval(1000); setContextMenuPolicy(Qt::CustomContextMenu); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index bae3ad872..cb8e1b957 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -491,7 +491,7 @@ void TimelineWidget::wheelEvent(QWheelEvent *event) { } void TimelineWidget::dragLeaveEvent(QDragLeaveEvent*) { - if (sequence != NULL && panel_timeline->importing) { + if (panel_timeline->importing) { if (panel_timeline->importing_files) { undo_stack.undo(); }