add MindMap editor

This commit is contained in:
Le Tan 2022-12-25 13:05:43 +08:00
parent e76c6829f7
commit 5229be4687
53 changed files with 1243 additions and 204 deletions

View File

@ -5,12 +5,13 @@ SOURCES += \
$$PWD/markdownbuffer.cpp \
$$PWD/markdownbufferfactory.cpp \
$$PWD/filetypehelper.cpp \
$$PWD/mindmapbuffer.cpp \
$$PWD/mindmapbufferfactory.cpp \
$$PWD/nodebufferprovider.cpp \
$$PWD/pdfbuffer.cpp \
$$PWD/pdfbufferfactory.cpp \
$$PWD/textbuffer.cpp \
$$PWD/textbufferfactory.cpp \
$$PWD/urlbasedbufferprovider.cpp
$$PWD/textbufferfactory.cpp
HEADERS += \
$$PWD/bufferprovider.h \
@ -20,6 +21,8 @@ HEADERS += \
$$PWD/markdownbuffer.h \
$$PWD/markdownbufferfactory.h \
$$PWD/filetypehelper.h \
$$PWD/mindmapbuffer.h \
$$PWD/mindmapbufferfactory.h \
$$PWD/nodebufferprovider.h \
$$PWD/pdfbuffer.h \
$$PWD/pdfbufferfactory.h \

View File

@ -91,6 +91,22 @@ void FileTypeHelper::setupBuiltInTypes()
m_fileTypes.push_back(type);
}
{
FileType type;
type.m_type = FileType::MindMap;
type.m_typeName = QStringLiteral("MindMap");
type.m_displayName = Buffer::tr("Mind Map");
auto suffixes = coreConfig.findFileTypeSuffix(type.m_typeName);
if (suffixes && !suffixes->isEmpty()) {
type.m_suffixes = *suffixes;
} else {
type.m_suffixes << QStringLiteral("emind");
}
m_fileTypes.push_back(type);
}
{
FileType type;
type.m_type = FileType::Others;

View File

@ -16,6 +16,7 @@ namespace vnotex
Markdown = 0,
Text,
Pdf,
MindMap,
Others
};

View File

@ -0,0 +1,17 @@
#include "mindmapbuffer.h"
#include <widgets/mindmapviewwindow.h>
using namespace vnotex;
MindMapBuffer::MindMapBuffer(const BufferParameters &p_parameters,
QObject *p_parent)
: Buffer(p_parameters, p_parent)
{
}
ViewWindow *MindMapBuffer::createViewWindowInternal(const QSharedPointer<FileOpenParameters> &p_paras, QWidget *p_parent)
{
Q_UNUSED(p_paras);
return new MindMapViewWindow(p_parent);
}

View File

@ -0,0 +1,21 @@
#ifndef MINDMAPBUFFER_H
#define MINDMAPBUFFER_H
#include "buffer.h"
namespace vnotex
{
class MindMapBuffer : public Buffer
{
Q_OBJECT
public:
MindMapBuffer(const BufferParameters &p_parameters,
QObject *p_parent = nullptr);
protected:
ViewWindow *createViewWindowInternal(const QSharedPointer<FileOpenParameters> &p_paras,
QWidget *p_parent) Q_DECL_OVERRIDE;
};
}
#endif // MINDMAPBUFFER_H

View File

@ -0,0 +1,16 @@
#include "mindmapbufferfactory.h"
#include "mindmapbuffer.h"
using namespace vnotex;
Buffer *MindMapBufferFactory::createBuffer(const BufferParameters &p_parameters,
QObject *p_parent)
{
return new MindMapBuffer(p_parameters, p_parent);
}
bool MindMapBufferFactory::isBufferCreatedByFactory(const Buffer *p_buffer) const
{
return dynamic_cast<const MindMapBuffer *>(p_buffer) != nullptr;
}

View File

@ -0,0 +1,19 @@
#ifndef MINDMAPBUFFERFACTORY_H
#define MINDMAPBUFFERFACTORY_H
#include "ibufferfactory.h"
namespace vnotex
{
// Buffer factory for MindMap file.
class MindMapBufferFactory : public IBufferFactory
{
public:
Buffer *createBuffer(const BufferParameters &p_parameters,
QObject *p_parent) Q_DECL_OVERRIDE;
bool isBufferCreatedByFactory(const Buffer *p_buffer) const Q_DECL_OVERRIDE;
};
}
#endif // MINDMAPBUFFERFACTORY_H

View File

@ -15,7 +15,6 @@ namespace vnotex
protected:
ViewWindow *createViewWindowInternal(const QSharedPointer<FileOpenParameters> &p_paras,
QWidget *p_parent) Q_DECL_OVERRIDE;
};
} // ns vnotex

View File

@ -1,3 +0,0 @@
#include "urlbasedbufferprovider.h"
using namespace vnotex;

View File

@ -8,6 +8,7 @@
#include <buffer/markdownbufferfactory.h>
#include <buffer/textbufferfactory.h>
#include <buffer/pdfbufferfactory.h>
#include <buffer/mindmapbufferfactory.h>
#include <buffer/buffer.h>
#include <buffer/nodebufferprovider.h>
#include <buffer/filebufferprovider.h>
@ -57,6 +58,10 @@ void BufferMgr::initBufferServer()
// Pdf.
auto pdfFactory = QSharedPointer<PdfBufferFactory>::create();
m_bufferServer->registerItem(helper.getFileType(FileType::Pdf).m_typeName, pdfFactory);
// MindMap.
auto mindMapFactory = QSharedPointer<MindMapBufferFactory>::create();
m_bufferServer->registerItem(helper.getFileType(FileType::MindMap).m_typeName, mindMapFactory);
}
void BufferMgr::open(Node *p_node, const QSharedPointer<FileOpenParameters> &p_paras)

View File

@ -24,6 +24,7 @@ SOURCES += \
$$PWD/logger.cpp \
$$PWD/mainconfig.cpp \
$$PWD/markdowneditorconfig.cpp \
$$PWD/mindmapeditorconfig.cpp \
$$PWD/pdfviewerconfig.cpp \
$$PWD/quickaccesshelper.cpp \
$$PWD/singleinstanceguard.cpp \
@ -54,6 +55,7 @@ HEADERS += \
$$PWD/logger.h \
$$PWD/mainconfig.h \
$$PWD/markdowneditorconfig.h \
$$PWD/mindmapeditorconfig.h \
$$PWD/noncopyable.h \
$$PWD/pdfviewerconfig.h \
$$PWD/quickaccesshelper.h \

View File

