mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support local PlantUml and Graphviz (#1776)
This commit is contained in:
parent
1d4e2b14b6
commit
79abddd802
@ -1 +1 @@
|
||||
Subproject commit 9b9aa9dd1d8ebec02daee23cb26d0b12ae00cf69
|
||||
Subproject commit 5e02a011cb7e4979e897c0670fe8ac8f1060feb4
|
@ -24,7 +24,7 @@
|
||||
using namespace vnotex;
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
// #define VX_DEBUG_WEB
|
||||
// #define VX_DEBUG_WEB
|
||||
#endif
|
||||
|
||||
const QString ConfigMgr::c_orgName = "VNote";
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <QJsonObject>
|
||||
#include <QScopedPointer>
|
||||
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class MainConfig;
|
||||
@ -14,7 +16,7 @@ namespace vnotex
|
||||
class EditorConfig;
|
||||
class WidgetConfig;
|
||||
|
||||
class ConfigMgr : public QObject
|
||||
class ConfigMgr : public QObject, private Noncopyable
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -47,6 +47,7 @@ HEADERS += \
|
||||
$$PWD/logger.h \
|
||||
$$PWD/mainconfig.h \
|
||||
$$PWD/markdowneditorconfig.h \
|
||||
$$PWD/noncopyable.h \
|
||||
$$PWD/quickaccesshelper.h \
|
||||
$$PWD/singleinstanceguard.h \
|
||||
$$PWD/iconfig.h \
|
||||
|
@ -11,6 +11,9 @@ namespace vnotex
|
||||
{
|
||||
ViewWindowMode m_mode = ViewWindowMode::Read;
|
||||
|
||||
// Force to enter m_mode.
|
||||
bool m_forceMode = false;
|
||||
|
||||
// Whether focus to the opened window.
|
||||
bool m_focus = true;
|
||||
|
||||
|
@ -30,8 +30,15 @@ void MarkdownEditorConfig::init(const QJsonObject &p_app, const QJsonObject &p_u
|
||||
loadExportResource(appObj, userObj);
|
||||
|
||||
m_webPlantUml = READBOOL(QStringLiteral("web_plantuml"));
|
||||
|
||||
m_plantUmlJar = READSTR(QStringLiteral("plantuml_jar"));
|
||||
|
||||
m_plantUmlCommand = READSTR(QStringLiteral("plantuml_command"));
|
||||
|
||||
m_webGraphviz = READBOOL(QStringLiteral("web_graphviz"));
|
||||
|
||||
m_graphvizExe = READSTR(QStringLiteral("graphviz_exe"));
|
||||
|
||||
m_prependDotInRelativeLink = READBOOL(QStringLiteral("prepend_dot_in_relative_link"));
|
||||
m_confirmBeforeClearObsoleteImages = READBOOL(QStringLiteral("confirm_before_clear_obsolete_images"));
|
||||
m_insertFileNameAsTitle = READBOOL(QStringLiteral("insert_file_name_as_title"));
|
||||
@ -63,7 +70,10 @@ QJsonObject MarkdownEditorConfig::toJson() const
|
||||
obj[QStringLiteral("viewer_resource")] = saveViewerResource();
|
||||
obj[QStringLiteral("export_resource")] = saveExportResource();
|
||||
obj[QStringLiteral("web_plantuml")] = m_webPlantUml;
|
||||
obj[QStringLiteral("plantuml_jar")] = m_plantUmlJar;
|
||||
obj[QStringLiteral("plantuml_command")] = m_plantUmlCommand;
|
||||
obj[QStringLiteral("web_graphviz")] = m_webGraphviz;
|
||||
obj[QStringLiteral("graphviz_exe")] = m_graphvizExe;
|
||||
obj[QStringLiteral("prepend_dot_in_relative_link")] = m_prependDotInRelativeLink;
|
||||
obj[QStringLiteral("confirm_before_clear_obsolete_images")] = m_confirmBeforeClearObsoleteImages;
|
||||
obj[QStringLiteral("insert_file_name_as_title")] = m_insertFileNameAsTitle;
|
||||
@ -167,11 +177,46 @@ bool MarkdownEditorConfig::getWebPlantUml() const
|
||||
return m_webPlantUml;
|
||||
}
|
||||
|
||||
void MarkdownEditorConfig::setWebPlantUml(bool p_enabled)
|
||||
{
|
||||
updateConfig(m_webPlantUml, p_enabled, this);
|
||||
}
|
||||
|
||||
const QString &MarkdownEditorConfig::getPlantUmlJar() const
|
||||
{
|
||||
return m_plantUmlJar;
|
||||
}
|
||||
|
||||
void MarkdownEditorConfig::setPlantUmlJar(const QString &p_jar)
|
||||
{
|
||||
updateConfig(m_plantUmlJar, p_jar, this);
|
||||
}
|
||||
|
||||
const QString &MarkdownEditorConfig::getPlantUmlCommand() const
|
||||
{
|
||||
return m_plantUmlCommand;
|
||||
}
|
||||
|
||||
bool MarkdownEditorConfig::getWebGraphviz() const
|
||||
{
|
||||
return m_webGraphviz;
|
||||
}
|
||||
|
||||
void MarkdownEditorConfig::setWebGraphviz(bool p_enabled)
|
||||
{
|
||||
updateConfig(m_webGraphviz, p_enabled, this);
|
||||
}
|
||||
|
||||
const QString &MarkdownEditorConfig::getGraphvizExe() const
|
||||
{
|
||||
return m_graphvizExe;
|
||||
}
|
||||
|
||||
void MarkdownEditorConfig::setGraphvizExe(const QString &p_exe)
|
||||
{
|
||||
updateConfig(m_graphvizExe, p_exe, this);
|
||||
}
|
||||
|
||||
bool MarkdownEditorConfig::getPrependDotInRelativeLink() const
|
||||
{
|
||||
return m_prependDotInRelativeLink;
|
||||
|
@ -48,8 +48,18 @@ namespace vnotex
|
||||
const WebResource &getExportResource() const;
|
||||
|
||||
bool getWebPlantUml() const;
|
||||
void setWebPlantUml(bool p_enabled);
|
||||
|
||||
const QString &getPlantUmlJar() const;
|
||||
void setPlantUmlJar(const QString &p_jar);
|
||||
|
||||
const QString &getPlantUmlCommand() const;
|
||||
|
||||
bool getWebGraphviz() const;
|
||||
void setWebGraphviz(bool p_enabled);
|
||||
|
||||
const QString &getGraphvizExe() const;
|
||||
void setGraphvizExe(const QString &p_exe);
|
||||
|
||||
bool getPrependDotInRelativeLink() const;
|
||||
|
||||
@ -124,8 +134,18 @@ namespace vnotex
|
||||
// Whether use javascript or external program to render PlantUML.
|
||||
bool m_webPlantUml = true;
|
||||
|
||||
// File path of the JAR to render PlantUmL.
|
||||
QString m_plantUmlJar;
|
||||
|
||||
// Command to render PlantUml. If set, will ignore m_plantUmlJar.
|
||||
// %1: the format to render in.
|
||||
QString m_plantUmlCommand;
|
||||
|
||||
bool m_webGraphviz = true;
|
||||
|
||||
// Graphviz executable file.
|
||||
QString m_graphvizExe;
|
||||
|
||||
// Whether prepend a dot in front of the relative link, like images.
|
||||
bool m_prependDotInRelativeLink = false;
|
||||
|
||||
|
18
src/core/noncopyable.h
Normal file
18
src/core/noncopyable.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef NONCOPYABLE_H
|
||||
#define NONCOPYABLE_H
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class Noncopyable
|
||||
{
|
||||
protected:
|
||||
Noncopyable() = default;
|
||||
|
||||
virtual ~Noncopyable() = default;
|
||||
|
||||
Noncopyable(const Noncopyable&) = delete;
|
||||
Noncopyable &operator=(const Noncopyable&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NONCOPYABLE_H
|
@ -4,6 +4,7 @@
|
||||
#include <QObject>
|
||||
#include <QScopedPointer>
|
||||
|
||||
#include "noncopyable.h"
|
||||
#include "thememgr.h"
|
||||
#include "global.h"
|
||||
|
||||
@ -18,7 +19,7 @@ namespace vnotex
|
||||
class Notebook;
|
||||
struct ComplexLocation;
|
||||
|
||||
class VNoteX : public QObject
|
||||
class VNoteX : public QObject, private Noncopyable
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -28,9 +29,6 @@ namespace vnotex
|
||||
return inst;
|
||||
}
|
||||
|
||||
VNoteX(const VNoteX &) = delete;
|
||||
void operator=(const VNoteX &) = delete;
|
||||
|
||||
// MUST be called to load some heavy data.
|
||||
// It is good to call it after MainWindow is shown.
|
||||
void initLoad();
|
||||
|
@ -261,8 +261,15 @@
|
||||
},
|
||||
"//comment" : "Whether use javascript or external program to render PlantUML",
|
||||
"web_plantuml" : true,
|
||||
"//commnet" : "Local PlantUML JAR file to render PlantUML",
|
||||
"plantuml_jar" : "",
|
||||
"//commnet" : "Command to render PlantUML via stdin and stdout (overrides plantuml_jar)",
|
||||
"//commnet" : "- %1: the format to render in",
|
||||
"plantuml_command" : "",
|
||||
"//comment" : "Whether use javascript or external program to render Graphviz",
|
||||
"web_graphviz" : true,
|
||||
"//commnet" : "Local Graphviz executable file to render Graphviz",
|
||||
"graphviz_exe" : "",
|
||||
"//comment" : "Whether prepend a dot at front in relative link like images",
|
||||
"prepend_dot_in_relative_link" : false,
|
||||
"//comment" : "Whether ask for user confirmation before clearing obsolete images",
|
||||
|
@ -73,6 +73,9 @@
|
||||
"background-color" : "#333842",
|
||||
"selected-text-color" : "#e3e5e9",
|
||||
"selected-background-color" : "#0c7bff"
|
||||
},
|
||||
"Preview" : {
|
||||
"background-color" : "#b0bec5"
|
||||
}
|
||||
},
|
||||
"markdown-syntax-styles" : {
|
||||
|
@ -30,7 +30,7 @@ class GraphRenderer extends VxWorker {
|
||||
registerInternal() {
|
||||
this.vnotex.on('basicMarkdownRendered', () => {
|
||||
this.reset();
|
||||
this.renderCodeNodes(this.vnotex.contentContainer);
|
||||
this.renderCodeNodes();
|
||||
});
|
||||
|
||||
this.vnotex.getWorker('markdownit').addLangsToSkipHighlight(this.langs);
|
||||
@ -78,8 +78,9 @@ class GraphRenderer extends VxWorker {
|
||||
|
||||
// Interface 2.
|
||||
// Get code nodes from markdownIt directly.
|
||||
renderCodeNodes(p_node) {
|
||||
renderCodeNodes() {
|
||||
this.nodesToRender = this.vnotex.getWorker('markdownit').getCodeNodes(this.langs);
|
||||
this.numOfRenderedNodes = 0;
|
||||
this.doRender();
|
||||
}
|
||||
|
||||
|
@ -14,21 +14,30 @@ class Graphviz extends GraphRenderer {
|
||||
this.format = 'svg';
|
||||
|
||||
this.langs = ['dot'];
|
||||
|
||||
this.useWeb = true;
|
||||
|
||||
this.nextLocalGraphIndex = 1;
|
||||
}
|
||||
|
||||
registerInternal() {
|
||||
this.vnotex.on('basicMarkdownRendered', () => {
|
||||
this.reset();
|
||||
this.renderCodeNodes(this.vnotex.contentContainer,
|
||||
window.vxOptions.transformSvgToPngEnabled ? 'png' : 'svg');
|
||||
this.renderCodeNodes(window.vxOptions.transformSvgToPngEnabled ? 'png' : 'svg');
|
||||
});
|
||||
|
||||
this.vnotex.getWorker('markdownit').addLangsToSkipHighlight(this.langs);
|
||||
this.useWeb = window.vxOptions.webGraphviz;
|
||||
if (!this.useWeb) {
|
||||
this.extraScripts = [];
|
||||
}
|
||||
}
|
||||
|
||||
initialize(p_callback) {
|
||||
return super.initialize(() => {
|
||||
this.viz = new Viz();
|
||||
if (this.useWeb) {
|
||||
this.viz = new Viz();
|
||||
}
|
||||
p_callback();
|
||||
});
|
||||
}
|
||||
@ -41,13 +50,22 @@ class Graphviz extends GraphRenderer {
|
||||
}
|
||||
|
||||
// Interface 2.
|
||||
renderCodeNodes(p_node, p_format) {
|
||||
renderCodeNodes(p_format) {
|
||||
this.format = p_format;
|
||||
|
||||
super.renderCodeNodes(p_node);
|
||||
super.renderCodeNodes();
|
||||
}
|
||||
|
||||
renderOne(p_node, p_idx) {
|
||||
if (this.useWeb) {
|
||||
this.renderOnline(p_node, p_idx);
|
||||
} else {
|
||||
this.renderLocal(p_node);
|
||||
}
|
||||
}
|
||||
|
||||
renderOnline(p_node, p_idx) {
|
||||
console.assert(this.viz);
|
||||
let func = function(p_graphviz, p_renderNode) {
|
||||
let graphviz = p_graphviz;
|
||||
let node = p_renderNode;
|
||||
@ -85,13 +103,61 @@ class Graphviz extends GraphRenderer {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
renderLocal(p_node) {
|
||||
let func = function(p_graphviz, p_renderNode) {
|
||||
let graphviz = p_graphviz;
|
||||
let node = p_renderNode;
|
||||
return function(format, data) {
|
||||
if (node && data.length > 0) {
|
||||
let obj = null;
|
||||
if (format == 'svg') {
|
||||
obj = document.createElement('div');
|
||||
obj.classList.add(graphviz.graphDivClass);
|
||||
obj.innerHTML = data;
|
||||
window.vxImageViewer.setupSVGToView(obj.children[0], false);
|
||||
} else {
|
||||
obj = document.createElement('div');
|
||||
obj.classList.add(graphviz.graphDivClass);
|
||||
|
||||
let imgObj = document.createElement('img');
|
||||
obj.appendChild(imgObj);
|
||||
imgObj.src = "data:image/" + format + ";base64, " + data;
|
||||
window.vxImageViewer.setupIMGToView(imgObj);
|
||||
}
|
||||
|
||||
Utils.checkSourceLine(p_node, obj);
|
||||
|
||||
Utils.replaceNodeWithPreCheck(p_node, obj);
|
||||
}
|
||||
graphviz.finishRenderingOne();
|
||||
};
|
||||
};
|
||||
|
||||
let callback = func(this, p_node);
|
||||
this.vnotex.renderGraph(this.id,
|
||||
this.nextLocalGraphIndex++,
|
||||
this.format,
|
||||
'dot',
|
||||
p_node.textContent,
|
||||
function(id, index, format, data) {
|
||||
callback(format, data);
|
||||
});
|
||||
}
|
||||
|
||||
// Render a graph from @p_text in SVG format.
|
||||
// p_callback(svgNode).
|
||||
renderText(p_text, p_callback) {
|
||||
console.assert(this.useWeb, "renderText() should be called only when web Graphviz is enabled");
|
||||
|
||||
let func = () => {
|
||||
if (!this.viz) {
|
||||
console.log("viz is not ready yet");
|
||||
return;
|
||||
}
|
||||
this.viz.renderSVGElement(p_text)
|
||||
.then(p_callback)
|
||||
.catch(function(err) {
|
||||
|
@ -47,6 +47,10 @@ new QWebChannel(qt.webChannelTransport,
|
||||
window.vnotex.saveContent();
|
||||
});
|
||||
|
||||
adapter.graphRenderDataReady.connect(function(p_id, p_index, p_format, p_data) {
|
||||
window.vnotex.graphRenderDataReady(p_id, p_index, p_format, p_data);
|
||||
});
|
||||
|
||||
console.log('QWebChannel has been set up');
|
||||
if (window.vnotex.initialized) {
|
||||
window.vnotex.kickOffMarkdown();
|
||||
|
@ -14,16 +14,24 @@ class PlantUml extends GraphRenderer {
|
||||
this.format = 'svg';
|
||||
|
||||
this.langs = ['plantuml', 'puml'];
|
||||
|
||||
this.useWeb = true;
|
||||
|
||||
this.nextLocalGraphIndex = 1;
|
||||
}
|
||||
|
||||
registerInternal() {
|
||||
this.vnotex.on('basicMarkdownRendered', () => {
|
||||
this.reset();
|
||||
this.renderCodeNodes(this.vnotex.contentContainer,
|
||||
window.vxOptions.transformSvgToPngEnabled ? 'png' : 'svg');
|
||||
this.renderCodeNodes(window.vxOptions.transformSvgToPngEnabled ? 'png' : 'svg');
|
||||
});
|
||||
|
||||
this.vnotex.getWorker('markdownit').addLangsToSkipHighlight(this.langs);
|
||||
|
||||
this.useWeb = window.vxOptions.webPlantUml;
|
||||
if (!this.useWeb) {
|
||||
this.extraScripts = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,10 +43,10 @@ class PlantUml extends GraphRenderer {
|
||||
}
|
||||
|
||||
// Interface 2.
|
||||
renderCodeNodes(p_node, p_format) {
|
||||
renderCodeNodes(p_format) {
|
||||
this.format = p_format;
|
||||
|
||||
super.renderCodeNodes(p_node);
|
||||
super.renderCodeNodes();
|
||||
}
|
||||
|
||||
renderOne(p_node, p_idx) {
|
||||
@ -46,20 +54,26 @@ class PlantUml extends GraphRenderer {
|
||||
let plantUml = p_plantUml;
|
||||
let node = p_node;
|
||||
return function(p_format, p_data) {
|
||||
plantUml.handlePlantUmlResult(node, 0, p_format, p_data);
|
||||
plantUml.handlePlantUmlResult(node, p_format, p_data);
|
||||
};
|
||||
};
|
||||
|
||||
this.renderOnline(this.serverUrl,
|
||||
this.format,
|
||||
p_node.textContent,
|
||||
func(this, p_node));
|
||||
if (this.useWeb) {
|
||||
this.renderOnline(this.serverUrl,
|
||||
this.format,
|
||||
p_node.textContent,
|
||||
func(this, p_node));
|
||||
} else {
|
||||
this.renderLocal(this.format, p_node.textContent, func(this, p_node));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Render a graph from @p_text in SVG format.
|
||||
// p_callback(format, data).
|
||||
renderText(p_text, p_callback) {
|
||||
console.assert(this.useWeb, "renderText() should be called only when web PlantUml is enabled");
|
||||
|
||||
let func = () => {
|
||||
this.renderOnline(this.serverUrl,
|
||||
'svg',
|
||||
@ -111,7 +125,19 @@ class PlantUml extends GraphRenderer {
|
||||
return url;
|
||||
}
|
||||
|
||||
handlePlantUmlResult(p_node, p_timeStamp, p_format, p_result) {
|
||||
// A helper function to render PlantUml via local JAR.
|
||||
renderLocal(p_format, p_text, p_callback) {
|
||||
this.vnotex.renderGraph(this.id,
|
||||
this.nextLocalGraphIndex++,
|
||||
p_format,
|
||||
'puml',
|
||||
p_text,
|
||||
function(id, index, format, data) {
|
||||
p_callback(format, data);
|
||||
});
|
||||
}
|
||||
|
||||
handlePlantUmlResult(p_node, p_format, p_result) {
|
||||
if (p_node && p_result.length > 0) {
|
||||
let obj = null;
|
||||
if (p_format == 'svg') {
|
||||
@ -120,9 +146,13 @@ class PlantUml extends GraphRenderer {
|
||||
obj.innerHTML = p_result;
|
||||
window.vxImageViewer.setupSVGToView(obj.children[0], false);
|
||||
} else {
|
||||
obj = document.createElement('img');
|
||||
obj.src = "data:image/" + p_format + ";base64, " + p_result;
|
||||
window.vxImageViewer.setupIMGToView(obj);
|
||||
obj = document.createElement('div');
|
||||
obj.classList.add(this.graphDivClass);
|
||||
|
||||
let imgObj = document.createElement('img');
|
||||
obj.appendChild(imgObj);
|
||||
imgObj.src = "data:image/" + p_format + ";base64, " + p_result;
|
||||
window.vxImageViewer.setupIMGToView(imgObj);
|
||||
}
|
||||
|
||||
Utils.checkSourceLine(p_node, obj);
|
||||
|
@ -39,6 +39,9 @@ class VNoteX extends EventEmitter {
|
||||
|
||||
this.sectionNumberBaseLevel = 2;
|
||||
|
||||
// Dict mapping from {id, index} to callback for renderGraph().
|
||||
this.renderGraphCallbacks = {}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
console.log('window load finished');
|
||||
|
||||
@ -307,6 +310,19 @@ class VNoteX extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
renderGraph(p_id, p_index, p_format, p_lang, p_text, p_callback) {
|
||||
this.renderGraphCallbacks[p_id + '_' + p_index] = p_callback;
|
||||
window.vxMarkdownAdapter.renderGraph(p_id, p_index, p_format, p_lang, p_text);
|
||||
}
|
||||
|
||||
graphRenderDataReady(p_id, p_index, p_format, p_data) {
|
||||
let key = p_id + '_' + p_index;
|
||||
if (key in this.renderGraphCallbacks) {
|
||||
this.renderGraphCallbacks[key](p_id, p_index, p_format, p_data);
|
||||
delete this.renderGraphCallbacks[key];
|
||||
}
|
||||
}
|
||||
|
||||
static detectOS() {
|
||||
let osName="Unknown OS";
|
||||
if (navigator.appVersion.indexOf("Win")!=-1) {
|
||||
|
@ -3,6 +3,11 @@ class VxWorker {
|
||||
constructor() {
|
||||
this.name = '';
|
||||
this.vnotex = null;
|
||||
|
||||
if (!window.vxWorkerId) {
|
||||
window.vxWorkerId = 1;
|
||||
}
|
||||
this.id = window.vxWorkerId++;
|
||||
}
|
||||
|
||||
// Called when registering this worker.
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include <widgets/widgetsfactory.h>
|
||||
#include <core/editorconfig.h>
|
||||
@ -16,6 +18,10 @@
|
||||
#include <utils/widgetutils.h>
|
||||
|
||||
#include "editorpage.h"
|
||||
#include <widgets/locationinputwithbrowsebutton.h>
|
||||
#include <widgets/messageboxhelper.h>
|
||||
#include <widgets/editors/plantumlhelper.h>
|
||||
#include <widgets/editors/graphvizhelper.h>
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
@ -76,6 +82,20 @@ void MarkdownEditorPage::loadInternal()
|
||||
m_smartTableCheckBox->setChecked(markdownConfig.getSmartTableEnabled());
|
||||
|
||||
m_spellCheckCheckBox->setChecked(markdownConfig.isSpellCheckEnabled());
|
||||
|
||||
{
|
||||
int idx = m_plantUmlModeComboBox->findData(markdownConfig.getWebPlantUml() ? 0 : 1);
|
||||
m_plantUmlModeComboBox->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
m_plantUmlJarFileInput->setText(markdownConfig.getPlantUmlJar());
|
||||
|
||||
{
|
||||
int idx = m_graphvizModeComboBox->findData(markdownConfig.getWebGraphviz() ? 0 : 1);
|
||||
m_graphvizModeComboBox->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
m_graphvizFileInput->setText(markdownConfig.getGraphvizExe());
|
||||
}
|
||||
|
||||
void MarkdownEditorPage::saveInternal()
|
||||
@ -118,6 +138,14 @@ void MarkdownEditorPage::saveInternal()
|
||||
|
||||
markdownConfig.setSpellCheckEnabled(m_spellCheckCheckBox->isChecked());
|
||||
|
||||
markdownConfig.setWebPlantUml(m_plantUmlModeComboBox->currentData().toInt() == 0);
|
||||
|
||||
markdownConfig.setPlantUmlJar(m_plantUmlJarFileInput->text());
|
||||
|
||||
markdownConfig.setWebGraphviz(m_graphvizModeComboBox->currentData().toInt() == 0);
|
||||
|
||||
markdownConfig.setGraphvizExe(m_graphvizFileInput->text());
|
||||
|
||||
EditorPage::notifyEditorConfigChange();
|
||||
}
|
||||
|
||||
@ -264,7 +292,7 @@ QGroupBox *MarkdownEditorPage::setupGeneralGroup()
|
||||
{
|
||||
auto sectionLayout = new QHBoxLayout();
|
||||
|
||||
m_sectionNumberComboBox = WidgetsFactory::createComboBox(this);
|
||||
m_sectionNumberComboBox = WidgetsFactory::createComboBox(box);
|
||||
m_sectionNumberComboBox->setToolTip(tr("Section number mode"));
|
||||
m_sectionNumberComboBox->addItem(tr("None"), (int)MarkdownEditorConfig::SectionNumberMode::None);
|
||||
m_sectionNumberComboBox->addItem(tr("Read"), (int)MarkdownEditorConfig::SectionNumberMode::Read);
|
||||
@ -273,7 +301,7 @@ QGroupBox *MarkdownEditorPage::setupGeneralGroup()
|
||||
connect(m_sectionNumberComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &MarkdownEditorPage::pageIsChanged);
|
||||
|
||||
m_sectionNumberBaseLevelSpinBox = WidgetsFactory::createSpinBox(this);
|
||||
m_sectionNumberBaseLevelSpinBox = WidgetsFactory::createSpinBox(box);
|
||||
m_sectionNumberBaseLevelSpinBox->setToolTip(tr("Base level to start section numbering in edit mode"));
|
||||
m_sectionNumberBaseLevelSpinBox->setRange(1, 6);
|
||||
m_sectionNumberBaseLevelSpinBox->setSingleStep(1);
|
||||
@ -281,7 +309,7 @@ QGroupBox *MarkdownEditorPage::setupGeneralGroup()
|
||||
connect(m_sectionNumberBaseLevelSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||
this, &MarkdownEditorPage::pageIsChanged);
|
||||
|
||||
m_sectionNumberStyleComboBox = WidgetsFactory::createComboBox(this);
|
||||
m_sectionNumberStyleComboBox = WidgetsFactory::createComboBox(box);
|
||||
m_sectionNumberStyleComboBox->setToolTip(tr("Section number style"));
|
||||
m_sectionNumberStyleComboBox->addItem(tr("1.1."), (int)MarkdownEditorConfig::SectionNumberStyle::DigDotDigDot);
|
||||
m_sectionNumberStyleComboBox->addItem(tr("1.1"), (int)MarkdownEditorConfig::SectionNumberStyle::DigDotDig);
|
||||
@ -300,5 +328,122 @@ QGroupBox *MarkdownEditorPage::setupGeneralGroup()
|
||||
addSearchItem(label, m_sectionNumberComboBox->toolTip(), m_sectionNumberComboBox);
|
||||
}
|
||||
|
||||
{
|
||||
m_plantUmlModeComboBox = WidgetsFactory::createComboBox(box);
|
||||
m_plantUmlModeComboBox->setToolTip(tr("Use online service or local JAR file to render PlantUml graphs"));
|
||||
|
||||
m_plantUmlModeComboBox->addItem(tr("Online Service"), 0);
|
||||
m_plantUmlModeComboBox->addItem(tr("Local JAR"), 1);
|
||||
|
||||
const QString label(tr("PlantUml:"));
|
||||
layout->addRow(label, m_plantUmlModeComboBox);
|
||||
addSearchItem(label, m_plantUmlModeComboBox->toolTip(), m_plantUmlModeComboBox);
|
||||
connect(m_plantUmlModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &MarkdownEditorPage::pageIsChanged);
|
||||
}
|
||||
|
||||
{
|
||||
auto jarLayout = new QHBoxLayout();
|
||||
|
||||
m_plantUmlJarFileInput = new LocationInputWithBrowseButton(box);
|
||||
m_plantUmlJarFileInput->setToolTip(tr("Local JAR file to render PlantUML graphs"));
|
||||
connect(m_plantUmlJarFileInput, &LocationInputWithBrowseButton::clicked,
|
||||
this, [this]() {
|
||||
auto filePath = QFileDialog::getOpenFileName(this,
|
||||
tr("Select PlantUml JAR File"),
|
||||
QDir::homePath(),
|
||||
"PlantUml JAR (*.jar)");
|
||||
if (!filePath.isEmpty()) {
|
||||
m_plantUmlJarFileInput->setText(filePath);
|
||||
}
|
||||
});
|
||||
jarLayout->addWidget(m_plantUmlJarFileInput, 1);
|
||||
|
||||
auto testBtn = new QPushButton(tr("Test"), box);
|
||||
testBtn->setToolTip(tr("Test PlantUml JAR and Java Runtime Environment"));
|
||||
connect(testBtn, &QPushButton::clicked,
|
||||
this, [this]() {
|
||||
const auto jar = m_plantUmlJarFileInput->text();
|
||||
if (jar.isEmpty() || !QFileInfo::exists(jar)) {
|
||||
MessageBoxHelper::notify(MessageBoxHelper::Warning,
|
||||
tr("The JAR file (%1) specified does not exist.").arg(jar),
|
||||
this);
|
||||
return;
|
||||
}
|
||||
|
||||
auto testRet = PlantUmlHelper::testPlantUml(jar);
|
||||
MessageBoxHelper::notify(MessageBoxHelper::Information,
|
||||
tr("Test %1.").arg(testRet.first ? tr("succeeded") : tr("failed")),
|
||||
QString(),
|
||||
testRet.second,
|
||||
this);
|
||||
});
|
||||
jarLayout->addWidget(testBtn);
|
||||
|
||||
const QString label(tr("PlantUml JAR file:"));
|
||||
layout->addRow(label, jarLayout);
|
||||
addSearchItem(label, m_plantUmlJarFileInput->toolTip(), m_plantUmlJarFileInput);
|
||||
connect(m_plantUmlJarFileInput, &LocationInputWithBrowseButton::textChanged,
|
||||
this, &MarkdownEditorPage::pageIsChanged);
|
||||
}
|
||||
|
||||
{
|
||||
m_graphvizModeComboBox = WidgetsFactory::createComboBox(box);
|
||||
m_graphvizModeComboBox->setToolTip(tr("Use online service or local executable file to render Graphviz graphs"));
|
||||
|
||||
m_graphvizModeComboBox->addItem(tr("Online Service"), 0);
|
||||
m_graphvizModeComboBox->addItem(tr("Local Executable"), 1);
|
||||
|
||||
const QString label(tr("Graphviz:"));
|
||||
layout->addRow(label, m_graphvizModeComboBox);
|
||||
addSearchItem(label, m_graphvizModeComboBox->toolTip(), m_graphvizModeComboBox);
|
||||
connect(m_graphvizModeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &MarkdownEditorPage::pageIsChanged);
|
||||
}
|
||||
|
||||
{
|
||||
auto fileLayout = new QHBoxLayout();
|
||||
|
||||
m_graphvizFileInput = new LocationInputWithBrowseButton(box);
|
||||
m_graphvizFileInput->setToolTip(tr("Local executable file to render Graphviz graphs"));
|
||||
connect(m_graphvizFileInput, &LocationInputWithBrowseButton::clicked,
|
||||
this, [this]() {
|
||||
auto filePath = QFileDialog::getOpenFileName(this,
|
||||
tr("Select Graphviz Executable File"),
|
||||
QDir::homePath());
|
||||
if (!filePath.isEmpty()) {
|
||||
m_graphvizFileInput->setText(filePath);
|
||||
}
|
||||
});
|
||||
fileLayout->addWidget(m_graphvizFileInput, 1);
|
||||
|
||||
auto testBtn = new QPushButton(tr("Test"), box);
|
||||
testBtn->setToolTip(tr("Test Graphviz executable file"));
|
||||
connect(testBtn, &QPushButton::clicked,
|
||||
this, [this]() {
|
||||
const auto exe = m_graphvizFileInput->text();
|
||||
if (exe.isEmpty() || !QFileInfo::exists(exe)) {
|
||||
MessageBoxHelper::notify(MessageBoxHelper::Warning,
|
||||
tr("The executable file (%1) specified does not exist.").arg(exe),
|
||||
this);
|
||||
return;
|
||||
}
|
||||
|
||||
auto testRet = GraphvizHelper::testGraphviz(exe);
|
||||
MessageBoxHelper::notify(MessageBoxHelper::Information,
|
||||
tr("Test %1.").arg(testRet.first ? tr("succeeded") : tr("failed")),
|
||||
QString(),
|
||||
testRet.second,
|
||||
this);
|
||||
});
|
||||
fileLayout->addWidget(testBtn);
|
||||
|
||||
const QString label(tr("Graphviz executable file:"));
|
||||
layout->addRow(label, fileLayout);
|
||||
addSearchItem(label, m_graphvizFileInput->toolTip(), m_graphvizFileInput);
|
||||
connect(m_graphvizFileInput, &LocationInputWithBrowseButton::textChanged,
|
||||
this, &MarkdownEditorPage::pageIsChanged);
|
||||
}
|
||||
|
||||
return box;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ class QComboBox;
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class LocationInputWithBrowseButton;
|
||||
|
||||
class MarkdownEditorPage : public SettingsPage
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -60,6 +62,14 @@ namespace vnotex
|
||||
QCheckBox *m_smartTableCheckBox = nullptr;
|
||||
|
||||
QCheckBox *m_spellCheckCheckBox = nullptr;
|
||||
|
||||
QComboBox *m_plantUmlModeComboBox = nullptr;
|
||||
|
||||
LocationInputWithBrowseButton *m_plantUmlJarFileInput = nullptr;
|
||||
|
||||
QComboBox *m_graphvizModeComboBox = nullptr;
|
||||
|
||||
LocationInputWithBrowseButton *m_graphvizFileInput = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
|
201
src/widgets/editors/graphhelper.cpp
Normal file
201
src/widgets/editors/graphhelper.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
#include "graphhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <utils/processutils.h>
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
#define TaskIdProperty "GraphTaskId"
|
||||
#define TaskTimeStampProperty "GraphTaskTimeStamp"
|
||||
|
||||
GraphHelper::GraphHelper()
|
||||
: m_cache(100, CacheItem())
|
||||
{
|
||||
}
|
||||
|
||||
QStringList GraphHelper::getArgsToUse(const QStringList &p_args)
|
||||
{
|
||||
if (p_args.isEmpty()) {
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
if (p_args[0] == "-c") {
|
||||
// Combine all the arguments except the first one.
|
||||
QStringList args;
|
||||
args << p_args[0];
|
||||
|
||||
QString subCmd;
|
||||
for (int i = 1; i < p_args.size(); ++i) {
|
||||
subCmd += " " + p_args[i];
|
||||
}
|
||||
args << subCmd;
|
||||
|
||||
return args;
|
||||
} else {
|
||||
return p_args;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphHelper::process(quint64 p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_format,
|
||||
const QString &p_text,
|
||||
const ResultCallback &p_callback)
|
||||
{
|
||||
Task task;
|
||||
task.m_id = p_id;
|
||||
task.m_timeStamp = p_timeStamp;
|
||||
task.m_format = p_format;
|
||||
task.m_text = p_text;
|
||||
task.m_callback = p_callback;
|
||||
|
||||
m_tasks.enqueue(task);
|
||||
|
||||
processOneTask();
|
||||
}
|
||||
|
||||
void GraphHelper::processOneTask()
|
||||
{
|
||||
if (m_taskOngoing || m_tasks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_taskOngoing = true;
|
||||
|
||||
const auto &task = m_tasks.head();
|
||||
|
||||
const auto &cachedData = m_cache.get(task.m_text);
|
||||
if (!cachedData.isNull() && cachedData.m_format == task.m_format) {
|
||||
finishOneTask(cachedData.m_data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_programValid) {
|
||||
qWarning() << "program to execute for rendering is not valid" << m_program;
|
||||
finishOneTask(QString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Will be released in finishOneTask.
|
||||
QProcess *process = new QProcess();
|
||||
process->setProperty(TaskIdProperty, task.m_id);
|
||||
process->setProperty(TaskTimeStampProperty, task.m_timeStamp);
|
||||
QObject::connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
[this, process](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
finishOneTask(process, exitCode, exitStatus);
|
||||
});
|
||||
|
||||
if (m_overriddenCommand.isEmpty()) {
|
||||
Q_ASSERT(!m_program.isEmpty());
|
||||
QStringList args(m_args);
|
||||
args << getFormatArgs(task.m_format);
|
||||
process->start(m_program, getArgsToUse(args));
|
||||
} else {
|
||||
auto cmd = getCommandToUse(m_overriddenCommand, task.m_format);
|
||||
process->start(cmd);
|
||||
}
|
||||
|
||||
if (process->write(task.m_text.toUtf8()) == -1) {
|
||||
qWarning() << "Graph task" << task.m_id << "failed to write to process stdin:" << process->errorString();
|
||||
}
|
||||
|
||||
process->closeWriteChannel();
|
||||
}
|
||||
|
||||
void GraphHelper::finishOneTask(QProcess *p_process, int p_exitCode, QProcess::ExitStatus p_exitStatus)
|
||||
{
|
||||
Q_ASSERT(m_taskOngoing && !m_tasks.isEmpty());
|
||||
|
||||
const auto task = m_tasks.dequeue();
|
||||
|
||||
const quint64 id = p_process->property(TaskIdProperty).toULongLong();
|
||||
const quint64 timeStamp = p_process->property(TaskTimeStampProperty).toULongLong();
|
||||
Q_ASSERT(task.m_id == id && task.m_timeStamp == timeStamp);
|
||||
|
||||
qDebug() << "Graph task" << id << timeStamp << "finished";
|
||||
|
||||
bool failed = true;
|
||||
if (p_exitStatus == QProcess::NormalExit) {
|
||||
if (p_exitCode < 0) {
|
||||
qWarning() << "Graph task" << id << "failed:" << p_exitCode;
|
||||
} else {
|
||||
failed = false;
|
||||
const auto outBa = p_process->readAllStandardOutput();
|
||||
QString data;
|
||||
if (task.m_format == QStringLiteral("svg")) {
|
||||
data = QString::fromLocal8Bit(outBa);
|
||||
task.m_callback(id, timeStamp, task.m_format, data);
|
||||
} else {
|
||||
data = QString::fromLocal8Bit(outBa.toBase64());
|
||||
task.m_callback(id, timeStamp, task.m_format, data);
|
||||
}
|
||||
|
||||
CacheItem item;
|
||||
item.m_format = task.m_format;
|
||||
item.m_data = data;
|
||||
m_cache.set(task.m_text, item);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Graph task" << id << "failed to start" << p_exitCode << p_exitStatus;
|
||||
}
|
||||
|
||||
const QByteArray errBa = p_process->readAllStandardError();
|
||||
if (!errBa.isEmpty()) {
|
||||
QString errStr(QString::fromLocal8Bit(errBa));
|
||||
if (failed) {
|
||||
qWarning() << "Graph task" << id << "stderr:" << errStr;
|
||||
} else {
|
||||
qDebug() << "Graph task" << id << "stderr:" << errStr;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
task.m_callback(id, task.m_timeStamp, task.m_format, QString());
|
||||
}
|
||||
|
||||
p_process->deleteLater();
|
||||
|
||||
m_taskOngoing = false;
|
||||
processOneTask();
|
||||
}
|
||||
|
||||
void GraphHelper::finishOneTask(const QString &p_data)
|
||||
{
|
||||
Q_ASSERT(m_taskOngoing && !m_tasks.isEmpty());
|
||||
|
||||
const auto task = m_tasks.dequeue();
|
||||
|
||||
qDebug() << "Graph task" << task.m_id << task.m_timeStamp << "finished by cache" << p_data.size();
|
||||
|
||||
task.m_callback(task.m_id, task.m_timeStamp, task.m_format, p_data);
|
||||
|
||||
m_taskOngoing = false;
|
||||
processOneTask();
|
||||
}
|
||||
|
||||
QString GraphHelper::getCommandToUse(const QString &p_command, const QString &p_format)
|
||||
{
|
||||
auto cmd(p_command);
|
||||
cmd.replace("%1", p_format);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void GraphHelper::clearCache()
|
||||
{
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
void GraphHelper::checkValidProgram()
|
||||
{
|
||||
m_programValid = true;
|
||||
if (m_overriddenCommand.isEmpty()) {
|
||||
if (m_program.isEmpty()) {
|
||||
m_programValid = false;
|
||||
} else {
|
||||
QFileInfo finfo(m_program);
|
||||
m_programValid = !finfo.isAbsolute() || finfo.isExecutable();
|
||||
}
|
||||
}
|
||||
}
|
91
src/widgets/editors/graphhelper.h
Normal file
91
src/widgets/editors/graphhelper.h
Normal file
@ -0,0 +1,91 @@
|
||||
#ifndef GRAPHHELPER_H
|
||||
#define GRAPHHELPER_H
|
||||
|
||||
#include <QProcess>
|
||||
#include <QStringList>
|
||||
#include <QPair>
|
||||
#include <QQueue>
|
||||
|
||||
#include <core/noncopyable.h>
|
||||
#include <core/global.h>
|
||||
#include <vtextedit/lrucache.h>
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class GraphHelper : private Noncopyable
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(quint64, TimeStamp, const QString &, const QString &)> ResultCallback;
|
||||
|
||||
GraphHelper();
|
||||
|
||||
void process(quint64 p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_format,
|
||||
const QString &p_text,
|
||||
const ResultCallback &p_callback);
|
||||
|
||||
protected:
|
||||
virtual QStringList getFormatArgs(const QString &p_format) = 0;
|
||||
|
||||
void clearCache();
|
||||
|
||||
void checkValidProgram();
|
||||
|
||||
static QStringList getArgsToUse(const QStringList &p_args);
|
||||
|
||||
static QString getCommandToUse(const QString &p_command,
|
||||
const QString &p_format);
|
||||
|
||||
QString m_program;
|
||||
|
||||
QStringList m_args;
|
||||
|
||||
// If this is not empty, @m_program and @m_args will be ignored.
|
||||
QString m_overriddenCommand;
|
||||
|
||||
private:
|
||||
struct Task
|
||||
{
|
||||
quint64 m_id = 0;
|
||||
|
||||
TimeStamp m_timeStamp = 0;
|
||||
|
||||
QString m_format;
|
||||
|
||||
QString m_text;
|
||||
|
||||
ResultCallback m_callback;
|
||||
};
|
||||
|
||||
struct CacheItem
|
||||
{
|
||||
bool isNull() const
|
||||
{
|
||||
return m_data.isNull();
|
||||
}
|
||||
|
||||
QString m_format;
|
||||
|
||||
QString m_data;
|
||||
};
|
||||
|
||||
void processOneTask();
|
||||
|
||||
void finishOneTask(QProcess *p_process, int p_exitCode, QProcess::ExitStatus p_exitStatus);
|
||||
|
||||
void finishOneTask(const QString &p_data);
|
||||
|
||||
QQueue<Task> m_tasks;
|
||||
|
||||
bool m_taskOngoing = false;
|
||||
|
||||
// {text} -> CacheItem.
|
||||
vte::LruCache<QString, CacheItem> m_cache;
|
||||
|
||||
// Whether @m_program is valid.
|
||||
bool m_programValid = true;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GRAPHHELPER_H
|
74
src/widgets/editors/graphvizhelper.cpp
Normal file
74
src/widgets/editors/graphvizhelper.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "graphvizhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <utils/processutils.h>
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
void GraphvizHelper::init(const QString &p_graphvizFile)
|
||||
{
|
||||
if (m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
update(p_graphvizFile);
|
||||
}
|
||||
|
||||
void GraphvizHelper::update(const QString &p_graphvizFile)
|
||||
{
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
prepareProgramAndArgs(p_graphvizFile, m_program, m_args);
|
||||
|
||||
checkValidProgram();
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
void GraphvizHelper::prepareProgramAndArgs(const QString &p_graphvizFile,
|
||||
QString &p_program,
|
||||
QStringList &p_args)
|
||||
{
|
||||
p_program = p_graphvizFile.isEmpty() ? QStringLiteral("dot") : p_graphvizFile;
|
||||
p_args.clear();
|
||||
}
|
||||
|
||||
QPair<bool, QString> GraphvizHelper::testGraphviz(const QString &p_graphvizFile)
|
||||
{
|
||||
auto ret = qMakePair(false, QString());
|
||||
|
||||
QString program;
|
||||
QStringList args;
|
||||
prepareProgramAndArgs(p_graphvizFile, program, args);
|
||||
args << "-Tsvg";
|
||||
|
||||
const QString testGraph("digraph G {VNote->Markdown}");
|
||||
|
||||
int exitCode = -1;
|
||||
QByteArray outData;
|
||||
QByteArray errData;
|
||||
auto state = ProcessUtils::start(program,
|
||||
args,
|
||||
testGraph.toUtf8(),
|
||||
exitCode,
|
||||
outData,
|
||||
errData);
|
||||
ret.first = (state == ProcessUtils::Succeeded) && (exitCode == 0);
|
||||
|
||||
ret.second = QString("%1 %2\n\nExitcode: %3\n\nOutput: %4\n\nError: %5")
|
||||
.arg(program, args.join(' '), QString::number(exitCode), QString::fromLocal8Bit(outData), QString::fromLocal8Bit(errData));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList GraphvizHelper::getFormatArgs(const QString &p_format)
|
||||
{
|
||||
QStringList args;
|
||||
args << ("-T" + p_format);
|
||||
return args;
|
||||
}
|
36
src/widgets/editors/graphvizhelper.h
Normal file
36
src/widgets/editors/graphvizhelper.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef GRAPHVIZHELPER_H
|
||||
#define GRAPHVIZHELPER_H
|
||||
|
||||
#include "graphhelper.h"
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class GraphvizHelper : public GraphHelper
|
||||
{
|
||||
public:
|
||||
void init(const QString &p_graphvizFile);
|
||||
|
||||
void update(const QString &p_graphvizFile);
|
||||
|
||||
static GraphvizHelper &getInst()
|
||||
{
|
||||
static GraphvizHelper inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
static QPair<bool, QString> testGraphviz(const QString &p_graphvizFile);
|
||||
|
||||
private:
|
||||
GraphvizHelper() = default;
|
||||
|
||||
QStringList getFormatArgs(const QString &p_format) Q_DECL_OVERRIDE;
|
||||
|
||||
static void prepareProgramAndArgs(const QString &p_graphvizFile,
|
||||
QString &p_program,
|
||||
QStringList &p_args);
|
||||
|
||||
bool m_initialized = false;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GRAPHVIZHELPER_H
|
@ -21,6 +21,7 @@
|
||||
#include <vtextedit/vtextedit.h>
|
||||
#include <vtextedit/texteditutils.h>
|
||||
#include <vtextedit/networkutils.h>
|
||||
#include <vtextedit/theme.h>
|
||||
|
||||
#include <widgets/dialogs/linkinsertdialog.h>
|
||||
#include <widgets/dialogs/imageinsertdialog.h>
|
||||
@ -1274,3 +1275,10 @@ void MarkdownEditor::setupTableHelper()
|
||||
connect(getHighlighter(), &vte::PegMarkdownHighlighter::tableBlocksUpdated,
|
||||
m_tableHelper, &MarkdownTableHelper::updateTableBlocks);
|
||||
}
|
||||
|
||||
QRgb MarkdownEditor::getPreviewBackground() const
|
||||
{
|
||||
auto th = theme();
|
||||
const auto &fmt = th->editorStyle(vte::Theme::EditorStyle::Preview);
|
||||
return fmt.m_backgroundColor;
|
||||
}
|
||||
|
@ -100,6 +100,8 @@ namespace vnotex
|
||||
|
||||
void updateFromConfig(bool p_initialized = true);
|
||||
|
||||
QRgb getPreviewBackground() const;
|
||||
|
||||
public slots:
|
||||
void handleHtmlToMarkdownData(quint64 p_id, TimeStamp p_timeStamp, const QString &p_text);
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <QMap>
|
||||
|
||||
#include "../outlineprovider.h"
|
||||
#include "plantumlhelper.h"
|
||||
#include "graphvizhelper.h"
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
@ -371,3 +373,35 @@ void MarkdownViewerAdapter::reset()
|
||||
m_currentHeadingIndex = -1;
|
||||
m_crossCopyTargets.clear();
|
||||
}
|
||||
|
||||
void MarkdownViewerAdapter::renderGraph(quint64 p_id,
|
||||
quint64 p_index,
|
||||
const QString &p_format,
|
||||
const QString &p_lang,
|
||||
const QString &p_text)
|
||||
{
|
||||
if (p_text.isEmpty()) {
|
||||
emit graphRenderDataReady(p_id, p_index, p_format, QString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_lang == QStringLiteral("puml")) {
|
||||
PlantUmlHelper::getInst().process(p_id,
|
||||
p_index,
|
||||
p_format,
|
||||
p_text,
|
||||
[this](quint64 id, TimeStamp timeStamp, const QString &format, const QString &data) {
|
||||
emit graphRenderDataReady(id, timeStamp, format, data);
|
||||
});
|
||||
} else if (p_lang == QStringLiteral("dot")) {
|
||||
GraphvizHelper::getInst().process(p_id,
|
||||
p_index,
|
||||
p_format,
|
||||
p_text,
|
||||
[this](quint64 id, TimeStamp timeStamp, const QString &format, const QString &data) {
|
||||
emit graphRenderDataReady(id, timeStamp, format, data);
|
||||
});
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +172,13 @@ namespace vnotex
|
||||
|
||||
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.
|
||||
void renderGraph(quint64 p_id,
|
||||
quint64 p_index,
|
||||
const QString &p_format,
|
||||
const QString &p_lang,
|
||||
const QString &p_text);
|
||||
|
||||
// Signals to be connected at web side.
|
||||
signals:
|
||||
// Current Markdown text is updated.
|
||||
@ -208,6 +215,11 @@ namespace vnotex
|
||||
// Request to get the whole HTML content.
|
||||
void contentRequested();
|
||||
|
||||
void graphRenderDataReady(quint64 p_id,
|
||||
quint64 p_index,
|
||||
const QString &p_format,
|
||||
const QString &p_data);
|
||||
|
||||
// Signals to be connected at cpp side.
|
||||
signals:
|
||||
void graphPreviewDataReady(const PreviewData &p_data);
|
||||
|
104
src/widgets/editors/plantumlhelper.cpp
Normal file
104
src/widgets/editors/plantumlhelper.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "plantumlhelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <utils/processutils.h>
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
void PlantUmlHelper::init(const QString &p_plantUmlJarFile,
|
||||
const QString &p_graphvizFile,
|
||||
const QString &p_overriddenCommand)
|
||||
{
|
||||
if (m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
|
||||
update(p_plantUmlJarFile, p_graphvizFile, p_overriddenCommand);
|
||||
}
|
||||
|
||||
void PlantUmlHelper::update(const QString &p_plantUmlJarFile,
|
||||
const QString &p_graphvizFile,
|
||||
const QString &p_overriddenCommand)
|
||||
{
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_overriddenCommand = p_overriddenCommand;
|
||||
if (m_overriddenCommand.isEmpty()) {
|
||||
prepareProgramAndArgs(p_plantUmlJarFile, p_graphvizFile, m_program, m_args);
|
||||
} else {
|
||||
m_program.clear();
|
||||
m_args.clear();
|
||||
}
|
||||
|
||||
checkValidProgram();
|
||||
|
||||
clearCache();
|
||||
}
|
||||
|
||||
void PlantUmlHelper::prepareProgramAndArgs(const QString &p_plantUmlJarFile,
|
||||
const QString &p_graphvizFile,
|
||||
QString &p_program,
|
||||
QStringList &p_args)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
p_program = "java";
|
||||
#else
|
||||
p_program = "/bin/sh";
|
||||
p_args << "-c";
|
||||
p_args << "java";
|
||||
#endif
|
||||
|
||||
p_args << "-Djava.awt.headless=true";
|
||||
|
||||
p_args << "-jar" << p_plantUmlJarFile;
|
||||
|
||||
p_args << "-charset" << "UTF-8";
|
||||
|
||||
if (!p_graphvizFile.isEmpty()) {
|
||||
p_args << "-graphvizdot" << p_graphvizFile;
|
||||
}
|
||||
|
||||
p_args << "-pipe";
|
||||
}
|
||||
|
||||
QPair<bool, QString> PlantUmlHelper::testPlantUml(const QString &p_plantUmlJarFile)
|
||||
{
|
||||
auto ret = qMakePair(false, QString());
|
||||
|
||||
QString program;
|
||||
QStringList args;
|
||||
prepareProgramAndArgs(p_plantUmlJarFile, QString(), program, args);
|
||||
|
||||
args << "-tsvg";
|
||||
args = getArgsToUse(args);
|
||||
|
||||
const QString testGraph("VNote->Markdown : Hello");
|
||||
|
||||
int exitCode = -1;
|
||||
QByteArray outData;
|
||||
QByteArray errData;
|
||||
auto state = ProcessUtils::start(program,
|
||||
args,
|
||||
testGraph.toUtf8(),
|
||||
exitCode,
|
||||
outData,
|
||||
errData);
|
||||
ret.first = (state == ProcessUtils::Succeeded) && (exitCode == 0);
|
||||
|
||||
ret.second = QString("%1 %2\n\nExitcode: %3\n\nOutput: %4\n\nError: %5")
|
||||
.arg(program, args.join(' '), QString::number(exitCode), QString::fromLocal8Bit(outData), QString::fromLocal8Bit(errData));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList PlantUmlHelper::getFormatArgs(const QString &p_format)
|
||||
{
|
||||
QStringList args;
|
||||
args << ("-t" + p_format);
|
||||
return args;
|
||||
}
|
41
src/widgets/editors/plantumlhelper.h
Normal file
41
src/widgets/editors/plantumlhelper.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef PLANTUMLHELPER_H
|
||||
#define PLANTUMLHELPER_H
|
||||
|
||||
#include "graphhelper.h"
|
||||
|
||||
namespace vnotex
|
||||
{
|
||||
class PlantUmlHelper : public GraphHelper
|
||||
{
|
||||
public:
|
||||
void init(const QString &p_plantUmlJarFile,
|
||||
const QString &p_graphvizFile,
|
||||
const QString &p_overriddenCommand);
|
||||
|
||||
void update(const QString &p_plantUmlJarFile,
|
||||
const QString &p_graphvizFile,
|
||||
const QString &p_overriddenCommand);
|
||||
|
||||
static PlantUmlHelper &getInst()
|
||||
{
|
||||
static PlantUmlHelper inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
static QPair<bool, QString> testPlantUml(const QString &p_plantUmlJarFile);
|
||||
|
||||
private:
|
||||
PlantUmlHelper() = default;
|
||||
|
||||
QStringList getFormatArgs(const QString &p_format) Q_DECL_OVERRIDE;
|
||||
|
||||
static void prepareProgramAndArgs(const QString &p_plantUmlJarFile,
|
||||
const QString &p_graphvizFile,
|
||||
QString &p_program,
|
||||
QStringList &p_args);
|
||||
|
||||
bool m_initialized = false;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // PLANTUMLHELPER_H
|
@ -12,6 +12,8 @@
|
||||
#include <utils/utils.h>
|
||||
|
||||
#include "markdowneditor.h"
|
||||
#include "plantumlhelper.h"
|
||||
#include "graphvizhelper.h"
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
@ -134,9 +136,11 @@ void PreviewHelper::codeBlocksUpdated(vte::TimeStamp p_timeStamp,
|
||||
++m_codeBlockTimeStamp;
|
||||
m_codeBlocksData.clear();
|
||||
|
||||
bool needUpdateEditorInplacePreview = true;
|
||||
QVector<int> needPreviewBlocks;
|
||||
|
||||
for (int i = 0; i < p_codeBlocks.size(); ++i) {
|
||||
const auto &cb = p_codeBlocks[i];
|
||||
|
||||
for (const auto &cb : p_codeBlocks) {
|
||||
const auto needPreview = isLangNeedPreview(cb.m_lang);
|
||||
if (!needPreview.first && !needPreview.second) {
|
||||
continue;
|
||||
@ -158,16 +162,16 @@ void PreviewHelper::codeBlocksUpdated(vte::TimeStamp p_timeStamp,
|
||||
}
|
||||
|
||||
if (m_inplacePreviewEnabled && needPreview.first && !cacheHit) {
|
||||
// No need to update in-place preview for now.
|
||||
needUpdateEditorInplacePreview = false;
|
||||
m_codeBlocksData[blockPreviewIdx].m_text = cb.m_text;
|
||||
inplacePreviewCodeBlock(blockPreviewIdx);
|
||||
needPreviewBlocks.push_back(blockPreviewIdx);
|
||||
}
|
||||
}
|
||||
|
||||
if (needUpdateEditorInplacePreview) {
|
||||
updateEditorInplacePreviewCodeBlock();
|
||||
for (auto idx : needPreviewBlocks) {
|
||||
inplacePreviewCodeBlock(idx);
|
||||
}
|
||||
|
||||
updateEditorInplacePreviewCodeBlock();
|
||||
}
|
||||
|
||||
bool PreviewHelper::checkPreviewSourceLang(SourceFlag p_flag, const QString &p_lang) const
|
||||
@ -221,13 +225,38 @@ void PreviewHelper::inplacePreviewCodeBlock(int p_blockPreviewIdx)
|
||||
if (checkPreviewSourceLang(SourceFlag::FlowChart, blockData.m_lang)
|
||||
|| checkPreviewSourceLang(SourceFlag::WaveDrom, blockData.m_lang)
|
||||
|| checkPreviewSourceLang(SourceFlag::Mermaid, blockData.m_lang)
|
||||
|| checkPreviewSourceLang(SourceFlag::PlantUml, blockData.m_lang)
|
||||
|| checkPreviewSourceLang(SourceFlag::Graphviz, blockData.m_lang)
|
||||
|| (checkPreviewSourceLang(SourceFlag::PlantUml, blockData.m_lang) && m_webPlantUmlEnabled)
|
||||
|| (checkPreviewSourceLang(SourceFlag::Graphviz, blockData.m_lang) && m_webGraphvizEnabled)
|
||||
|| checkPreviewSourceLang(SourceFlag::Math, blockData.m_lang)) {
|
||||
emit graphPreviewRequested(p_blockPreviewIdx,
|
||||
m_codeBlockTimeStamp,
|
||||
blockData.m_lang,
|
||||
TextUtils::removeCodeBlockFence(blockData.m_text));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_webPlantUmlEnabled && checkPreviewSourceLang(SourceFlag::PlantUml, blockData.m_lang)) {
|
||||
// Local PlantUml.
|
||||
PlantUmlHelper::getInst().process(static_cast<quint64>(p_blockPreviewIdx),
|
||||
m_codeBlockTimeStamp,
|
||||
QStringLiteral("svg"),
|
||||
TextUtils::removeCodeBlockFence(blockData.m_text),
|
||||
[this](quint64 id, TimeStamp timeStamp, const QString &format, const QString &data) {
|
||||
handleLocalData(id, timeStamp, format, data, true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_webGraphvizEnabled && checkPreviewSourceLang(SourceFlag::Graphviz, blockData.m_lang)) {
|
||||
// Local PlantUml.
|
||||
GraphvizHelper::getInst().process(static_cast<quint64>(p_blockPreviewIdx),
|
||||
m_codeBlockTimeStamp,
|
||||
QStringLiteral("svg"),
|
||||
TextUtils::removeCodeBlockFence(blockData.m_text),
|
||||
[this](quint64 id, TimeStamp timeStamp, const QString &format, const QString &data) {
|
||||
handleLocalData(id, timeStamp, format, data, false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,10 +271,11 @@ void PreviewHelper::handleGraphPreviewData(const MarkdownViewerAdapter::PreviewD
|
||||
}
|
||||
|
||||
auto &blockData = m_codeBlocksData[p_data.m_id];
|
||||
const bool forcedBackground = needForcedBackground(blockData.m_lang);
|
||||
auto previewData = QSharedPointer<GraphPreviewData>::create(p_data.m_timeStamp,
|
||||
p_data.m_format,
|
||||
p_data.m_data,
|
||||
0,
|
||||
forcedBackground ? m_editor->getPreviewBackground() : 0,
|
||||
p_data.m_needScale ? getEditorScaleFactor() : 1);
|
||||
m_codeBlockCache.set(blockData.m_text, previewData);
|
||||
blockData.m_text.clear();
|
||||
@ -414,3 +444,58 @@ qreal PreviewHelper::getEditorScaleFactor() const
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PreviewHelper::setWebPlantUmlEnabled(bool p_enabled)
|
||||
{
|
||||
m_webPlantUmlEnabled = p_enabled;
|
||||
}
|
||||
|
||||
void PreviewHelper::setWebGraphvizEnabled(bool p_enabled)
|
||||
{
|
||||
m_webGraphvizEnabled = p_enabled;
|
||||
}
|
||||
|
||||
void PreviewHelper::handleLocalData(quint64 p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_format,
|
||||
const QString &p_data,
|
||||
bool p_forcedBackground)
|
||||
{
|
||||
if (p_timeStamp != m_codeBlockTimeStamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_UNUSED(p_format);
|
||||
Q_ASSERT(p_format == QStringLiteral("svg"));
|
||||
|
||||
if (p_id >= static_cast<quint64>(m_codeBlocksData.size()) || p_data.isEmpty()) {
|
||||
updateEditorInplacePreviewCodeBlock();
|
||||
return;
|
||||
}
|
||||
|
||||
auto &blockData = m_codeBlocksData[p_id];
|
||||
auto previewData = QSharedPointer<GraphPreviewData>::create(p_timeStamp,
|
||||
p_format,
|
||||
p_data.toUtf8(),
|
||||
p_forcedBackground ? m_editor->getPreviewBackground() : 0,
|
||||
getEditorScaleFactor());
|
||||
m_codeBlockCache.set(blockData.m_text, previewData);
|
||||
blockData.m_text.clear();
|
||||
|
||||
blockData.updateInplacePreview(m_document,
|
||||
previewData->m_image,
|
||||
previewData->m_name,
|
||||
previewData->m_background,
|
||||
m_tabStopWidth);
|
||||
|
||||
updateEditorInplacePreviewCodeBlock();
|
||||
}
|
||||
|
||||
bool PreviewHelper::needForcedBackground(const QString &p_lang) const
|
||||
{
|
||||
if (checkPreviewSourceLang(SourceFlag::PlantUml, p_lang)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -47,6 +47,10 @@ namespace vnotex
|
||||
|
||||
void setMarkdownEditor(MarkdownEditor *p_editor);
|
||||
|
||||
void setWebPlantUmlEnabled(bool p_enabled);
|
||||
|
||||
void setWebGraphvizEnabled(bool p_enabled);
|
||||
|
||||
public slots:
|
||||
void codeBlocksUpdated(vte::TimeStamp p_timeStamp,
|
||||
const QVector<vte::peg::FencedCodeBlock> &p_codeBlocks);
|
||||
@ -180,8 +184,16 @@ namespace vnotex
|
||||
|
||||
void updateEditorInplacePreviewMathBlock();
|
||||
|
||||
void handleLocalData(quint64 p_id,
|
||||
TimeStamp p_timeStamp,
|
||||
const QString &p_format,
|
||||
const QString &p_data,
|
||||
bool p_forcedBackground);
|
||||
|
||||
qreal getEditorScaleFactor() const;
|
||||
|
||||
bool needForcedBackground(const QString &p_lang) const;
|
||||
|
||||
MarkdownEditor *m_editor = nullptr;
|
||||
|
||||
QTextDocument *m_document = nullptr;
|
||||
@ -213,6 +225,10 @@ namespace vnotex
|
||||
vte::LruCache<QString, QSharedPointer<GraphPreviewData>> m_codeBlockCache;
|
||||
|
||||
vte::LruCache<QString, QSharedPointer<GraphPreviewData>> m_mathBlockCache;
|
||||
|
||||
bool m_webPlantUmlEnabled = true;
|
||||
|
||||
bool m_webGraphvizEnabled = true;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ LocationInputWithBrowseButton::LocationInputWithBrowseButton(QWidget *p_parent)
|
||||
: QWidget(p_parent)
|
||||
{
|
||||
auto layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_lineEdit = WidgetsFactory::createLineEdit(this);
|
||||
layout->addWidget(m_lineEdit, 1);
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "toolbarhelper.h"
|
||||
#include "findandreplacewidget.h"
|
||||
#include "editors/statuswidget.h"
|
||||
#include "editors/plantumlhelper.h"
|
||||
#include "editors/graphvizhelper.h"
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
@ -40,7 +42,7 @@ MarkdownViewWindow::MarkdownViewWindow(QWidget *p_parent)
|
||||
|
||||
setupUI();
|
||||
|
||||
m_previewHelper = new PreviewHelper(nullptr, this);
|
||||
setupPreviewHelper();
|
||||
}
|
||||
|
||||
MarkdownViewWindow::~MarkdownViewWindow()
|
||||
@ -176,7 +178,12 @@ void MarkdownViewWindow::handleEditorConfigChange()
|
||||
|
||||
if (markdownEditorConfig.revision() != m_markdownEditorConfigRevision) {
|
||||
m_markdownEditorConfigRevision = markdownEditorConfig.revision();
|
||||
|
||||
m_previewHelper->setWebPlantUmlEnabled(markdownEditorConfig.getWebPlantUml());
|
||||
m_previewHelper->setWebGraphvizEnabled(markdownEditorConfig.getWebGraphviz());
|
||||
|
||||
HtmlTemplateHelper::updateMarkdownViewerTemplate(markdownEditorConfig);
|
||||
|
||||
if (m_editor) {
|
||||
auto config = createMarkdownEditorConfig(markdownEditorConfig);
|
||||
m_editor->setConfig(config);
|
||||
@ -236,7 +243,7 @@ void MarkdownViewWindow::handleBufferChangedInternal(const QSharedPointer<FileOp
|
||||
|
||||
TextViewWindowHelper::handleBufferChanged(this);
|
||||
|
||||
handleFileOpenParameters(p_paras);
|
||||
handleFileOpenParameters(p_paras, false);
|
||||
}
|
||||
|
||||
void MarkdownViewWindow::setupToolBar()
|
||||
@ -890,7 +897,7 @@ void MarkdownViewWindow::handleFindAndReplaceWidgetOpened()
|
||||
m_findAndReplace->setReplaceEnabled(!isReadMode());
|
||||
}
|
||||
|
||||
void MarkdownViewWindow::handleFileOpenParameters(const QSharedPointer<FileOpenParameters> &p_paras)
|
||||
void MarkdownViewWindow::handleFileOpenParameters(const QSharedPointer<FileOpenParameters> &p_paras, bool p_twice)
|
||||
{
|
||||
if (!p_paras) {
|
||||
return;
|
||||
@ -905,7 +912,9 @@ void MarkdownViewWindow::handleFileOpenParameters(const QSharedPointer<FileOpenP
|
||||
m_editor->insertText(title);
|
||||
}
|
||||
} else {
|
||||
setMode(p_paras->m_mode);
|
||||
if (!p_twice || p_paras->m_forceMode) {
|
||||
setMode(p_paras->m_mode);
|
||||
}
|
||||
|
||||
scrollToLine(p_paras->m_lineNumber);
|
||||
}
|
||||
@ -934,7 +943,7 @@ bool MarkdownViewWindow::isReadMode() const
|
||||
void MarkdownViewWindow::openTwice(const QSharedPointer<FileOpenParameters> &p_paras)
|
||||
{
|
||||
Q_ASSERT(!p_paras || !p_paras->m_newFile);
|
||||
handleFileOpenParameters(p_paras);
|
||||
handleFileOpenParameters(p_paras, true);
|
||||
}
|
||||
|
||||
ViewWindowSession MarkdownViewWindow::saveSession() const
|
||||
@ -946,3 +955,19 @@ ViewWindowSession MarkdownViewWindow::saveSession() const
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
void MarkdownViewWindow::setupPreviewHelper()
|
||||
{
|
||||
Q_ASSERT(!m_previewHelper);
|
||||
|
||||
m_previewHelper = new PreviewHelper(nullptr, this);
|
||||
|
||||
const auto &markdownEditorConfig = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig();
|
||||
m_previewHelper->setWebPlantUmlEnabled(markdownEditorConfig.getWebPlantUml());
|
||||
m_previewHelper->setWebGraphvizEnabled(markdownEditorConfig.getWebGraphviz());
|
||||
|
||||
PlantUmlHelper::getInst().init(markdownEditorConfig.getPlantUmlJar(),
|
||||
markdownEditorConfig.getGraphvizExe(),
|
||||
markdownEditorConfig.getPlantUmlCommand());
|
||||
GraphvizHelper::getInst().init(markdownEditorConfig.getGraphvizExe());
|
||||
}
|
||||
|
@ -97,6 +97,8 @@ namespace vnotex
|
||||
|
||||
void setupViewer();
|
||||
|
||||
void setupPreviewHelper();
|
||||
|
||||
void syncTextEditorFromBuffer(bool p_syncPositionFromReadMode);
|
||||
|
||||
void syncViewerFromBuffer(bool p_syncPositionFromEditMode);
|
||||
@ -131,7 +133,7 @@ namespace vnotex
|
||||
|
||||
void setModeInternal(ViewWindowMode p_mode, bool p_syncBuffer);
|
||||
|
||||
void handleFileOpenParameters(const QSharedPointer<FileOpenParameters> &p_paras);
|
||||
void handleFileOpenParameters(const QSharedPointer<FileOpenParameters> &p_paras, bool p_twice);
|
||||
|
||||
void scrollToLine(int p_lineNumber);
|
||||
|
||||
|
@ -22,10 +22,14 @@
|
||||
#include <core/vnotex.h>
|
||||
#include <core/configmgr.h>
|
||||
#include <core/coreconfig.h>
|
||||
#include <core/editorconfig.h>
|
||||
#include <core/markdowneditorconfig.h>
|
||||
#include <core/sessionconfig.h>
|
||||
#include <core/fileopenparameters.h>
|
||||
#include <notebook/node.h>
|
||||
#include <notebook/notebook.h>
|
||||
#include "editors/plantumlhelper.h"
|
||||
#include "editors/graphvizhelper.h"
|
||||
|
||||
using namespace vnotex;
|
||||
|
||||
@ -87,6 +91,12 @@ ViewArea::ViewArea(QWidget *p_parent)
|
||||
p_win->handleEditorConfigChange();
|
||||
return true;
|
||||
});
|
||||
|
||||
const auto &markdownEditorConfig = ConfigMgr::getInst().getEditorConfig().getMarkdownEditorConfig();
|
||||
PlantUmlHelper::getInst().update(markdownEditorConfig.getPlantUmlJar(),
|
||||
markdownEditorConfig.getGraphvizExe(),
|
||||
markdownEditorConfig.getPlantUmlCommand());
|
||||
GraphvizHelper::getInst().update(markdownEditorConfig.getGraphvizExe());
|
||||
});
|
||||
|
||||
m_fileCheckTimer = new QTimer(this);
|
||||
|
@ -28,11 +28,14 @@ SOURCES += \
|
||||
$$PWD/dialogs/tableinsertdialog.cpp \
|
||||
$$PWD/dragdropareaindicator.cpp \
|
||||
$$PWD/editors/editormarkdownvieweradapter.cpp \
|
||||
$$PWD/editors/graphhelper.cpp \
|
||||
$$PWD/editors/graphvizhelper.cpp \
|
||||
$$PWD/editors/markdowneditor.cpp \
|
||||
$$PWD/editors/markdowntable.cpp \
|
||||
$$PWD/editors/markdowntablehelper.cpp \
|
||||
$$PWD/editors/markdownviewer.cpp \
|
||||
$$PWD/editors/markdownvieweradapter.cpp \
|
||||
$$PWD/editors/plantumlhelper.cpp \
|
||||
$$PWD/editors/previewhelper.cpp \
|
||||
$$PWD/editors/statuswidget.cpp \
|
||||
$$PWD/editors/texteditor.cpp \
|
||||
@ -123,11 +126,14 @@ HEADERS += \
|
||||
$$PWD/dialogs/tableinsertdialog.h \
|
||||
$$PWD/dragdropareaindicator.h \
|
||||
$$PWD/editors/editormarkdownvieweradapter.h \
|
||||
$$PWD/editors/graphhelper.h \
|
||||
$$PWD/editors/graphvizhelper.h \
|
||||
$$PWD/editors/markdowneditor.h \
|
||||
$$PWD/editors/markdowntable.h \
|
||||
$$PWD/editors/markdowntablehelper.h \
|
||||
$$PWD/editors/markdownviewer.h \
|
||||
$$PWD/editors/markdownvieweradapter.h \
|
||||
$$PWD/editors/plantumlhelper.h \
|
||||
$$PWD/editors/previewhelper.h \
|
||||
$$PWD/editors/statuswidget.h \
|
||||
$$PWD/editors/texteditor.h \
|
||||
|
Loading…
x
Reference in New Issue
Block a user