project: improved main window layout loading
There were a lot of issues that arose from trying to make GUI changes from another thread (even though we ran those functions in the right thread). Now we store layout information until the end of the load and make the changes then. This works much better from both a business logic and user experience perspective. Also prevents multiple sequences from taking focus during load and starting a render job.
This commit is contained in:
@@ -22,5 +22,7 @@ set(OLIVE_SOURCES
|
||||
window/mainwindow/mainstatusbar.cpp
|
||||
window/mainwindow/mainwindow.h
|
||||
window/mainwindow/mainwindow.cpp
|
||||
window/mainwindow/mainwindowlayoutinfo.h
|
||||
window/mainwindow/mainwindowlayoutinfo.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -111,43 +111,37 @@ MainWindow::~MainWindow()
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::LoadLayout(QXmlStreamReader *reader, XMLNodeData &xml_data)
|
||||
void MainWindow::LoadLayout(const MainWindowLayoutInfo &info)
|
||||
{
|
||||
QMetaObject::invokeMethod(this,
|
||||
"LoadLayoutInternal",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QXmlStreamReader*, reader),
|
||||
Q_ARG(XMLNodeData*, &xml_data));
|
||||
foreach (Folder* folder, info.open_folders()) {
|
||||
FolderOpen(folder->project(), folder, true);
|
||||
}
|
||||
|
||||
foreach (Sequence* sequence, info.open_sequences()) {
|
||||
OpenSequence(sequence, false);
|
||||
}
|
||||
|
||||
restoreState(info.state());
|
||||
}
|
||||
|
||||
void MainWindow::SaveLayout(QXmlStreamWriter *writer) const
|
||||
MainWindowLayoutInfo MainWindow::SaveLayout() const
|
||||
{
|
||||
writer->writeStartElement(QStringLiteral("layout"));
|
||||
|
||||
writer->writeStartElement(QStringLiteral("folders"));
|
||||
MainWindowLayoutInfo info;
|
||||
|
||||
foreach (ProjectPanel* panel, folder_panels_) {
|
||||
writer->writeTextElement(QStringLiteral("folder"),
|
||||
QString::number(reinterpret_cast<quintptr>(panel->get_root_index().internalPointer())));
|
||||
info.add_folder(static_cast<Folder*>(panel->get_root_index().internalPointer()));
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // folders
|
||||
|
||||
writer->writeStartElement(QStringLiteral("timeline"));
|
||||
|
||||
foreach (TimelinePanel* panel, timeline_panels_) {
|
||||
writer->writeTextElement(QStringLiteral("sequence"),
|
||||
QString::number(reinterpret_cast<quintptr>(panel->GetConnectedViewer())));
|
||||
info.add_sequence(static_cast<Sequence*>(panel->GetConnectedViewer()->parent()));
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // timeline
|
||||
info.set_state(saveState());
|
||||
|
||||
writer->writeTextElement(QStringLiteral("state"), QString(saveState().toBase64()));
|
||||
|
||||
writer->writeEndElement(); // layout
|
||||
return info;
|
||||
}
|
||||
|
||||
void MainWindow::OpenSequence(Sequence *sequence)
|
||||
void MainWindow::OpenSequence(Sequence *sequence, bool enable_focus)
|
||||
{
|
||||
// See if this sequence is already open, and switch to it if so
|
||||
foreach (TimelinePanel* tl, timeline_panels_) {
|
||||
@@ -164,11 +158,14 @@ void MainWindow::OpenSequence(Sequence *sequence)
|
||||
panel = timeline_panels_.first();
|
||||
} else {
|
||||
panel = AppendTimelinePanel();
|
||||
enable_focus = false;
|
||||
}
|
||||
|
||||
panel->ConnectViewerNode(sequence->viewer_output());
|
||||
|
||||
TimelineFocused(sequence->viewer_output());
|
||||
if (enable_focus) {
|
||||
TimelineFocused(sequence->viewer_output());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::CloseSequence(Sequence *sequence)
|
||||
@@ -467,53 +464,6 @@ void MainWindow::FloatingPanelCloseRequested()
|
||||
panel->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::LoadLayoutInternal(QXmlStreamReader *reader, XMLNodeData *xml_data)
|
||||
{
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("folders")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("folder")) {
|
||||
quintptr item_id = reader->readElementText().toULongLong();
|
||||
|
||||
Item* open_item = xml_data->item_ptrs.value(item_id);
|
||||
|
||||
if (open_item) {
|
||||
FolderOpen(open_item->project(), open_item, true);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("timeline")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("sequence")) {
|
||||
quintptr item_id = reader->readElementText().toULongLong();
|
||||
|
||||
Sequence* open_seq = dynamic_cast<Sequence*>(xml_data->item_ptrs.value(item_id));
|
||||
|
||||
if (open_seq) {
|
||||
OpenSequence(open_seq);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("state")) {
|
||||
|
||||
QByteArray state = QByteArray::fromBase64(reader->readElementText().toLatin1());
|
||||
|
||||
restoreState(state);
|
||||
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimelinePanel* MainWindow::AppendTimelinePanel()
|
||||
{
|
||||
TimelinePanel* panel = AppendPanelInternal<TimelinePanel>(timeline_panels_);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "mainwindowlayoutinfo.h"
|
||||
#include "panel/panelmanager.h"
|
||||
#include "panel/audiomonitor/audiomonitor.h"
|
||||
#include "panel/curve/curve.h"
|
||||
@@ -55,11 +56,11 @@ public:
|
||||
|
||||
virtual ~MainWindow() override;
|
||||
|
||||
void LoadLayout(QXmlStreamReader* reader, XMLNodeData& xml_data);
|
||||
void LoadLayout(const MainWindowLayoutInfo &info);
|
||||
|
||||
void SaveLayout(QXmlStreamWriter* writer) const;
|
||||
MainWindowLayoutInfo SaveLayout() const;
|
||||
|
||||
void OpenSequence(Sequence* sequence);
|
||||
void OpenSequence(Sequence* sequence, bool enable_focus = true);
|
||||
|
||||
void CloseSequence(Sequence* sequence);
|
||||
|
||||
@@ -167,8 +168,6 @@ private slots:
|
||||
|
||||
void FloatingPanelCloseRequested();
|
||||
|
||||
void LoadLayoutInternal(QXmlStreamReader* reader, XMLNodeData *xml_data);
|
||||
|
||||
void StatusBarDoubleClicked();
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "mainwindowlayoutinfo.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
void MainWindowLayoutInfo::toXml(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeStartElement(QStringLiteral("layout"));
|
||||
|
||||
writer->writeStartElement(QStringLiteral("folders"));
|
||||
|
||||
foreach (Folder* folder, open_folders_) {
|
||||
writer->writeTextElement(QStringLiteral("folder"),
|
||||
QString::number(reinterpret_cast<quintptr>(folder)));
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // folders
|
||||
|
||||
writer->writeStartElement(QStringLiteral("timeline"));
|
||||
|
||||
foreach (Sequence* sequence, open_sequences_) {
|
||||
writer->writeTextElement(QStringLiteral("sequence"),
|
||||
QString::number(reinterpret_cast<quintptr>(sequence)));
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // timeline
|
||||
|
||||
writer->writeTextElement(QStringLiteral("state"), QString(state_.toBase64()));
|
||||
|
||||
writer->writeEndElement(); // layout
|
||||
}
|
||||
|
||||
MainWindowLayoutInfo MainWindowLayoutInfo::fromXml(QXmlStreamReader *reader, XMLNodeData &xml_data)
|
||||
{
|
||||
MainWindowLayoutInfo info;
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("folders")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("folder")) {
|
||||
quintptr item_id = reader->readElementText().toULongLong();
|
||||
|
||||
Item* open_item = xml_data.item_ptrs.value(item_id);
|
||||
|
||||
if (open_item) {
|
||||
info.open_folders_.append(static_cast<Folder*>(open_item));
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("timeline")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("sequence")) {
|
||||
quintptr item_id = reader->readElementText().toULongLong();
|
||||
|
||||
Sequence* open_seq = dynamic_cast<Sequence*>(xml_data.item_ptrs.value(item_id));
|
||||
|
||||
if (open_seq) {
|
||||
info.open_sequences_.append(open_seq);
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("state")) {
|
||||
|
||||
info.state_ = QByteArray::fromBase64(reader->readElementText().toLatin1());
|
||||
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void MainWindowLayoutInfo::add_folder(olive::Folder *f)
|
||||
{
|
||||
open_folders_.append(f);
|
||||
}
|
||||
|
||||
void MainWindowLayoutInfo::add_sequence(Sequence *s)
|
||||
{
|
||||
open_sequences_.append(s);
|
||||
}
|
||||
|
||||
void MainWindowLayoutInfo::set_state(const QByteArray &layout)
|
||||
{
|
||||
state_ = layout;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef MAINWINDOWLAYOUTINFO_H
|
||||
#define MAINWINDOWLAYOUTINFO_H
|
||||
|
||||
#include "project/item/folder/folder.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class MainWindowLayoutInfo
|
||||
{
|
||||
public:
|
||||
MainWindowLayoutInfo() = default;
|
||||
|
||||
void toXml(QXmlStreamWriter* writer) const;
|
||||
|
||||
static MainWindowLayoutInfo fromXml(QXmlStreamReader* reader, XMLNodeData &xml_data);
|
||||
|
||||
void add_folder(Folder* f);
|
||||
|
||||
void add_sequence(Sequence* s);
|
||||
|
||||
void set_state(const QByteArray& layout);
|
||||
|
||||
const QList<Folder*>& open_folders() const
|
||||
{
|
||||
return open_folders_;
|
||||
}
|
||||
|
||||
const QList<Sequence*>& open_sequences() const
|
||||
{
|
||||
return open_sequences_;
|
||||
}
|
||||
|
||||
const QByteArray& state() const
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray state_;
|
||||
|
||||
QList<Folder*> open_folders_;
|
||||
|
||||
QList<Sequence*> open_sequences_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Q_DECLARE_METATYPE(OLIVE_NAMESPACE::MainWindowLayoutInfo)
|
||||
|
||||
#endif // MAINWINDOWLAYOUTINFO_H
|
||||
Reference in New Issue
Block a user