@ -6,6 +6,7 @@
#include "texteditorconfig.h"
#include "markdowneditorconfig.h"
#include "pdfviewerconfig.h"
#include "mindmapeditorconfig.h"
#include <vtextedit/viconfig.h>
@ -43,7 +44,8 @@ EditorConfig::EditorConfig(ConfigMgr *p_mgr, IConfig *p_topConfig)
: IConfig(p_mgr, p_topConfig),
m_textEditorConfig(new TextEditorConfig(p_mgr, p_topConfig)),
m_markdownEditorConfig(new MarkdownEditorConfig(p_mgr, p_topConfig, m_textEditorConfig)),
m_pdfViewerConfig(new PdfViewerConfig(p_mgr, p_topConfig))
m_pdfViewerConfig(new PdfViewerConfig(p_mgr, p_topConfig)),
m_mindMapEditorConfig(new MindMapEditorConfig(p_mgr, p_topConfig))
{
m_sessionName = QStringLiteral("editor");
}
@ -68,6 +70,7 @@ void EditorConfig::init(const QJsonObject &p_app,
m_textEditorConfig->init(appObj, userObj);
m_markdownEditorConfig->init(appObj, userObj);
m_pdfViewerConfig->init(appObj, userObj);
m_mindMapEditorConfig->init(appObj, userObj);
}
void EditorConfig::loadCore(const QJsonObject &p_app, const QJsonObject &p_user)
@ -152,6 +155,7 @@ QJsonObject EditorConfig::toJson() const
obj[m_textEditorConfig->getSessionName()] = m_textEditorConfig->toJson();
obj[m_markdownEditorConfig->getSessionName()] = m_markdownEditorConfig->toJson();
obj[m_pdfViewerConfig->getSessionName()] = m_pdfViewerConfig->toJson();
obj[m_mindMapEditorConfig->getSessionName()] = m_mindMapEditorConfig->toJson();
obj[QStringLiteral("core")] = saveCore();
obj[QStringLiteral("image_host")] = saveImageHost();
@ -192,6 +196,16 @@ const PdfViewerConfig &EditorConfig::getPdfViewerConfig() const
return *m_pdfViewerConfig;
}
MindMapEditorConfig &EditorConfig::getMindMapEditorConfig()
{
return *m_mindMapEditorConfig;
}
const MindMapEditorConfig &EditorConfig::getMindMapEditorConfig() const
{
return *m_mindMapEditorConfig;
}
int EditorConfig::getToolBarIconSize() const
{
return m_toolBarIconSize;

View File

@ -20,6 +20,7 @@ namespace vnotex
class TextEditorConfig;
class MarkdownEditorConfig;
class PdfViewerConfig;
class MindMapEditorConfig;
class EditorConfig : public IConfig
{
@ -109,6 +110,9 @@ namespace vnotex
PdfViewerConfig &getPdfViewerConfig();
const PdfViewerConfig &getPdfViewerConfig() const;
MindMapEditorConfig &getMindMapEditorConfig();
const MindMapEditorConfig &getMindMapEditorConfig() const;
void init(const QJsonObject &p_app, const QJsonObject &p_user) Q_DECL_OVERRIDE;
QJsonObject toJson() const Q_DECL_OVERRIDE;
@ -182,6 +186,8 @@ namespace vnotex
QScopedPointer<PdfViewerConfig> m_pdfViewerConfig;
QScopedPointer<MindMapEditorConfig> m_mindMapEditorConfig;
bool m_spellCheckAutoDetectLanguageEnabled = false;
QString m_spellCheckDefaultDictionary;

View File

@ -4,6 +4,7 @@
#include <core/markdowneditorconfig.h>
#include <core/pdfviewerconfig.h>
#include <core/mindmapeditorconfig.h>
#include <core/configmgr.h>
#include <utils/utils.h>
#include <utils/fileutils.h>
@ -19,6 +20,8 @@ HtmlTemplateHelper::Template HtmlTemplateHelper::s_markdownViewerTemplate;
HtmlTemplateHelper::Template HtmlTemplateHelper::s_pdfViewerTemplate;
HtmlTemplateHelper::Template HtmlTemplateHelper::s_mindMapEditorTemplate;
QString MarkdownWebGlobalOptions::toJavascriptObject() const
{
return QStringLiteral("window.vxOptions = {\n")
@ -339,7 +342,7 @@ const QString &HtmlTemplateHelper::getPdfViewerTemplatePath()
void HtmlTemplateHelper::updatePdfViewerTemplate(const PdfViewerConfig &p_config, bool p_force)
{
if (!p_force && p_config.revision() == s_markdownViewerTemplate.m_revision) {
if (!p_force && p_config.revision() == s_pdfViewerTemplate.m_revision) {
return;
}
@ -361,3 +364,41 @@ void HtmlTemplateHelper::generatePdfViewerTemplate(const PdfViewerConfig &p_conf
fillResources(p_template.m_template, viewerResource);
}
const QString &HtmlTemplateHelper::getMindMapEditorTemplate()
{
return s_mindMapEditorTemplate.m_template;
}
void HtmlTemplateHelper::updateMindMapEditorTemplate(const MindMapEditorConfig &p_config, bool p_force)
{
if (!p_force && p_config.revision() == s_mindMapEditorTemplate.m_revision) {
return;
}
s_mindMapEditorTemplate.m_revision = p_config.revision();
const auto &themeMgr = VNoteX::getInst().getThemeMgr();
generateMindMapEditorTemplate(p_config,
themeMgr.getFile(Theme::File::WebStyleSheet),
s_mindMapEditorTemplate);
}
void HtmlTemplateHelper::generateMindMapEditorTemplate(const MindMapEditorConfig &p_config,
const QString &p_webStyleSheetFile,
Template& p_template)
{
const auto &editorResource = p_config.getEditorResource();
p_template.m_templatePath = ConfigMgr::getInst().getUserOrAppFile(editorResource.m_template);
try {
p_template.m_template = FileUtils::readTextFile(p_template.m_templatePath);
} catch (Exception &p_e) {
qWarning() << "failed to read HTML template" << p_template.m_templatePath << p_e.what();
p_template.m_template = errorPage();
return;
}
fillThemeStyles(p_template.m_template, p_webStyleSheetFile, QString());
fillResources(p_template.m_template, editorResource);
}

View File

@ -7,6 +7,7 @@ namespace vnotex
{
class MarkdownEditorConfig;
class PdfViewerConfig;
class MindMapEditorConfig;
struct WebResource;
// Global options to be passed to Web side at the very beginning for Markdown.
@ -91,7 +92,7 @@ namespace vnotex
HtmlTemplateHelper() = delete;
// For Markdown.
// For MarkdownViewer.
static const QString &getMarkdownViewerTemplate();
static void updateMarkdownViewerTemplate(const MarkdownEditorConfig &p_config, bool p_force = false);
@ -119,6 +120,10 @@ namespace vnotex
static const QString &getPdfViewerTemplatePath();
// For MindMapEditor.
static const QString &getMindMapEditorTemplate();
static void updateMindMapEditorTemplate(const MindMapEditorConfig &p_config, bool p_force = false);
private:
struct Template
{
@ -131,9 +136,15 @@ namespace vnotex
static void generatePdfViewerTemplate(const PdfViewerConfig &p_config, Template& p_template);
static void generateMindMapEditorTemplate(const MindMapEditorConfig &p_config,
const QString &p_webStyleSheetFile,
Template& p_template);
static Template s_markdownViewerTemplate;
static Template s_pdfViewerTemplate;
static Template s_mindMapEditorTemplate;
};
}

View File

@ -0,0 +1,61 @@
#include "mindmapeditorconfig.h"
#include "mainconfig.h"
#define READSTR(key) readString(appObj, userObj, (key))
#define READBOOL(key) readBool(appObj, userObj, (key))
#define READINT(key) readInt(appObj, userObj, (key))
using namespace vnotex;
MindMapEditorConfig::MindMapEditorConfig(ConfigMgr *p_mgr, IConfig *p_topConfig)
: IConfig(p_mgr, p_topConfig)
{
m_sessionName = QStringLiteral("mindmap_editor");
}
void MindMapEditorConfig::init(const QJsonObject &p_app,
const QJsonObject &p_user)
{
const auto appObj = p_app.value(m_sessionName).toObject();
const auto userObj = p_user.value(m_sessionName).toObject();
loadEditorResource(appObj, userObj);
}
QJsonObject MindMapEditorConfig::toJson() const
{
QJsonObject obj;
obj[QStringLiteral("editor_resource")] = saveEditorResource();
return obj;
}
void MindMapEditorConfig::loadEditorResource(const QJsonObject &p_app, const QJsonObject &p_user)
{
const QString name(QStringLiteral("editor_resource"));
if (MainConfig::isVersionChanged()) {
bool needOverride = p_app[QStringLiteral("override_editor_resource")].toBool();
if (needOverride) {
qInfo() << "override \"editor_resource\" in user configuration due to version change";
m_editorResource.init(p_app[name].toObject());
return;
}
}
if (p_user.contains(name)) {
m_editorResource.init(p_user[name].toObject());
} else {
m_editorResource.init(p_app[name].toObject());
}
}
QJsonObject MindMapEditorConfig::saveEditorResource() const
{
return m_editorResource.toJson();
}
const WebResource &MindMapEditorConfig::getEditorResource() const
{
return m_editorResource;
}

View File

@ -0,0 +1,31 @@
#ifndef MINDMAPEDITORCONFIG_H
#define MINDMAPEDITORCONFIG_H
#include "iconfig.h"
#include "webresource.h"
namespace vnotex
{
class MindMapEditorConfig : public IConfig
{
public:
MindMapEditorConfig(ConfigMgr *p_mgr, IConfig *p_topConfig);
void init(const QJsonObject &p_app, const QJsonObject &p_user) Q_DECL_OVERRIDE;
QJsonObject toJson() const Q_DECL_OVERRIDE;
const WebResource &getEditorResource() const;
private:
friend class MainConfig;
void loadEditorResource(const QJsonObject &p_app, const QJsonObject &p_user);
QJsonObject saveEditorResource() const;
WebResource m_editorResource;
};
}
#endif // MINDMAPEDITORCONFIG_H

View File

@ -94,6 +94,12 @@
"suffixes" : [
"pdf"
]
},
{
"name" : "MindMap",
"suffixes" : [
"emind"
]
}
],
"shortcut_leader_key" : "Ctrl+G",
@ -519,6 +525,39 @@
]
}
},
"mindmap_editor" : {
"override_editor_resource" : true,
"editor_resource" : {
"template" : "web/mindmap-editor-template.html",
"resources" : [
{
"name" : "built_in",
"enabled" : true,
"scripts" : [
"web/js/qwebchannel.js",
"web/js/eventemitter.js",
"web/js/utils.js",
"web/js/vxcore.js",
"web/js/mindmapeditorcore.js"
]
},
{
"name" : "mind_elixir",
"enabled" : true,
"scripts" : [
"web/js/mind-elixir/MindElixir.js"
]
},
{
"name" : "mindmap_editor",
"enabled" : true,
"scripts" : [
"web/js/mindmapeditor.js"
]
}
]
}
},
"image_host" : {
"hosts" : [
],

View File

@ -79,8 +79,6 @@
<file>web/js/turndown.js</file>
<file>web/js/mark.js/mark.min.js</file>
<file>web/js/markjs.js</file>
<file>web/js/mind-elixir/MindElixir.min.js</file>
<file>web/js/mind-elixir/painter.js</file>
<file>web/pdf.js/pdfviewer.js</file>
<file>web/pdf.js/pdfviewer.css</file>
@ -327,6 +325,11 @@
<file>web/pdf.js/web/cmaps/V.bcmap</file>
<file>web/pdf.js/web/cmaps/WP-Symbol.bcmap</file>
<file>web/js/mind-elixir/MindElixir.js</file>
<file>web/mindmap-editor-template.html</file>
<file>web/js/mindmapeditorcore.js</file>
<file>web/js/mindmapeditor.js</file>
<file>dicts/en_US.aff</file>
<file>dicts/en_US.dic</file>
<file>themes/native/text-editor.theme</file>

View File

@ -12,6 +12,10 @@ class MarkJs {
this.adapter.on('basicMarkdownRendered', () => {
this.clearCache();
});
this.adapter.on('rendered', () => {
this.clearCache();
});
}
// @p_options: {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
# [mind-elixir](https://github.com/ssshooter/mind-elixir-core)
v0.19.3
v1.1.3

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
/* Main script file for MindMapEditor. */
new QWebChannel(qt.webChannelTransport,
function(p_channel) {
let adapter = p_channel.objects.vxAdapter;
// Export the adapter globally.
window.vxAdapter = adapter;
// Connect signals from CPP side.
adapter.saveDataRequested.connect(function(p_id) {
window.vxcore.saveData(p_id);
});
adapter.dataUpdated.connect(function(p_data) {
window.vxcore.setData(p_data);
});
adapter.findTextRequested.connect(function(p_texts, p_options, p_currentMatchLine) {
window.vxcore.findText(p_texts, p_options, p_currentMatchLine);
});
console.log('QWebChannel has been set up');
if (window.vxcore.initialized) {
window.vxAdapter.setReady(true);
}
});
window.vxcore.on('ready', function() {
if (window.vxAdapter) {
window.vxAdapter.setReady(true);
}
});

View File

@ -0,0 +1,38 @@
class MindMapEditorCore extends VXCore {
constructor() {
super();
}
initOnLoad() {
let options = {
el: '#vx-mindmap',
direction: MindElixir.LEFT,
}
this.mind = new MindElixir(options);
this.mind.bus.addListener('operation', operation => {
if (operation === 'beginEdit') {
return;
}
window.vxAdapter.notifyContentsChanged();
});
}
saveData(p_id) {
let data = this.mind.getAllDataString();
window.vxAdapter.setSavedData(p_id, data);
}
setData(p_data) {
if (p_data && p_data !== "") {
this.mind.init(JSON.parse(p_data));
} else {
const data = MindElixir.new('New Topic')
this.mind.init(data)
}
this.emit('rendered');
}
}
window.vxcore = new MindMapEditorCore();

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>VNoteX MindMap Viewer</title>
<style type="text/css">
/* VX_GLOBAL_STYLES_PLACEHOLDER */
#vx-mindmap {
height: 100vh;
width: 100%;
}
body {
margin: 0px !important;
padding: 0px !important;
}
</style>
<!-- VX_THEME_STYLES_PLACEHOLDER -->
<!-- VX_STYLES_PLACEHOLDER -->
<script type="text/javascript">
/* VX_GLOBAL_OPTIONS_PLACEHOLDER */
</script>
<!-- VX_SCRIPTS_PLACEHOLDER -->
</head>
<body>
<div id="vx-mindmap"></div>
</body>
</html>

