From 9797a3bf4b75104486eccef559b7b0d089c816c1 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 20 Dec 2018 23:20:00 +1100 Subject: [PATCH] fixed a bunch of multithreaded loading issues and #174 --- dialogs/loaddialog.cpp | 9 ++++-- dialogs/loaddialog.h | 1 + io/clipboard.cpp | 1 + io/loadthread.cpp | 60 +++++++++++++++++++++++---------------- io/loadthread.h | 5 +++- mainwindow.cpp | 6 ++-- panels/effectcontrols.cpp | 2 ++ panels/panels.cpp | 2 +- panels/project.cpp | 22 +++++++------- playback/playback.cpp | 5 ++-- project/clip.cpp | 1 + project/effect.cpp | 5 ++-- project/media.cpp | 4 +-- ui/collapsiblewidget.cpp | 4 ++- ui/timelinewidget.cpp | 4 +-- ui/viewerwidget.cpp | 2 +- 16 files changed, 82 insertions(+), 51 deletions(-) diff --git a/dialogs/loaddialog.cpp b/dialogs/loaddialog.cpp index 1d25a9fa8..706b1193a 100644 --- a/dialogs/loaddialog.cpp +++ b/dialogs/loaddialog.cpp @@ -39,6 +39,7 @@ LoadDialog::LoadDialog(QWidget *parent, bool autorecovery) : QDialog(parent) { lt = new LoadThread(this, autorecovery); QObject::connect(lt, SIGNAL(success()), this, SLOT(thread_done())); + QObject::connect(lt, SIGNAL(error()), this, SLOT(die())); QObject::connect(lt, SIGNAL(report_progress(int)), bar, SLOT(setValue(int))); lt->start(); } @@ -46,8 +47,12 @@ LoadDialog::LoadDialog(QWidget *parent, bool autorecovery) : QDialog(parent) { void LoadDialog::cancel() { lt->cancel(); lt->wait(); - mainWindow->new_project(); - reject(); + die(); +} + +void LoadDialog::die() { + mainWindow->new_project(); + reject(); } void LoadDialog::thread_done() { diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h index b5f2cdf4f..736acfaef 100644 --- a/dialogs/loaddialog.h +++ b/dialogs/loaddialog.h @@ -17,6 +17,7 @@ public: LoadDialog(QWidget* parent, bool autorecovery); private slots: void cancel(); + void die(); void thread_done(); private: QProgressBar* bar; diff --git a/io/clipboard.cpp b/io/clipboard.cpp index bca0912df..b02761d5e 100644 --- a/io/clipboard.cpp +++ b/io/clipboard.cpp @@ -1,6 +1,7 @@ #include "clipboard.h" #include "project/clip.h" +#include "project/effect.h" int clipboard_type = CLIPBOARD_TYPE_CLIP; QVector clipboard; diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 8a65d1496..001d29669 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -31,6 +31,7 @@ struct TransitionData { LoadThread::LoadThread(LoadDialog* l, bool a) : ld(l), autorecovery(a), cancelled(false) { connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); connect(this, SIGNAL(success()), this, SLOT(success_func())); + connect(this, SIGNAL(error()), this, SLOT(error_func())); connect(this, SIGNAL(start_create_effect_ui(QXmlStreamReader*, Clip*, int, const EffectMeta*, long, bool)), this, SLOT(create_effect_ui(QXmlStreamReader*, Clip*, int, const EffectMeta*, long, bool))); } @@ -572,23 +573,7 @@ void LoadThread::run() { cont = load_worker(file, stream, LOAD_TYPE_VERSION); // find project's internal URL - cont = load_worker(file, stream, LOAD_TYPE_URL); - if (autorecovery) { - QString orig_filename = internal_proj_url; - int insert_index = internal_proj_url.lastIndexOf(".ove", -1, Qt::CaseInsensitive); - if (insert_index == -1) insert_index = internal_proj_url.length(); - int counter = 1; - while (QFileInfo::exists(orig_filename)) { - orig_filename = internal_proj_url; - QString recover_text = "recovered"; - if (counter > 1) { - recover_text += " " + QString::number(counter); - } - orig_filename.insert(insert_index, " (" + recover_text + ")"); - counter++; - } - mainWindow->updateTitle(orig_filename); - } + cont = load_worker(file, stream, LOAD_TYPE_URL); // load folders first if (cont) { @@ -614,11 +599,14 @@ void LoadThread::run() { if (!cancelled) { if (!cont) { - if (show_err) QMessageBox::critical(mainWindow, "Project Load Error", "Error loading project: " + error_str, QMessageBox::Ok); + xml_error = false; + if (show_err) emit error(); } else if (stream.hasError()) { - dout << "[ERROR] Error parsing XML." << stream.errorString(); - QMessageBox::critical(mainWindow, "XML Parsing Error", "Couldn't load '" + project_url + "'. " + stream.errorString(), QMessageBox::Ok); + error_str = stream.errorString(); + xml_error = true; + emit error(); cont = false; + } else { // attach nested sequence clips to their sequences for (int i=0;istart_preview_generator(loaded_media_items.at(i), true); } - } else { - mainWindow->new_project(); - } + } file.close(); @@ -652,10 +638,36 @@ void LoadThread::run() { void LoadThread::cancel() { waitCond.wakeAll(); - cancelled = true; + cancelled = true; +} + +void LoadThread::error_func() { + if (xml_error) { + dout << "[ERROR] Error parsing XML." << error_str; + QMessageBox::critical(mainWindow, "XML Parsing Error", "Couldn't load '" + project_url + "'. " + error_str, QMessageBox::Ok); + } else { + QMessageBox::critical(mainWindow, "Project Load Error", "Error loading project: " + error_str, QMessageBox::Ok); + } } void LoadThread::success_func() { + if (autorecovery) { + QString orig_filename = internal_proj_url; + int insert_index = internal_proj_url.lastIndexOf(".ove", -1, Qt::CaseInsensitive); + if (insert_index == -1) insert_index = internal_proj_url.length(); + int counter = 1; + while (QFileInfo::exists(orig_filename)) { + orig_filename = internal_proj_url; + QString recover_text = "recovered"; + if (counter > 1) { + recover_text += " " + QString::number(counter); + } + orig_filename.insert(insert_index, " (" + recover_text + ")"); + counter++; + } + mainWindow->updateTitle(orig_filename); + } + mainWindow->setWindowModified(autorecovery); if (open_seq != NULL) set_sequence(open_seq); update_ui(false); diff --git a/io/loadthread.h b/io/loadthread.h index 522e2867d..d0b86f5f9 100644 --- a/io/loadthread.h +++ b/io/loadthread.h @@ -12,7 +12,7 @@ struct Footage; struct Clip; struct Sequence; class LoadDialog; -class EffectMeta; +struct EffectMeta; class LoadThread : public QThread { @@ -23,9 +23,11 @@ public: void cancel(); signals: void success(); + void error(); void start_create_effect_ui(QXmlStreamReader* stream, Clip* c, int type, const EffectMeta* meta, long effect_length, bool effect_enabled); void report_progress(int p); private slots: + void error_func(); void success_func(); void create_effect_ui(QXmlStreamReader* stream, Clip* c, int type, const EffectMeta* meta, long effect_length, bool effect_enabled); private: @@ -61,6 +63,7 @@ private: QWaitCondition waitCond; bool cancelled; + bool xml_error; }; #endif // LOADTHREAD_H diff --git a/mainwindow.cpp b/mainwindow.cpp index b317aa017..2efb33e42 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -227,6 +227,9 @@ MainWindow::MainWindow(QWidget *parent) : } MainWindow::~MainWindow() { + panel_sequence_viewer->viewer_widget->delete_function(); + panel_footage_viewer->viewer_widget->delete_function(); + set_sequence(NULL); QString data_dir = get_data_path(); @@ -439,8 +442,7 @@ void MainWindow::new_project() { } } -void MainWindow::on_actionSplit_at_Playhead_triggered() -{ +void MainWindow::on_actionSplit_at_Playhead_triggered() { if (panel_timeline->focused()) { panel_timeline->split_at_playhead(); } diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index c31f46e13..3fa48359c 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -201,6 +201,8 @@ void EffectControls::show_effect_menu(int type, int subtype) { void EffectControls::clear_effects(bool clear_cache) { // clear existing clips + deselect_all_effects(NULL); + QVBoxLayout* video_layout = static_cast(ui->video_effect_area->layout()); QVBoxLayout* audio_layout = static_cast(ui->audio_effect_area->layout()); QLayoutItem* item; diff --git a/panels/panels.cpp b/panels/panels.cpp index 4efe6de21..dd8206ccc 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -125,7 +125,7 @@ QDockWidget *get_focused_panel() { if (w == NULL) { if (panel_project->is_focused()) { w = panel_project; - } else if (panel_effect_controls->keyframe_focus()) { + } else if (panel_effect_controls->keyframe_focus() || panel_effect_controls->is_focused()) { w = panel_effect_controls; } else if (panel_sequence_viewer->is_focused()) { w = panel_sequence_viewer; diff --git a/panels/project.cpp b/panels/project.cpp index 6b77d01a0..280fab531 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -859,16 +859,18 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, stream.writeAttribute("maintainpitch", QString::number(c->maintain_audio_pitch)); stream.writeAttribute("reverse", QString::number(c->reverse)); - stream.writeAttribute("type", QString::number(c->media->get_type())); - switch (c->media->get_type()) { - case MEDIA_TYPE_FOOTAGE: - stream.writeAttribute("media", QString::number(c->media->to_footage()->save_id)); - stream.writeAttribute("stream", QString::number(c->media_stream)); - break; - case MEDIA_TYPE_SEQUENCE: - stream.writeAttribute("sequence", QString::number(c->media->to_sequence()->save_id)); - break; - } + if (c->media != NULL) { + stream.writeAttribute("type", QString::number(c->media->get_type())); + switch (c->media->get_type()) { + case MEDIA_TYPE_FOOTAGE: + stream.writeAttribute("media", QString::number(c->media->to_footage()->save_id)); + stream.writeAttribute("stream", QString::number(c->media_stream)); + break; + case MEDIA_TYPE_SEQUENCE: + stream.writeAttribute("sequence", QString::number(c->media->to_sequence()->save_id)); + break; + } + } stream.writeStartElement("linked"); // linked for (int k=0;klinked.size();k++) { diff --git a/playback/playback.cpp b/playback/playback.cpp index cfc99bc1b..12361233d 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -87,7 +87,8 @@ void close_clip(Clip* clip) { } else { if (clip->media != NULL && clip->media->get_type() == MEDIA_TYPE_SEQUENCE) closeActiveClips(clip->media->to_sequence(), false); - clip->open = false; + + clip->open = false; } } @@ -342,7 +343,7 @@ void closeActiveClips(Sequence *s, bool wait) { if (c != NULL) { if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_SEQUENCE) { closeActiveClips(c->media->to_sequence(), wait); - close_clip(c); + if (c->open) close_clip(c); } else if (clip_uses_cacher(c) && c->open) { close_clip(c); if (c->multithreaded && wait) c->cacher->wait(); diff --git a/project/clip.cpp b/project/clip.cpp index 90a0fb48b..df0927544 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -210,6 +210,7 @@ double Clip::getMediaFrameRate() { if (!qIsNaN(rate)) return rate; } if (sequence != NULL) return sequence->frame_rate; + return qSNaN(); } void Clip::recalculateMaxLength() { diff --git a/project/effect.cpp b/project/effect.cpp index 7d9d25e0f..9940e8b43 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -432,7 +432,7 @@ Effect::~Effect() { close(); } - delete container; + delete container; for (int i=0;idestroy(); delete texture; texture = NULL; } diff --git a/project/media.cpp b/project/media.cpp index b97d09a11..696a0f34b 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -183,8 +183,8 @@ 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; - } + default: return folder_name; + } } void Media::set_name(const QString &n) { diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index a4284b80b..910cf0ef2 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -12,6 +12,8 @@ #include #include +#include "debug.h" + CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { selected = false; @@ -48,7 +50,7 @@ void CollapsibleWidget::header_click(bool s, bool deselect) { selected = s; title_bar->selected = s; if (s) { - QPalette p = palette(); + QPalette p = title_bar->palette(); p.setColor(QPalette::Background, QColor(255, 255, 255, 64)); title_bar->setPalette(p); } else { diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 5e3a318d7..719b1ca51 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -1237,7 +1237,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { if (g.clip != -1) c = sequence->clips.at(g.clip); FootageStream* ms = NULL; - if (g.clip != -1 && c->media->get_type() == MEDIA_TYPE_FOOTAGE) { + if (g.clip != -1 && c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) { ms = c->media->to_footage()->get_stream_from_file_index(c->track < 0, c->media_stream); } @@ -1277,7 +1277,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) { if (validator < 1) frame_diff += (1 - validator); // prevent clip length exceeding media length - if (c->media->get_type() == MEDIA_TYPE_SEQUENCE + if ((c->media != NULL && c->media->get_type() == MEDIA_TYPE_SEQUENCE) || (ms != NULL && !ms->infinite_length)) { validator = g.old_clip_in + g.ghost_length + frame_diff; if (validator > g.media_length) frame_diff -= validator - g.media_length; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 071c428e3..0a7732832 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -67,7 +67,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : void ViewerWidget::delete_function() { // destroy all textures as well - if (viewer->seq != NULL) { + if (viewer->seq != NULL) { makeCurrent(); closeActiveClips(viewer->seq, true); doneCurrent();