aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/texteditor/markdowneditor.cpp
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2023-05-09 14:55:44 +0200
committerEike Ziller <eike.ziller@qt.io>2023-05-10 13:02:25 +0000
commit68656354427141b8521270a559cffe8230f5d6fd (patch)
treea740d2dbead7d00bf85263a3dd728c59169f06e0 /src/plugins/texteditor/markdowneditor.cpp
parent349a3a5872b8287329ae48466a19aaf43cd43dd6 (diff)
Markdown: Save and restore state
This restores the state of the markdown editor, including text editor state, preview scroll position and button states, when closing and re- opening a file. Change-Id: Ibf1cadd5e0e80149123c6c5f599157e931330343 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
Diffstat (limited to 'src/plugins/texteditor/markdowneditor.cpp')
-rw-r--r--src/plugins/texteditor/markdowneditor.cpp176
1 files changed, 115 insertions, 61 deletions
diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp
index 6310bd32689..12e60f027af 100644
--- a/src/plugins/texteditor/markdowneditor.cpp
+++ b/src/plugins/texteditor/markdowneditor.cpp
@@ -20,6 +20,8 @@
#include <QTimer>
#include <QToolButton>
+#include <optional>
+
namespace TextEditor::Internal {
const char MARKDOWNVIEWER_ID[] = "Editors.MarkdownViewer";
@@ -50,10 +52,10 @@ public:
m_splitter = new Core::MiniSplitter;
// preview
- auto browser = new QTextBrowser();
- browser->setOpenExternalLinks(true);
- browser->setFrameShape(QFrame::NoFrame);
- new Utils::MarkdownHighlighter(browser->document());
+ m_previewWidget = new QTextBrowser();
+ m_previewWidget->setOpenExternalLinks(true);
+ m_previewWidget->setFrameShape(QFrame::NoFrame);
+ new Utils::MarkdownHighlighter(m_previewWidget->document());
// editor
m_textEditorWidget = new TextEditorWidget;
@@ -65,13 +67,8 @@ public:
context->setContext(Core::Context(MARKDOWNVIEWER_TEXT_CONTEXT));
Core::ICore::addContextObject(context);
- if (textEditorRight) {
- m_splitter->addWidget(browser);
- m_splitter->addWidget(m_textEditorWidget);
- } else {
- m_splitter->addWidget(m_textEditorWidget);
- m_splitter->addWidget(browser);
- }
+ m_splitter->addWidget(m_previewWidget);
+ m_splitter->addWidget(m_textEditorWidget);
setContext(Core::Context(MARKDOWNVIEWER_ID));
@@ -90,11 +87,11 @@ public:
}
agg->add(m_widget.get());
- auto togglePreviewVisible = new QToolButton;
- togglePreviewVisible->setText(Tr::tr("Show Preview"));
- togglePreviewVisible->setCheckable(true);
- togglePreviewVisible->setChecked(showPreview);
- browser->setVisible(showPreview);
+ m_togglePreviewVisible = new QToolButton;
+ m_togglePreviewVisible->setText(Tr::tr("Show Preview"));
+ m_togglePreviewVisible->setCheckable(true);
+ m_togglePreviewVisible->setChecked(showPreview);
+ m_previewWidget->setVisible(showPreview);
m_toggleEditorVisible = new QToolButton;
m_toggleEditorVisible->setText(Tr::tr("Show Editor"));
@@ -106,37 +103,33 @@ public:
swapViews->setText(Tr::tr("Swap Views"));
swapViews->setEnabled(showEditor && showPreview);
- auto toolbarLayout = new QHBoxLayout(&m_toolbar);
- toolbarLayout->setSpacing(0);
- toolbarLayout->setContentsMargins(0, 0, 0, 0);
- toolbarLayout->addStretch();
- if (textEditorRight) {
- toolbarLayout->addWidget(togglePreviewVisible);
- toolbarLayout->addWidget(m_toggleEditorVisible);
- } else {
- toolbarLayout->addWidget(m_toggleEditorVisible);
- toolbarLayout->addWidget(togglePreviewVisible);
- }
- toolbarLayout->addWidget(swapViews);
+ m_toolbarLayout = new QHBoxLayout(&m_toolbar);
+ m_toolbarLayout->setSpacing(0);
+ m_toolbarLayout->setContentsMargins(0, 0, 0, 0);
+ m_toolbarLayout->addStretch();
+ m_toolbarLayout->addWidget(m_togglePreviewVisible);
+ m_toolbarLayout->addWidget(m_toggleEditorVisible);
+ m_toolbarLayout->addWidget(swapViews);
+
+ setWidgetOrder(textEditorRight);
connect(m_document.data(),
&TextDocument::mimeTypeChanged,
m_document.data(),
&TextDocument::changed);
- const auto updatePreview = [this, browser] {
- QHash<QScrollBar *, int> positions;
- const auto scrollBars = browser->findChildren<QScrollBar *>();
-
+ const auto updatePreview = [this] {
// save scroll positions
- for (QScrollBar *scrollBar : scrollBars)
- positions.insert(scrollBar, scrollBar->value());
+ const QPoint positions = m_previewRestoreScrollPosition
+ ? *m_previewRestoreScrollPosition
+ : QPoint(m_previewWidget->horizontalScrollBar()->value(),
+ m_previewWidget->verticalScrollBar()->value());
+ m_previewRestoreScrollPosition.reset();
- browser->setMarkdown(m_document->plainText());
+ m_previewWidget->setMarkdown(m_document->plainText());
- // restore scroll positions
- for (QScrollBar *scrollBar : scrollBars)
- scrollBar->setValue(positions.value(scrollBar));
+ m_previewWidget->horizontalScrollBar()->setValue(positions.x());
+ m_previewWidget->verticalScrollBar()->setValue(positions.y());
};
const auto viewToggled =
@@ -154,10 +147,10 @@ public:
}
swapViews->setEnabled(view->isVisible() && otherView->isVisible());
};
- const auto saveViewSettings = [this, togglePreviewVisible] {
+ const auto saveViewSettings = [this] {
Utils::QtcSettings *s = Core::ICore::settings();
s->setValueWithDefault(MARKDOWNVIEWER_SHOW_PREVIEW,
- togglePreviewVisible->isChecked(),
+ m_togglePreviewVisible->isChecked(),
kShowPreviewDefault);
s->setValueWithDefault(MARKDOWNVIEWER_SHOW_EDITOR,
m_toggleEditorVisible->isChecked(),
@@ -167,15 +160,18 @@ public:
connect(m_toggleEditorVisible,
&QToolButton::toggled,
this,
- [this, browser, togglePreviewVisible, viewToggled, saveViewSettings](bool visible) {
- viewToggled(m_textEditorWidget, visible, browser, togglePreviewVisible);
+ [this, viewToggled, saveViewSettings](bool visible) {
+ viewToggled(m_textEditorWidget,
+ visible,
+ m_previewWidget,
+ m_togglePreviewVisible);
saveViewSettings();
});
- connect(togglePreviewVisible,
+ connect(m_togglePreviewVisible,
&QToolButton::toggled,
this,
- [this, browser, viewToggled, updatePreview, saveViewSettings](bool visible) {
- viewToggled(browser, visible, m_textEditorWidget, m_toggleEditorVisible);
+ [this, viewToggled, updatePreview, saveViewSettings](bool visible) {
+ viewToggled(m_previewWidget, visible, m_textEditorWidget, m_toggleEditorVisible);
if (visible && m_performDelayedUpdate) {
m_performDelayedUpdate = false;
updatePreview();
@@ -183,31 +179,21 @@ public:
saveViewSettings();
});
- connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this, toolbarLayout] {
- QTC_ASSERT(m_splitter->count() > 1, return);
- // switch views
- auto placeholder = std::make_unique<QWidget>();
- auto second = m_splitter->replaceWidget(1, placeholder.get());
- auto first = m_splitter->replaceWidget(0, second);
- m_splitter->replaceWidget(1, first);
- // switch buttons
- const int rightIndex = toolbarLayout->count() - 2;
- QLayoutItem *right = toolbarLayout->takeAt(rightIndex);
- toolbarLayout->insertItem(rightIndex - 1, right);
+ connect(swapViews, &QToolButton::clicked, m_textEditorWidget, [this] {
+ const bool textEditorRight = isTextEditorRight();
+ setWidgetOrder(!textEditorRight);
// save settings
Utils::QtcSettings *s = Core::ICore::settings();
s->setValueWithDefault(MARKDOWNVIEWER_TEXTEDITOR_RIGHT,
- !s->value(MARKDOWNVIEWER_TEXTEDITOR_RIGHT,
- kTextEditorRightDefault)
- .toBool(),
+ !textEditorRight,
kTextEditorRightDefault);
});
// TODO directly update when we build with Qt 6.5.2
m_previewTimer.setInterval(500);
m_previewTimer.setSingleShot(true);
- connect(&m_previewTimer, &QTimer::timeout, this, [this, togglePreviewVisible, updatePreview] {
- if (togglePreviewVisible->isChecked())
+ connect(&m_previewTimer, &QTimer::timeout, this, [this, updatePreview] {
+ if (m_togglePreviewVisible->isChecked())
updatePreview();
else
m_performDelayedUpdate = true;
@@ -218,6 +204,25 @@ public:
});
}
+ bool isTextEditorRight() const { return m_splitter->widget(0) == m_previewWidget; }
+
+ void setWidgetOrder(bool textEditorRight)
+ {
+ QTC_ASSERT(m_splitter->count() > 1, return);
+ QWidget *left = textEditorRight ? static_cast<QWidget *>(m_previewWidget)
+ : m_textEditorWidget;
+ QWidget *right = textEditorRight ? static_cast<QWidget *>(m_textEditorWidget)
+ : m_previewWidget;
+ m_splitter->insertWidget(0, left);
+ m_splitter->insertWidget(1, right);
+ // buttons
+ QWidget *leftButton = textEditorRight ? m_togglePreviewVisible : m_toggleEditorVisible;
+ QWidget *rightButton = textEditorRight ? m_toggleEditorVisible : m_togglePreviewVisible;
+ const int rightIndex = m_toolbarLayout->count() - 2;
+ m_toolbarLayout->insertWidget(rightIndex, leftButton);
+ m_toolbarLayout->insertWidget(rightIndex, rightButton);
+ }
+
QWidget *toolBar() override { return &m_toolbar; }
Core::IDocument *document() const override { return m_document.data(); }
@@ -247,14 +252,63 @@ public:
return Core::IEditor::eventFilter(obj, ev);
}
+ QByteArray saveState() const override
+ {
+ QByteArray state;
+ QDataStream stream(&state, QIODevice::WriteOnly);
+ stream << 1; // version number
+ stream << m_textEditorWidget->saveState();
+ stream << m_previewWidget->horizontalScrollBar()->value();
+ stream << m_previewWidget->verticalScrollBar()->value();
+ stream << isTextEditorRight();
+ stream << m_togglePreviewVisible->isChecked();
+ stream << m_toggleEditorVisible->isChecked();
+ stream << m_splitter->saveState();
+ return state;
+ }
+
+ void restoreState(const QByteArray &state) override
+ {
+ if (state.isEmpty())
+ return;
+ int version;
+ QByteArray editorState;
+ int previewHV;
+ int previewVV;
+ bool textEditorRight;
+ bool previewShown;
+ bool textEditorShown;
+ QByteArray splitterState;
+ QDataStream stream(state);
+ stream >> version;
+ stream >> editorState;
+ stream >> previewHV;
+ stream >> previewVV;
+ stream >> textEditorRight;
+ stream >> previewShown;
+ stream >> textEditorShown;
+ stream >> splitterState;
+ m_textEditorWidget->restoreState(editorState);
+ m_previewRestoreScrollPosition.emplace(previewHV, previewVV);
+ setWidgetOrder(textEditorRight);
+ m_splitter->restoreState(splitterState);
+ m_togglePreviewVisible->setChecked(previewShown);
+ // ensure at least one is shown
+ m_toggleEditorVisible->setChecked(textEditorShown || !previewShown);
+ }
+
private:
QTimer m_previewTimer;
bool m_performDelayedUpdate = false;
Core::MiniSplitter *m_splitter;
+ QTextBrowser *m_previewWidget;
TextEditorWidget *m_textEditorWidget;
TextDocumentPtr m_document;
QWidget m_toolbar;
+ QHBoxLayout *m_toolbarLayout;
QToolButton *m_toggleEditorVisible;
+ QToolButton *m_togglePreviewVisible;
+ std::optional<QPoint> m_previewRestoreScrollPosition;
};
MarkdownEditorFactory::MarkdownEditorFactory()