View File

@ -84,7 +84,7 @@ void MarkdownViewer::setPreviewHelper(PreviewHelper *p_previewHelper)
TimeStamp p_timeStamp,
const QString &p_lang,
const QString &p_text) {
if (m_adapter->isViewerReady()) {
if (m_adapter->isReady()) {
m_adapter->graphPreviewRequested(p_id, p_timeStamp, p_lang, p_text);
} else {
p_previewHelper->handleGraphPreviewData(MarkdownViewerAdapter::PreviewData());
@ -94,7 +94,7 @@ void MarkdownViewer::setPreviewHelper(PreviewHelper *p_previewHelper)
this, [this, p_previewHelper](quint64 p_id,
TimeStamp p_timeStamp,
const QString &p_text) {
if (m_adapter->isViewerReady()) {
if (m_adapter->isReady()) {
m_adapter->mathPreviewRequested(p_id, p_timeStamp, p_text);
} else {
p_previewHelper->handleMathPreviewData(MarkdownViewerAdapter::PreviewData());

View File

@ -50,16 +50,6 @@ MarkdownViewerAdapter::Heading MarkdownViewerAdapter::Heading::fromJson(const QJ
p_obj.value(QStringLiteral("anchor")).toString());
}
QJsonObject MarkdownViewerAdapter::FindOption::toJson() const
{
QJsonObject obj;
obj["findBackward"] = m_findBackward;
obj["caseSensitive"] = m_caseSensitive;
obj["wholeWordOnly"] = m_wholeWordOnly;
obj["regularExpression"] = m_regularExpression;
return obj;
}
MarkdownViewerAdapter::CssRuleStyle MarkdownViewerAdapter::CssRuleStyle::fromJson(const QJsonObject &p_obj)
{
CssRuleStyle style;
@ -90,7 +80,7 @@ QTextCharFormat MarkdownViewerAdapter::CssRuleStyle::toTextCharFormat() const
}
MarkdownViewerAdapter::MarkdownViewerAdapter(QObject *p_parent)
: QObject(p_parent)
: WebViewAdapter(p_parent)
{
}
@ -108,15 +98,16 @@ void MarkdownViewerAdapter::setText(int p_revision,
return;
}
m_revision = p_revision;
if (m_viewerReady) {
if (isReady()) {
m_revision = p_revision;
emit textUpdated(p_text);
scrollToPosition(Position(p_lineNumber, ""));
} else {
m_pendingActions.append([this, p_text, p_lineNumber]() {
emit textUpdated(p_text);
scrollToPosition(Position(p_lineNumber, ""));
});
pendAction(std::bind(QOverload<int, const QString &, int>::of(&MarkdownViewerAdapter::setText),
this,
p_revision,
p_text,
p_lineNumber));
}
}
@ -125,37 +116,18 @@ void MarkdownViewerAdapter::setText(const QString &p_text, int p_lineNumber)
setText(0, p_text, p_lineNumber);
}
void MarkdownViewerAdapter::setReady(bool p_ready)
{
if (m_viewerReady == p_ready) {
return;
}
m_viewerReady = p_ready;
if (m_viewerReady) {
for (auto &act : m_pendingActions) {
act();
}
m_pendingActions.clear();
emit viewerReady();
}
}
void MarkdownViewerAdapter::scrollToLine(int p_lineNumber)
{
if (p_lineNumber == -1) {
return;
}
if (!m_viewerReady) {
m_pendingActions.append([this, p_lineNumber]() {
scrollToPosition(Position(p_lineNumber, ""));
});
return;
if (isReady()) {
m_topLineNumber = p_lineNumber;
emit editLineNumberUpdated(p_lineNumber);
} else {
pendAction(std::bind(&MarkdownViewerAdapter::scrollToLine, this, p_lineNumber));
}
m_topLineNumber = p_lineNumber;
emit editLineNumberUpdated(p_lineNumber);
}
void MarkdownViewerAdapter::setTopLineNumber(int p_lineNumber)
@ -196,11 +168,6 @@ void MarkdownViewerAdapter::setGraphPreviewData(quint64 p_id,
emit graphPreviewDataReady(PreviewData(p_id, p_timeStamp, p_format, ba, p_needScale));
}
bool MarkdownViewerAdapter::isViewerReady() const
{
return m_viewerReady;
}
void MarkdownViewerAdapter::setMathPreviewData(quint64 p_id,
quint64 p_timeStamp,
const QString &p_format,
@ -272,7 +239,7 @@ void MarkdownViewerAdapter::scrollToAnchor(const QString &p_anchor)
if (p_anchor.isEmpty()) {
return;
}
Q_ASSERT(m_viewerReady);
Q_ASSERT(isReady());
m_currentHeadingIndex = -1;
emit anchorScrollRequested(p_anchor);
}
@ -340,38 +307,6 @@ void MarkdownViewerAdapter::setCrossCopyResult(quint64 p_id, quint64 p_timeStamp
emit crossCopyReady(p_id, p_timeStamp, p_html);
}
void MarkdownViewerAdapter::findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine)
{
FindOption opts;
if (p_options & vnotex::FindOption::FindBackward) {
opts.m_findBackward = true;
}
if (p_options & vnotex::FindOption::CaseSensitive) {
opts.m_caseSensitive = true;
}
if (p_options & vnotex::FindOption::WholeWordOnly) {
opts.m_wholeWordOnly = true;
}
if (p_options & vnotex::FindOption::RegularExpression) {
opts.m_regularExpression = true;
}
if (m_viewerReady) {
emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
} else {
m_pendingActions.append([this, p_texts, opts, p_currentMatchLine]() {
// FIXME: highlights will be clear once the page is ready. Add a delay here.
Utils::sleepWait(1000);
emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
});
}
}
void MarkdownViewerAdapter::setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex)
{
emit findTextReady(p_texts, p_totalMatches, p_currentMatchIndex);
}
void MarkdownViewerAdapter::setWorkFinished()
{
emit workFinished();
@ -393,8 +328,7 @@ void MarkdownViewerAdapter::setSavedContent(const QString &p_headContent,
void MarkdownViewerAdapter::reset()
{
m_revision = 0;
m_viewerReady = false;
m_pendingActions.clear();
setReady(false);
m_topLineNumber = -1;
m_headings.clear();
m_currentHeadingIndex = -1;
@ -437,12 +371,10 @@ void MarkdownViewerAdapter::renderGraph(quint64 p_id,
void MarkdownViewerAdapter::highlightCodeBlock(int p_idx, quint64 p_timeStamp, const QString &p_text)
{
if (m_viewerReady) {
if (isReady()) {
emit highlightCodeBlockRequested(p_idx, p_timeStamp, p_text);
} else {
m_pendingActions.append([this, p_idx, p_timeStamp, p_text]() {
emit highlightCodeBlockRequested(p_idx, p_timeStamp, p_text);
});
pendAction(std::bind(&MarkdownViewerAdapter::highlightCodeBlock, this, p_idx, p_timeStamp, p_text));
}
}
@ -454,24 +386,23 @@ void MarkdownViewerAdapter::setStyleSheetStyles(quint64 p_id, const QJsonArray &
ruleStyles.push_back(CssRuleStyle::fromJson(p_styles[i].toObject()));
}
m_callbackPool.call(p_id, &ruleStyles);
invokeCallback(p_id, &ruleStyles);
}
void MarkdownViewerAdapter::fetchStylesFromStyleSheet(const QString &p_styleSheet,
const std::function<void(const QVector<CssRuleStyle> *)> &p_callback)
{
if (p_styleSheet.isEmpty()) {
p_callback(nullptr);
return;
}
const quint64 id = m_callbackPool.add([p_callback](void *data) {
p_callback(reinterpret_cast<const QVector<CssRuleStyle> *>(data));
});
if (m_viewerReady) {
if (isReady()) {
const quint64 id = addCallback([p_callback](void *data) {
p_callback(reinterpret_cast<const QVector<CssRuleStyle> *>(data));
});
emit parseStyleSheetRequested(id, p_styleSheet);
} else {
m_pendingActions.append([this, p_styleSheet, id]() {
emit parseStyleSheetRequested(id, p_styleSheet);
});
pendAction(std::bind(&MarkdownViewerAdapter::fetchStylesFromStyleSheet, this, p_styleSheet, p_callback));
}
}

View File

@ -1,7 +1,8 @@
#ifndef MARKDOWNVIEWERADAPTER_H
#define MARKDOWNVIEWERADAPTER_H
#include <QObject>
#include "webviewadapter.h"
#include <QString>
#include <QJsonObject>
#include <QScopedPointer>
@ -9,12 +10,11 @@
#include <QTextCharFormat>
#include <core/global.h>
#include <utils/callbackpool.h>
namespace vnotex
{
// Adapter and interface between CPP and JS.
class MarkdownViewerAdapter : public QObject
class MarkdownViewerAdapter : public WebViewAdapter
{
Q_OBJECT
public:
@ -67,19 +67,6 @@ namespace vnotex
QString m_anchor;
};
struct FindOption
{
QJsonObject toJson() const;
bool m_findBackward = false;
bool m_caseSensitive = false;
bool m_wholeWordOnly = false;
bool m_regularExpression = false;
};
struct CssRuleStyle
{
QTextCharFormat toTextCharFormat() const;
@ -113,8 +100,6 @@ namespace vnotex
int getTopLineNumber() const;
bool isViewerReady() const;
const QVector<MarkdownViewerAdapter::Heading> &getHeadings() const;
int getCurrentHeadingIndex() const;
@ -126,8 +111,6 @@ namespace vnotex
QString getCrossCopyTargetDisplayName(const QString &p_target) const;
void findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine = -1);
void saveContent();
// Should be called before WebViewer.setHtml().
@ -141,8 +124,6 @@ namespace vnotex
// Functions to be called from web side.
public slots:
void setReady(bool p_ready);
void setWorkFinished();
// The line number at the top.
@ -183,8 +164,6 @@ namespace vnotex
void setCrossCopyResult(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
void setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
void setSavedContent(const QString &p_headContent, const QString &p_styleContent, const QString &p_content, const QString &p_bodyClassList);
// Call local CPP code to render graph.
@ -227,8 +206,6 @@ namespace vnotex
const QString &p_baseUrl,
const QString &p_html);
void findTextRequested(const QStringList &p_texts, const QJsonObject &p_options, int p_currentMatchLine);
// Request to get the whole HTML content.
void contentRequested();
@ -247,8 +224,6 @@ namespace vnotex
void mathPreviewDataReady(const PreviewData &p_data);
void viewerReady();
// All rendering work has finished.
void workFinished();
@ -264,8 +239,6 @@ namespace vnotex
void crossCopyReady(quint64 p_id, quint64 p_timeStamp, const QString &p_html);
void findTextReady(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
void contentReady(const QString &p_headContent,
const QString &p_styleContent,
const QString &p_content,
@ -280,12 +253,6 @@ namespace vnotex
int m_revision = 0;
// Whether web side viewer is ready to handle text update.
bool m_viewerReady = false;
// Pending actions for the viewer once it is ready.
QVector<std::function<void()>> m_pendingActions;
// Source line number of the top element node at web side.
int m_topLineNumber = -1;
@ -296,8 +263,6 @@ namespace vnotex
// Targets supported by cross copy. Set by web.
QStringList m_crossCopyTargets;
CallbackPool m_callbackPool;
};
}

View File

@ -0,0 +1,44 @@
#include "mindmapeditor.h"
#include <QWebChannel>
#include "mindmapeditoradapter.h"
using namespace vnotex;
MindMapEditor::MindMapEditor(MindMapEditorAdapter *p_adapter,
const QColor &p_background,
qreal p_zoomFactor,
QWidget *p_parent)
: WebViewer(p_background, p_zoomFactor, p_parent),
m_adapter(p_adapter)
{
setAcceptDrops(true);
m_adapter->setParent(this);
connect(m_adapter, &MindMapEditorAdapter::contentsChanged,
this, [this]() {
m_modified = true;
emit contentsChanged();
});
auto channel = new QWebChannel(this);
channel->registerObject(QStringLiteral("vxAdapter"), m_adapter);
page()->setWebChannel(channel);
}
MindMapEditorAdapter *MindMapEditor::adapter() const
{
return m_adapter;
}
void MindMapEditor::setModified(bool p_modified)
{
m_modified = p_modified;
}
bool MindMapEditor::isModified() const
{
return m_modified;
}

View File

@ -0,0 +1,35 @@
#ifndef MINDMAPEDITOR_H
#define MINDMAPEDITOR_H
#include "../webviewer.h"
namespace vnotex
{
class MindMapEditorAdapter;
class MindMapEditor : public WebViewer
{
Q_OBJECT
public:
MindMapEditor(MindMapEditorAdapter *p_adapter,
const QColor &p_background,
qreal p_zoomFactor,
QWidget *p_parent = nullptr);
MindMapEditorAdapter *adapter() const;
void setModified(bool p_modified);
bool isModified() const;
signals:
void contentsChanged();
private:
// Managed by QObject.
MindMapEditorAdapter *m_adapter = nullptr;
bool m_modified = false;
};
}
#endif // MINDMAPEDITOR_H

View File

@ -0,0 +1,39 @@
#include "mindmapeditoradapter.h"
using namespace vnotex;
MindMapEditorAdapter::MindMapEditorAdapter(QObject *p_parent)
: WebViewAdapter(p_parent)
{
}
void MindMapEditorAdapter::setData(const QString &p_data)
{
if (isReady()) {
emit dataUpdated(p_data);
} else {
pendAction(std::bind(&MindMapEditorAdapter::setData, this, p_data));
}
}
void MindMapEditorAdapter::saveData(const std::function<void(const QString &)> &p_callback)
{
if (isReady()) {
const quint64 id = addCallback([p_callback](void *data) {
p_callback(*reinterpret_cast<const QString *>(data));
});
emit saveDataRequested(id);
} else {
pendAction(std::bind(&MindMapEditorAdapter::saveData, this, p_callback));
}
}
void MindMapEditorAdapter::setSavedData(quint64 p_id, const QString &p_data)
{
invokeCallback(p_id, (void *)&p_data);
}
void MindMapEditorAdapter::notifyContentsChanged()
{
emit contentsChanged();
}

View File

@ -0,0 +1,45 @@
#ifndef MINDMAPEDITORADAPTER_H
#define MINDMAPEDITORADAPTER_H
#include "webviewadapter.h"
#include <QString>
#include <QJsonObject>
#include <core/global.h>
namespace vnotex
{
// Adapter and interface between CPP and JS for MindMap.
class MindMapEditorAdapter : public WebViewAdapter
{
Q_OBJECT
public:
explicit MindMapEditorAdapter(QObject *p_parent = nullptr);
~MindMapEditorAdapter() = default;
void setData(const QString &p_data);
void saveData(const std::function<void(const QString &)> &p_callback);
// Functions to be called from web side.
public slots:
void setSavedData(quint64 p_id, const QString &p_data);
void notifyContentsChanged();
// Signals to be connected at web side.
signals:
void dataUpdated(const QString& p_data);
void saveDataRequested(quint64 p_id);
signals:
void contentsChanged();
private:
};
}
#endif // MINDMAPEDITORADAPTER_H

View File

@ -3,7 +3,6 @@
#include <QWebChannel>
#include "pdfvieweradapter.h"
#include "previewhelper.h"
using namespace vnotex;

View File

@ -3,7 +3,7 @@
using namespace vnotex;
PdfViewerAdapter::PdfViewerAdapter(QObject *p_parent)
: QObject(p_parent)
: WebViewAdapter(p_parent)
{
}
@ -11,26 +11,9 @@ void PdfViewerAdapter::setUrl(const QString &p_url)
{
// TODO: Not supported yet.
Q_ASSERT(false);
if (m_viewerReady) {
if (isReady()) {
emit urlUpdated(p_url);
} else {
m_pendingActions.append([this, p_url]() {
emit urlUpdated(p_url);
});
}
}
void PdfViewerAdapter::setReady(bool p_ready)
{
if (m_viewerReady == p_ready) {
return;
}
m_viewerReady = p_ready;
if (m_viewerReady) {
for (auto &act : m_pendingActions) {
act();
}
m_pendingActions.clear();
pendAction(std::bind(&PdfViewerAdapter::setUrl, this, p_url));
}
}

View File

@ -1,16 +1,12 @@
#ifndef PDFVIEWERADAPTER_H
#define PDFVIEWERADAPTER_H
#include <QObject>
#include <QString>
#include <QJsonObject>
#include <core/global.h>
#include "webviewadapter.h"
namespace vnotex
{
// Adapter and interface between CPP and JS for PDF.
class PdfViewerAdapter : public QObject
class PdfViewerAdapter : public WebViewAdapter
{
Q_OBJECT
public:
@ -22,18 +18,10 @@ namespace vnotex
// Functions to be called from web side.
public slots:
void setReady(bool p_ready);
// Signals to be connected at web side.
signals:
void urlUpdated(const QString &p_url);
private:
// Whether web side viewer is ready to handle url update.
bool m_viewerReady = false;
// Pending actions for the viewer once it is ready.
QVector<std::function<void()>> m_pendingActions;
};
}

View File

@ -0,0 +1,92 @@
#include "webviewadapter.h"
#include <utils/utils.h>
using namespace vnotex;
QJsonObject WebViewAdapter::FindOption::toJson() const
{
QJsonObject obj;
obj["findBackward"] = m_findBackward;
obj["caseSensitive"] = m_caseSensitive;
obj["wholeWordOnly"] = m_wholeWordOnly;
obj["regularExpression"] = m_regularExpression;
return obj;
}
WebViewAdapter::WebViewAdapter(QObject *p_parent)
: QObject(p_parent)
{
}
void WebViewAdapter::setReady(bool p_ready)
{
if (m_ready == p_ready) {
return;
}
m_ready = p_ready;
if (m_ready) {
for (auto &act : m_pendingActions) {
act();
}
m_pendingActions.clear();
emit ready();
} else {
m_pendingActions.clear();
}
}
void WebViewAdapter::pendAction(const std::function<void()> &p_func)
{
Q_ASSERT(!m_ready);
m_pendingActions.append(p_func);
}
bool WebViewAdapter::isReady() const
{
return m_ready;
}
void WebViewAdapter::invokeCallback(quint64 p_id, void *p_data)
{
m_callbackPool.call(p_id, p_data);
}
quint64 WebViewAdapter::addCallback(const CallbackPool::Callback &p_callback)
{
return m_callbackPool.add(p_callback);
}
void WebViewAdapter::findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine)
{
FindOption opts;
if (p_options & vnotex::FindOption::FindBackward) {
opts.m_findBackward = true;
}
if (p_options & vnotex::FindOption::CaseSensitive) {
opts.m_caseSensitive = true;
}
if (p_options & vnotex::FindOption::WholeWordOnly) {
opts.m_wholeWordOnly = true;
}
if (p_options & vnotex::FindOption::RegularExpression) {
opts.m_regularExpression = true;
}
if (isReady()) {
emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
} else {
pendAction([this, p_texts, opts, p_currentMatchLine]() {
// FIXME: highlights will be clear once the page is ready. Add a delay here.
Utils::sleepWait(1000);
emit findTextRequested(p_texts, opts.toJson(), p_currentMatchLine);
});
}
}
void WebViewAdapter::setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex)
{
emit findTextReady(p_texts, p_totalMatches, p_currentMatchIndex);
}

View File

@ -0,0 +1,71 @@
#ifndef WEBVIEWADAPTER_H
#define WEBVIEWADAPTER_H
#include <QObject>
#include <QVector>
#include <utils/callbackpool.h>
#include <core/global.h>
namespace vnotex
{
// Base class of adapter and interface between CPP and JS for WebView.
class WebViewAdapter : public QObject
{
Q_OBJECT
public:
explicit WebViewAdapter(QObject *p_parent = nullptr);
bool isReady() const;
void findText(const QStringList &p_texts, FindOptions p_options, int p_currentMatchLine = -1);
// Functions to be called from web side.
public slots:
void setReady(bool p_ready);
void setFindText(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
// Signals to be connected at cpp side.
signals:
void ready();
void findTextReady(const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex);
// Signals to be connected at web side.
signals:
void findTextRequested(const QStringList &p_texts, const QJsonObject &p_options, int p_currentMatchLine);
protected:
void pendAction(const std::function<void()> &p_func);
void invokeCallback(quint64 p_id, void *p_data);
quint64 addCallback(const CallbackPool::Callback &p_callback);
private:
struct FindOption
{
QJsonObject toJson() const;
bool m_findBackward = false;
bool m_caseSensitive = false;
bool m_wholeWordOnly = false;
bool m_regularExpression = false;
};
// Whether web side is ready.
bool m_ready = false;
// Pending actions for the editor once it is ready.
QVector<std::function<void()>> m_pendingActions;
CallbackPool m_callbackPool;
};
}
#endif // WEBVIEWADAPTER_H

View File

@ -325,3 +325,19 @@ FindOptions FindAndReplaceWidget::getOptions() const
{
return m_options;
}
void FindAndReplaceWidget::setOptionsEnabled(FindOptions p_options, bool p_enabled)
{
if (p_options & FindOption::CaseSensitive) {
m_caseSensitiveCheckBox->setEnabled(p_enabled);
}
if (p_options & FindOption::WholeWordOnly) {
m_wholeWordOnlyCheckBox->setEnabled(p_enabled);
}
if (p_options & FindOption::RegularExpression) {
m_regularExpressionCheckBox->setEnabled(p_enabled);
}
if (p_options & FindOption::IncrementalSearch) {
m_incrementalSearchCheckBox->setEnabled(p_enabled);
}
}

View File

@ -29,6 +29,8 @@ namespace vnotex
FindOptions getOptions() const;
void setOptionsEnabled(FindOptions p_options, bool p_enabled);
signals:
void findTextChanged(const QString &p_text, FindOptions p_options);

View File

@ -140,7 +140,7 @@ void MarkdownViewWindow::setModeInternal(ViewWindowMode p_mode, bool p_syncBuffe
setupViewer();
// Must show the viewer to let it init with the correct DPI.
// Will hide it when viewerReady().
// Will hide it when ready().
m_viewer->show();
}
@ -361,7 +361,7 @@ void MarkdownViewWindow::setupTextEditor()
updateEditorFromConfig();
// Connect viewer and editor.
connect(adapter(), &MarkdownViewerAdapter::viewerReady,
connect(adapter(), &MarkdownViewerAdapter::ready,
m_editor->getHighlighter(), &vte::PegMarkdownHighlighter::updateHighlight);
connect(m_editor, &MarkdownEditor::htmlToMarkdownRequested,
adapter(), &MarkdownViewerAdapter::htmlToMarkdownRequested);
@ -494,7 +494,7 @@ void MarkdownViewWindow::setupViewer()
this, [this](const QStringList &p_texts, int p_totalMatches, int p_currentMatchIndex) {
this->showFindResult(p_texts, p_totalMatches, p_currentMatchIndex);
});
connect(adapter, &MarkdownViewerAdapter::viewerReady,
connect(adapter, &MarkdownViewerAdapter::ready,
this, [this]() {
m_viewerReady = true;

View File

@ -0,0 +1,292 @@
#include "mindmapviewwindow.h"
#include <QToolBar>
#include <QSplitter>
#include <core/vnotex.h>
#include <core/thememgr.h>
#include <core/htmltemplatehelper.h>
#include <core/configmgr.h>
#include <core/editorconfig.h>
#include <core/mindmapeditorconfig.h>
#include <utils/utils.h>
#include <utils/pathutils.h>
#include "toolbarhelper.h"
#include "findandreplacewidget.h"
#include "editors/mindmapeditor.h"
#include "editors/mindmapeditoradapter.h"
using namespace vnotex;
MindMapViewWindow::MindMapViewWindow(QWidget *p_parent)
: ViewWindow(p_parent)
{
m_mode = ViewWindowMode::Edit;
setupUI();
}
void MindMapViewWindow::setupUI()
{
setupEditor();
setCentralWidget(m_editor);
setupToolBar();
}
void MindMapViewWindow::setupEditor()
{
Q_ASSERT(!m_editor);
const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
const auto &mindMapEditorConfig = editorConfig.getMindMapEditorConfig();
updateConfigRevision();
HtmlTemplateHelper::updateMindMapEditorTemplate(mindMapEditorConfig);
auto adapter = new MindMapEditorAdapter(nullptr);
m_editor = new MindMapEditor(adapter,
VNoteX::getInst().getThemeMgr().getBaseBackground(),
1.0,
this);
connect(m_editor, &MindMapEditor::contentsChanged,
this, [this]() {
getBuffer()->setModified(m_editor->isModified());
getBuffer()->invalidateContent(
this, [this](int p_revision) {
this->setBufferRevisionAfterInvalidation(p_revision);
});
});
}
QString MindMapViewWindow::getLatestContent() const
{
QString content;
adapter()->saveData([&content](const QString &p_data) {
content = p_data;
});
while (content.isNull()) {
Utils::sleepWait(50);
}
return content;
}
QString MindMapViewWindow::selectedText() const
{
return m_editor->selectedText();
}
void MindMapViewWindow::setMode(ViewWindowMode p_mode)
{
Q_UNUSED(p_mode);
Q_ASSERT(false);
}
void MindMapViewWindow::openTwice(const QSharedPointer<FileOpenParameters> &p_paras)
{
Q_UNUSED(p_paras);
}
ViewWindowSession MindMapViewWindow::saveSession() const
{
auto session = ViewWindow::saveSession();
return session;
}
void MindMapViewWindow::applySnippet(const QString &p_name)
{
Q_UNUSED(p_name);
}
void MindMapViewWindow::applySnippet()
{
}
void MindMapViewWindow::fetchWordCountInfo(const std::function<void(const WordCountInfo &)> &p_callback) const
{
Q_UNUSED(p_callback);
}
void MindMapViewWindow::handleEditorConfigChange()
{
if (updateConfigRevision()) {
const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
const auto &mindMapEditorConfig = editorConfig.getMindMapEditorConfig();
HtmlTemplateHelper::updateMindMapEditorTemplate(mindMapEditorConfig);
}
}
void MindMapViewWindow::setModified(bool p_modified)
{
m_editor->setModified(p_modified);
}
void MindMapViewWindow::print()
{
}
void MindMapViewWindow::syncEditorFromBuffer()
{
auto buffer = getBuffer();
if (buffer) {
m_editor->setHtml(HtmlTemplateHelper::getMindMapEditorTemplate(),
PathUtils::pathToUrl(buffer->getContentPath()));
adapter()->setData(buffer->getContent());
m_editor->setModified(buffer->isModified());
} else {
m_editor->setHtml("");
adapter()->setData("");
m_editor->setModified(false);
}
m_bufferRevision = buffer ? buffer->getRevision() : 0;
}
void MindMapViewWindow::syncEditorFromBufferContent()
{
auto buffer = getBuffer();
Q_ASSERT(buffer);
adapter()->setData(buffer->getContent());
m_editor->setModified(buffer->isModified());
m_bufferRevision = buffer->getRevision();
}
void MindMapViewWindow::scrollUp()
{
}
void MindMapViewWindow::scrollDown()
{
}
void MindMapViewWindow::zoom(bool p_zoomIn)
{
Q_UNUSED(p_zoomIn);
}
MindMapEditorAdapter *MindMapViewWindow::adapter() const
{
if (m_editor) {
return dynamic_cast<MindMapEditorAdapter *>(m_editor->adapter());
}
return nullptr;
}
bool MindMapViewWindow::updateConfigRevision()
{
bool changed = false;
const auto &editorConfig = ConfigMgr::getInst().getEditorConfig();
if (m_editorConfigRevision != editorConfig.revision()) {
changed = true;
m_editorConfigRevision = editorConfig.revision();
}
if (m_editorConfigRevision != editorConfig.getMindMapEditorConfig().revision()) {
changed = true;
m_editorConfigRevision = editorConfig.getMindMapEditorConfig().revision();
}
return changed;
}
void MindMapViewWindow::setupToolBar()
{
auto toolBar = createToolBar(this);
addToolBar(toolBar);
addAction(toolBar, ViewWindowToolBarHelper::Save);
toolBar->addSeparator();
addAction(toolBar, ViewWindowToolBarHelper::Attachment);
addAction(toolBar, ViewWindowToolBarHelper::Tag);
ToolBarHelper::addSpacer(toolBar);
addAction(toolBar, ViewWindowToolBarHelper::FindAndReplace);
addAction(toolBar, ViewWindowToolBarHelper::Debug);
}
void MindMapViewWindow::toggleDebug()
{
if (m_debugViewer) {
bool shouldEnable = !m_debugViewer->isVisible();
m_debugViewer->setVisible(shouldEnable);
m_editor->page()->setDevToolsPage(shouldEnable ? m_debugViewer->page() : nullptr);
} else {
setupDebugViewer();
m_editor->page()->setDevToolsPage(m_debugViewer->page());
}
}
void MindMapViewWindow::setupDebugViewer()
{
Q_ASSERT(!m_debugViewer);
// Need a vertical QSplitter to hold the original QSplitter and the debug viewer.
auto mainSplitter = new QSplitter(this);
mainSplitter->setContentsMargins(0, 0, 0, 0);
mainSplitter->setOrientation(Qt::Vertical);
replaceCentralWidget(mainSplitter);
mainSplitter->addWidget(m_editor);
mainSplitter->setFocusProxy(m_editor);
m_debugViewer = new WebViewer(VNoteX::getInst().getThemeMgr().getBaseBackground(), this);
m_debugViewer->resize(m_editor->width(), m_editor->height() / 2);
mainSplitter->addWidget(m_debugViewer);
}
void MindMapViewWindow::handleFindTextChanged(const QString &p_text, FindOptions p_options)
{
if (p_options & FindOption::IncrementalSearch) {
m_editor->findText(p_text, p_options);
}
}
void MindMapViewWindow::handleFindNext(const QStringList &p_texts, FindOptions p_options)
{
// We do not use mark.js for searching as the contents are mainly SVG.
m_editor->findText(p_texts.empty() ? QString() : p_texts[0], p_options);
}
void MindMapViewWindow::handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
{
Q_UNUSED(p_text);
Q_UNUSED(p_options);
Q_UNUSED(p_replaceText);
showMessage(tr("Replace is not supported yet"));
}
void MindMapViewWindow::handleReplaceAll(const QString &p_text, FindOptions p_options, const QString &p_replaceText)
{
Q_UNUSED(p_text);
Q_UNUSED(p_options);
Q_UNUSED(p_replaceText);
showMessage(tr("Replace is not supported yet"));
}
void MindMapViewWindow::handleFindAndReplaceWidgetClosed()
{
m_editor->findText(QString(), FindOption::FindNone);
}
void MindMapViewWindow::showFindAndReplaceWidget()
{
bool isFirstTime = !m_findAndReplace;
ViewWindow::showFindAndReplaceWidget();
if (isFirstTime) {
m_findAndReplace->setReplaceEnabled(false);
m_findAndReplace->setOptionsEnabled(FindOption::WholeWordOnly | FindOption::RegularExpression, false);
}
}

View File

@ -0,0 +1,93 @@
#ifndef MINDMAPVIEWWINDOW_H
#define MINDMAPVIEWWINDOW_H
#include "viewwindow.h"
#include <QScopedPointer>
class QWebEngineView;
namespace vnotex
{
class MindMapEditor;
class MindMapEditorAdapter;
class MindMapViewWindow : public ViewWindow
{
Q_OBJECT
public:
explicit MindMapViewWindow(QWidget *p_parent = nullptr);
QString getLatestContent() const Q_DECL_OVERRIDE;
QString selectedText() const Q_DECL_OVERRIDE;
void setMode(ViewWindowMode p_mode) Q_DECL_OVERRIDE;
void openTwice(const QSharedPointer<FileOpenParameters> &p_paras) Q_DECL_OVERRIDE;
ViewWindowSession saveSession() const Q_DECL_OVERRIDE;
void applySnippet(const QString &p_name) Q_DECL_OVERRIDE;
void applySnippet() Q_DECL_OVERRIDE;
void fetchWordCountInfo(const std::function<void(const WordCountInfo &)> &p_callback) const Q_DECL_OVERRIDE;
public slots:
void handleEditorConfigChange() Q_DECL_OVERRIDE;
protected slots:
void setModified(bool p_modified) Q_DECL_OVERRIDE;
void print() Q_DECL_OVERRIDE;
void toggleDebug() Q_DECL_OVERRIDE;
void handleFindTextChanged(const QString &p_text, FindOptions p_options) Q_DECL_OVERRIDE;
void handleFindNext(const QStringList &p_texts, FindOptions p_options) Q_DECL_OVERRIDE;
void handleReplace(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
void handleReplaceAll(const QString &p_text, FindOptions p_options, const QString &p_replaceText) Q_DECL_OVERRIDE;
void handleFindAndReplaceWidgetClosed() Q_DECL_OVERRIDE;
void showFindAndReplaceWidget() Q_DECL_OVERRIDE;
protected:
void syncEditorFromBuffer() Q_DECL_OVERRIDE;
void syncEditorFromBufferContent() Q_DECL_OVERRIDE;
void scrollUp() Q_DECL_OVERRIDE;
void scrollDown() Q_DECL_OVERRIDE;
void zoom(bool p_zoomIn) Q_DECL_OVERRIDE;
private:
void setupUI();
void setupToolBar();
void setupEditor();
MindMapEditorAdapter *adapter() const;
bool updateConfigRevision();
void setupDebugViewer();
// Managed by QObject.
MindMapEditor *m_editor = nullptr;
// Used to debug web view.
QWebEngineView *m_debugViewer = nullptr;
int m_editorConfigRevision = 0;
};
}
#endif // MINDMAPVIEWWINDOW_H

View File

@ -24,6 +24,16 @@ void PdfViewWindow::setupUI()
{
setupViewer();
setCentralWidget(m_viewer);
setupToolBar();
}
void PdfViewWindow::setupToolBar()
{
auto toolBar = createToolBar(this);
addToolBar(toolBar);
addAction(toolBar, ViewWindowToolBarHelper::Tag);
}
void PdfViewWindow::setupViewer()
@ -68,7 +78,6 @@ void PdfViewWindow::openTwice(const QSharedPointer<FileOpenParameters> &p_paras)
ViewWindowSession PdfViewWindow::saveSession() const
{
auto session = ViewWindow::saveSession();
session.m_lineNumber = 1;
return session;
}

View File

@ -11,7 +11,6 @@ namespace vnotex
{
class PdfViewer;
class PdfViewerAdapter;
class EditorConfig;
class PdfViewWindow : public ViewWindow
{
@ -57,6 +56,8 @@ namespace vnotex
private:
void setupUI();
void setupToolBar();
void setupViewer();
PdfViewerAdapter *adapter() const;

View File

@ -165,11 +165,6 @@ bool TextViewWindow::updateConfigRevision()
return changed;
}
void TextViewWindow::setBufferRevisionAfterInvalidation(int p_bufferRevision)
{
m_bufferRevision = p_bufferRevision;
}
void TextViewWindow::setMode(ViewWindowMode p_mode)
{
Q_UNUSED(p_mode);

View File

@ -79,11 +79,6 @@ namespace vnotex
void setupToolBar();
// When we have new changes to the buffer content from our ViewWindow,
// we will invalidate the contents of the buffer and the buffer will
// call this function to tell us now the latest buffer revision.
void setBufferRevisionAfterInvalidation(int p_bufferRevision);
void updateEditorFromConfig();
void handleFileOpenParameters(const QSharedPointer<FileOpenParameters> &p_paras);

View File

@ -1402,3 +1402,8 @@ void ViewWindow::print()
void ViewWindow::clearHighlights()
{
}
void ViewWindow::setBufferRevisionAfterInvalidation(int p_bufferRevision)
{
m_bufferRevision = p_bufferRevision;
}

View File

@ -227,6 +227,11 @@ namespace vnotex
// Sync buffer content changes to editor.
virtual void syncEditorFromBufferContent() = 0;
// When we have new changes to the buffer content from our ViewWindow,
// we will invalidate the contents of the buffer and the buffer will
// call this function to tell us now the latest buffer revision.
void setBufferRevisionAfterInvalidation(int p_bufferRevision);
// Whether we are in a mode that enable us to insert text.
bool inModeCanInsert() const;
@ -242,7 +247,7 @@ namespace vnotex
void showZoomDelta(int p_delta);
void showFindAndReplaceWidget();
virtual void showFindAndReplaceWidget();
void hideFindAndReplaceWidget();

View File

@ -2,6 +2,8 @@
#include "webpage.h"
#include <QWebEnginePage>
#include <utils/utils.h>
using namespace vnotex;
@ -38,3 +40,20 @@ WebViewer::WebViewer(const QColor &p_background, QWidget *p_parent)
WebViewer::~WebViewer()
{
}
void WebViewer::findText(const QString &p_text, FindOptions p_options)
{
if (p_options & FindOption::RegularExpression) {
return;
}
QWebEnginePage::FindFlags flags;
if (p_options & FindOption::FindBackward) {
flags |= QWebEnginePage::FindFlag::FindBackward;
}
if (p_options & FindOption::CaseSensitive) {
flags |= QWebEnginePage::FindFlag::FindCaseSensitively;
}
QWebEngineView::findText(p_text, flags);
}

View File

@ -3,6 +3,8 @@
#include <QWebEngineView>
#include <core/global.h>
namespace vnotex
{
class WebViewer : public QWebEngineView
@ -15,6 +17,8 @@ namespace vnotex
virtual ~WebViewer();
void findText(const QString &p_text, FindOptions p_options);
signals:
void linkHovered(const QString &p_url);
};

View File

@ -51,12 +51,15 @@ SOURCES += \
$$PWD/editors/markdowntablehelper.cpp \
$$PWD/editors/markdownviewer.cpp \
$$PWD/editors/markdownvieweradapter.cpp \
$$PWD/editors/mindmapeditor.cpp \
$$PWD/editors/mindmapeditoradapter.cpp \
$$PWD/editors/pdfviewer.cpp \
$$PWD/editors/pdfvieweradapter.cpp \
$$PWD/editors/plantumlhelper.cpp \
$$PWD/editors/previewhelper.cpp \
$$PWD/editors/statuswidget.cpp \
$$PWD/editors/texteditor.cpp \
$$PWD/editors/webviewadapter.cpp \
$$PWD/editreaddiscardaction.cpp \
$$PWD/filesystemviewer.cpp \
$$PWD/dialogs/folderfilesfilterwidget.cpp \
@ -77,6 +80,7 @@ SOURCES += \
$$PWD/locationlist.cpp \
$$PWD/mainwindow.cpp \
$$PWD/markdownviewwindow.cpp \
$$PWD/mindmapviewwindow.cpp \
$$PWD/navigationmodemgr.cpp \
$$PWD/notebookexplorersession.cpp \
$$PWD/outlinepopup.cpp \
@ -186,12 +190,15 @@ HEADERS += \
$$PWD/editors/markdowntablehelper.h \
$$PWD/editors/markdownviewer.h \
$$PWD/editors/markdownvieweradapter.h \
$$PWD/editors/mindmapeditor.h \
$$PWD/editors/mindmapeditoradapter.h \
$$PWD/editors/pdfviewer.h \
$$PWD/editors/pdfvieweradapter.h \
$$PWD/editors/plantumlhelper.h \
$$PWD/editors/previewhelper.h \
$$PWD/editors/statuswidget.h \
$$PWD/editors/texteditor.h \
$$PWD/editors/webviewadapter.h \
$$PWD/editreaddiscardaction.h \
$$PWD/filesystemviewer.h \
$$PWD/dialogs/folderfilesfilterwidget.h \
@ -213,6 +220,7 @@ HEADERS += \
$$PWD/locationlist.h \
$$PWD/mainwindow.h \
$$PWD/markdownviewwindow.h \
$$PWD/mindmapviewwindow.h \
$$PWD/navigationmodemgr.h \
$$PWD/navigationmodewrapper.h \
$$PWD/notebookexplorersession.h \