diff --git a/src/dialog/vsettingsdialog.cpp b/src/dialog/vsettingsdialog.cpp
index 4d2c28d3..fcfbd8f9 100644
--- a/src/dialog/vsettingsdialog.cpp
+++ b/src/dialog/vsettingsdialog.cpp
@@ -912,10 +912,13 @@ VMarkdownTab::VMarkdownTab(QWidget *p_parent)
m_plantUMLJarEdit = new VLineEdit();
m_plantUMLJarEdit->setToolTip(tr("Location to the PlantUML JAR executable for local PlantUML"));
- m_plantUMLDotEdit = new VLineEdit();
- m_plantUMLDotEdit->setPlaceholderText(tr("Empty to detect automatically"));
- m_plantUMLDotEdit->setToolTip(tr("Location to the GraphViz executable for local PlantUML "
- "(empty to let PlantUML detect it automatically)"));
+ // Graphviz.
+ m_graphvizCB = new QCheckBox(tr("Graphviz"));
+ m_graphvizCB->setToolTip(tr("Enable Graphviz for drawing graph"));
+
+ m_graphvizDotEdit = new VLineEdit();
+ m_graphvizDotEdit->setPlaceholderText(tr("Empty to detect automatically"));
+ m_graphvizDotEdit->setToolTip(tr("Location to the GraphViz dot executable"));
QFormLayout *mainLayout = new QFormLayout();
mainLayout->addRow(tr("Note open mode:"), m_openModeCombo);
@@ -924,7 +927,8 @@ VMarkdownTab::VMarkdownTab(QWidget *p_parent)
mainLayout->addRow(tr("PlantUML:"), m_plantUMLModeCombo);
mainLayout->addRow(tr("PlantUML server:"), m_plantUMLServerEdit);
mainLayout->addRow(tr("PlantUML JAR:"), m_plantUMLJarEdit);
- mainLayout->addRow(tr("Graphviz executable:"), m_plantUMLDotEdit);
+ mainLayout->addRow(m_graphvizCB);
+ mainLayout->addRow(tr("Graphviz executable:"), m_graphvizDotEdit);
setLayout(mainLayout);
}
@@ -947,6 +951,10 @@ bool VMarkdownTab::loadConfiguration()
return false;
}
+ if (!loadGraphviz()) {
+ return false;
+ }
+
return true;
}
@@ -968,6 +976,10 @@ bool VMarkdownTab::saveConfiguration()
return false;
}
+ if (!saveGraphviz()) {
+ return false;
+ }
+
return true;
}
@@ -1044,7 +1056,6 @@ bool VMarkdownTab::loadPlantUML()
m_plantUMLModeCombo->setCurrentIndex(m_plantUMLModeCombo->findData(g_config->getPlantUMLMode()));
m_plantUMLServerEdit->setText(g_config->getPlantUMLServer());
m_plantUMLJarEdit->setText(g_config->getPlantUMLJar());
- m_plantUMLDotEdit->setText(g_config->getPlantUMLDot());
return true;
}
@@ -1053,6 +1064,19 @@ bool VMarkdownTab::savePlantUML()
g_config->setPlantUMLMode(m_plantUMLModeCombo->currentData().toInt());
g_config->setPlantUMLServer(m_plantUMLServerEdit->text());
g_config->setPlantUMLJar(m_plantUMLJarEdit->text());
- g_config->setPlantUMLDot(m_plantUMLDotEdit->text());
+ return true;
+}
+
+bool VMarkdownTab::loadGraphviz()
+{
+ m_graphvizCB->setChecked(g_config->getEnableGraphviz());
+ m_graphvizDotEdit->setText(g_config->getGraphvizDot());
+ return true;
+}
+
+bool VMarkdownTab::saveGraphviz()
+{
+ g_config->setEnableGraphviz(m_graphvizCB->isChecked());
+ g_config->setGraphvizDot(m_graphvizDotEdit->text());
return true;
}
diff --git a/src/dialog/vsettingsdialog.h b/src/dialog/vsettingsdialog.h
index 280e95d4..6468a6dc 100644
--- a/src/dialog/vsettingsdialog.h
+++ b/src/dialog/vsettingsdialog.h
@@ -160,6 +160,9 @@ private:
bool loadPlantUML();
bool savePlantUML();
+ bool loadGraphviz();
+ bool saveGraphviz();
+
// Default note open mode for markdown.
QComboBox *m_openModeCombo;
@@ -174,7 +177,10 @@ private:
QComboBox *m_plantUMLModeCombo;
VLineEdit *m_plantUMLServerEdit;
VLineEdit *m_plantUMLJarEdit;
- VLineEdit *m_plantUMLDotEdit;
+
+ // Graphviz.
+ QCheckBox *m_graphvizCB;
+ VLineEdit *m_graphvizDotEdit;
};
class VSettingsDialog : public QDialog
diff --git a/src/resources/hoedown.js b/src/resources/hoedown.js
index 7cb90cbe..cbaa9a0b 100644
--- a/src/resources/hoedown.js
+++ b/src/resources/hoedown.js
@@ -25,6 +25,7 @@ var updateHtml = function(html) {
var codes = document.getElementsByTagName('code');
mermaidIdx = 0;
plantUMLIdx = 0;
+ graphvizIdx = 0;
for (var i = 0; i < codes.length; ++i) {
var code = codes[i];
if (code.parentElement.tagName.toLowerCase() == 'pre') {
@@ -59,9 +60,15 @@ var updateHtml = function(html) {
renderPlantUMLOneLocal(code);
}
+ continue;
+ } else if (VEnableGraphviz
+ && code.classList.contains('language-dot')) {
+ // Graphviz code block.
+ renderGraphvizOneLocal(code);
continue;
}
+
if (listContainsRegex(code.classList, /language-.*/)) {
hljs.highlightBlock(code);
}
diff --git a/src/resources/markdown-it.js b/src/resources/markdown-it.js
index 98503c47..049779a4 100644
--- a/src/resources/markdown-it.js
+++ b/src/resources/markdown-it.js
@@ -116,6 +116,7 @@ var updateText = function(text) {
renderMermaid('lang-mermaid');
renderFlowchart(['lang-flowchart', 'lang-flow']);
renderPlantUML('lang-puml');
+ renderGraphviz('lang-dot');
addClassToCodeBlock();
renderCodeBlockLineNumber();
diff --git a/src/resources/markdown_template.js b/src/resources/markdown_template.js
index 1384ddb7..023d4df3 100644
--- a/src/resources/markdown_template.js
+++ b/src/resources/markdown_template.js
@@ -1,3 +1,5 @@
+var channelInitialized = false;
+
var content;
// Current header index in all headers.
@@ -45,6 +47,18 @@ if (typeof VPlantUMLServer == 'undefined') {
VPlantUMLServer = 'http://www.plantuml.com/plantuml';
}
+if (typeof VPlantUMLFormat == 'undefined') {
+ VPlantUMLFormat = 'svg';
+}
+
+if (typeof VEnableGraphviz == 'undefined') {
+ VEnableGraphviz = false;
+}
+
+if (typeof VGraphvizFormat == 'undefined') {
+ VGraphvizFormat = 'svg';
+}
+
// Add a caption (using alt text) under the image.
var VImageCenterClass = 'img-center';
var VImageCaptionClass = 'img-caption';
@@ -123,14 +137,7 @@ var htmlContent = function() {
new QWebChannel(qt.webChannelTransport,
function(channel) {
content = channel.objects.content;
- if (typeof updateHtml == "function") {
- updateHtml(content.html);
- content.htmlChanged.connect(updateHtml);
- }
- if (typeof updateText == "function") {
- content.textChanged.connect(updateText);
- content.updateText();
- }
+
content.requestScrollToAnchor.connect(scrollToAnchor);
if (typeof highlightText == "function") {
@@ -148,6 +155,19 @@ new QWebChannel(qt.webChannelTransport,
}
content.plantUMLResultReady.connect(handlePlantUMLResult);
+ content.graphvizResultReady.connect(handleGraphvizResult);
+
+ if (typeof updateHtml == "function") {
+ updateHtml(content.html);
+ content.htmlChanged.connect(updateHtml);
+ }
+
+ if (typeof updateText == "function") {
+ content.textChanged.connect(updateText);
+ content.updateText();
+ }
+
+ channelInitialized = true;
});
var VHighlightedAnchorClass = 'highlighted-anchor';
@@ -686,6 +706,33 @@ var renderPlantUMLOneLocal = function(code) {
plantUMLIdx++;
};
+var graphvizIdx = 0;
+var graphvizCodeClass = 'graphviz_code_';
+
+// @className, the class name of the Graghviz code block, such as 'lang-dot'.
+var renderGraphviz = function(className) {
+ if (!VEnableGraphviz) {
+ return;
+ }
+
+ graphvizIdx = 0;
+
+ var codes = document.getElementsByTagName('code');
+ for (var i = 0; i < codes.length; ++i) {
+ var code = codes[i];
+ if (code.classList.contains(className)) {
+ renderGraphvizOneLocal(code);
+ }
+ }
+};
+
+var renderGraphvizOneLocal = function(code) {
+ ++asyncJobsCount;
+ code.classList.add(graphvizCodeClass + graphvizIdx);
+ content.processGraphviz(graphvizIdx, VGraphvizFormat, code.textContent);
+ graphvizIdx++;
+};
+
var isImageBlock = function(img) {
var pn = img.parentNode;
return (pn.children.length == 1) && (pn.textContent == '');
@@ -1260,7 +1307,8 @@ var specialCodeBlock = function(lang) {
return (VEnableMathjax && lang == 'mathjax')
|| (VEnableMermaid && lang == 'mermaid')
|| (VEnableFlowchart && (lang == 'flowchart' || lang == 'flow'))
- || (VPlantUMLMode != 0 && lang == 'puml');
+ || (VPlantUMLMode != 0 && lang == 'puml')
+ || (VEnableGraphviz && lang == 'dot');
};
var handlePlantUMLResult = function(id, format, result) {
@@ -1282,3 +1330,22 @@ var handlePlantUMLResult = function(id, format, result) {
finishOneAsyncJob();
};
+
+var handleGraphvizResult = function(id, format, result) {
+ var code = document.getElementsByClassName(graphvizCodeClass + id)[0];
+ if (code && result.length > 0) {
+ var obj = null;
+ if (format == 'svg') {
+ obj = document.createElement('p');
+ obj.innerHTML = result;
+ } else {
+ obj = document.createElement('img');
+ obj.src = "data:image/" + format + ";base64, " + result;
+ }
+
+ var preNode = code.parentNode;
+ preNode.parentNode.replaceChild(obj, preNode);
+ }
+
+ finishOneAsyncJob();
+};
diff --git a/src/resources/marked.js b/src/resources/marked.js
index dd198b6c..67e0a9b3 100644
--- a/src/resources/marked.js
+++ b/src/resources/marked.js
@@ -60,6 +60,7 @@ var updateText = function(text) {
renderMermaid('lang-mermaid');
renderFlowchart(['lang-flowchart', 'lang-flow']);
renderPlantUML('lang-puml');
+ renderGraphviz('lang-dot');
addClassToCodeBlock();
renderCodeBlockLineNumber();
diff --git a/src/resources/showdown.js b/src/resources/showdown.js
index aaeace80..17ce9069 100644
--- a/src/resources/showdown.js
+++ b/src/resources/showdown.js
@@ -49,7 +49,12 @@ var mdHasTocSection = function(markdown) {
return n != -1;
};
-var highlightCodeBlocks = function(doc, enableMermaid, enableFlowchart, enableMathJax, enablePlantUML) {
+var highlightCodeBlocks = function(doc,
+ enableMermaid,
+ enableFlowchart,
+ enableMathJax,
+ enablePlantUML,
+ enableGraphviz) {
var codes = doc.getElementsByTagName('code');
for (var i = 0; i < codes.length; ++i) {
var code = codes[i];
@@ -68,6 +73,9 @@ var highlightCodeBlocks = function(doc, enableMermaid, enableFlowchart, enableMa
} else if (enablePlantUML && code.classList.contains('language-puml')) {
// PlantUML code block.
continue;
+ } else if (enableGraphviz && code.classList.contains('language-dot')) {
+ // Graphviz code block.
+ continue;
}
if (listContainsRegex(code.classList, /language-.*/)) {
@@ -89,10 +97,16 @@ var updateText = function(text) {
placeholder.innerHTML = html;
handleToc(needToc);
insertImageCaption();
- highlightCodeBlocks(document, VEnableMermaid, VEnableFlowchart, VEnableMathjax, VPlantUMLMode != 0);
+ highlightCodeBlocks(document,
+ VEnableMermaid,
+ VEnableFlowchart,
+ VEnableMathjax,
+ VPlantUMLMode != 0,
+ VEnableGraphviz);
renderMermaid('language-mermaid');
renderFlowchart(['language-flowchart', 'language-flow']);
renderPlantUML('language-puml');
+ renderGraphviz('language-dot');
addClassToCodeBlock();
renderCodeBlockLineNumber();
diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini
index c8c40086..f6834830 100644
--- a/src/resources/vnote.ini
+++ b/src/resources/vnote.ini
@@ -49,6 +49,9 @@ enable_flowchart=false
; 2 - local PlantUML
plantuml_mode=0
+; Enable Graphviz
+enable_graphviz=false
+
; -1 - calculate the factor
web_zoom_factor=-1
@@ -277,8 +280,8 @@ plantuml_server=http://www.plantuml.com/plantuml
; PlantUML JAR location
plantuml_jar=
-; PlantUML Graphviz Dot location
-plantuml_dot=
+; Graphviz Dot location
+graphviz_dot=
[shortcuts]
; Define shortcuts here, with each item in the form "operation=keysequence".
diff --git a/src/src.pro b/src/src.pro
index 9c22dafe..b6efef2a 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -126,7 +126,8 @@ SOURCES += main.cpp\
vhelpue.cpp \
vlistfolderue.cpp \
dialog/vfixnotebookdialog.cpp \
- vplantumlhelper.cpp
+ vplantumlhelper.cpp \
+ vgraphvizhelper.cpp
HEADERS += vmainwindow.h \
vdirectorytree.h \
@@ -243,7 +244,8 @@ HEADERS += vmainwindow.h \
vhelpue.h \
vlistfolderue.h \
dialog/vfixnotebookdialog.h \
- vplantumlhelper.h
+ vplantumlhelper.h \
+ vgraphvizhelper.h
RESOURCES += \
vnote.qrc \
diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp
index d8bceb49..eaa568fa 100644
--- a/src/utils/vutils.cpp
+++ b/src/utils/vutils.cpp
@@ -736,6 +736,13 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
extraFile += QString("\n").arg(format);
}
+ if (g_config->getEnableGraphviz()) {
+ extraFile += "\n";
+
+ QString format = p_isPDF ? "png" : "svg";
+ extraFile += QString("\n").arg(format);
+ }
+
if (g_config->getEnableImageCaption()) {
extraFile += "\n";
}
diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp
index 5e2298bb..f775a2a5 100644
--- a/src/vconfigmanager.cpp
+++ b/src/vconfigmanager.cpp
@@ -288,7 +288,9 @@ void VConfigManager::initialize()
m_plantUMLMode = getConfigFromSettings("global", "plantuml_mode").toInt();
m_plantUMLServer = getConfigFromSettings("web", "plantuml_server").toString();
m_plantUMLJar = getConfigFromSettings("web", "plantuml_jar").toString();
- m_plantUMLDot = getConfigFromSettings("web", "plantuml_dot").toString();
+
+ m_enableGraphviz = getConfigFromSettings("global", "enable_graphviz").toBool();
+ m_graphvizDot = getConfigFromSettings("web", "graphviz_dot").toString();
}
void VConfigManager::initSettings()
diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h
index ff8ca64c..4c7dad67 100644
--- a/src/vconfigmanager.h
+++ b/src/vconfigmanager.h
@@ -210,6 +210,9 @@ public:
bool getEnableMathjax() const;
void setEnableMathjax(bool p_enabled);
+ bool getEnableGraphviz() const;
+ void setEnableGraphviz(bool p_enabled);
+
int getPlantUMLMode() const;
void setPlantUMLMode(int p_mode);
@@ -469,8 +472,8 @@ public:
const QString &getPlantUMLJar() const;
void setPlantUMLJar(const QString &p_jarPath);
- const QString &getPlantUMLDot() const;
- void setPlantUMLDot(const QString &p_dotPath);
+ const QString &getGraphvizDot() const;
+ void setGraphvizDot(const QString &p_dotPath);
private:
// Look up a config from user and default settings.
@@ -634,6 +637,11 @@ private:
// Enable Mathjax.
bool m_enableMathjax;
+ // Enable Graphviz.
+ bool m_enableGraphviz;
+
+ QString m_graphvizDot;
+
// Zoom factor of the QWebEngineView.
qreal m_webZoomFactor;
@@ -871,8 +879,6 @@ private:
QString m_plantUMLJar;
- QString m_plantUMLDot;
-
// The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile;
@@ -1351,6 +1357,21 @@ inline void VConfigManager::setEnableMathjax(bool p_enabled)
setConfigToSettings("global", "enable_mathjax", m_enableMathjax);
}
+inline bool VConfigManager::getEnableGraphviz() const
+{
+ return m_enableGraphviz;
+}
+
+inline void VConfigManager::setEnableGraphviz(bool p_enabled)
+{
+ if (m_enableGraphviz == p_enabled) {
+ return;
+ }
+
+ m_enableGraphviz = p_enabled;
+ setConfigToSettings("global", "enable_graphviz", m_enableGraphviz);
+}
+
inline int VConfigManager::getPlantUMLMode() const
{
return m_plantUMLMode;
@@ -2217,18 +2238,18 @@ inline void VConfigManager::setPlantUMLJar(const QString &p_jarPath)
setConfigToSettings("web", "plantuml_jar", p_jarPath);
}
-inline const QString &VConfigManager::getPlantUMLDot() const
+inline const QString &VConfigManager::getGraphvizDot() const
{
- return m_plantUMLDot;
+ return m_graphvizDot;
}
-inline void VConfigManager::setPlantUMLDot(const QString &p_dotPath)
+inline void VConfigManager::setGraphvizDot(const QString &p_dotPath)
{
- if (m_plantUMLDot == p_dotPath) {
+ if (m_graphvizDot == p_dotPath) {
return;
}
- m_plantUMLDot = p_dotPath;
- setConfigToSettings("web", "plantuml_dot", p_dotPath);
+ m_graphvizDot = p_dotPath;
+ setConfigToSettings("web", "graphviz_dot", p_dotPath);
}
#endif // VCONFIGMANAGER_H
diff --git a/src/vdocument.cpp b/src/vdocument.cpp
index 0c6c4fe9..62a1e171 100644
--- a/src/vdocument.cpp
+++ b/src/vdocument.cpp
@@ -4,12 +4,14 @@
#include "vfile.h"
#include "vplantumlhelper.h"
+#include "vgraphvizhelper.h"
VDocument::VDocument(const VFile *v_file, QObject *p_parent)
: QObject(p_parent),
m_file(v_file),
m_readyToHighlight(false),
- m_plantUMLHelper(NULL)
+ m_plantUMLHelper(NULL),
+ m_graphvizHelper(NULL)
{
}
@@ -142,10 +144,19 @@ void VDocument::processPlantUML(int p_id, const QString &p_format, const QString
if (!m_plantUMLHelper) {
m_plantUMLHelper = new VPlantUMLHelper(this);
connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
- this, [this](int p_id, const QString &p_format, const QString &p_result) {
- emit plantUMLResultReady(p_id, p_format, p_result);
- });
+ this, &VDocument::plantUMLResultReady);
}
m_plantUMLHelper->processAsync(p_id, p_format, p_text);
}
+
+void VDocument::processGraphviz(int p_id, const QString &p_format, const QString &p_text)
+{
+ if (!m_graphvizHelper) {
+ m_graphvizHelper = new VGraphvizHelper(this);
+ connect(m_graphvizHelper, &VGraphvizHelper::resultReady,
+ this, &VDocument::graphvizResultReady);
+ }
+
+ m_graphvizHelper->processAsync(p_id, p_format, p_text);
+}
diff --git a/src/vdocument.h b/src/vdocument.h
index 097b11db..ebc72737 100644
--- a/src/vdocument.h
+++ b/src/vdocument.h
@@ -8,6 +8,7 @@
class VFile;
class VPlantUMLHelper;
+class VGraphvizHelper;
class VDocument : public QObject
{
@@ -86,6 +87,9 @@ public slots:
// Web-side call this to process PlantUML locally.
void processPlantUML(int p_id, const QString &p_format, const QString &p_text);
+ // Web-side call this to process Graphviz locally.
+ void processGraphviz(int p_id, const QString &p_format, const QString &p_text);
+
signals:
void textChanged(const QString &text);
@@ -124,6 +128,8 @@ signals:
void plantUMLResultReady(int p_id, const QString &p_format, const QString &p_result);
+ void graphvizResultReady(int p_id, const QString &p_format, const QString &p_result);
+
private:
QString m_toc;
QString m_header;
@@ -145,6 +151,8 @@ private:
VWordCountInfo m_wordCountInfo;
VPlantUMLHelper *m_plantUMLHelper;
+
+ VGraphvizHelper *m_graphvizHelper;
};
inline bool VDocument::isReadyToHighlight() const
diff --git a/src/veditarea.cpp b/src/veditarea.cpp
index 8a81344d..a0d37f1c 100644
--- a/src/veditarea.cpp
+++ b/src/veditarea.cpp
@@ -1012,6 +1012,7 @@ bool VEditArea::activateNextTabByCaptain(void *p_target, void *p_data)
VEditWindow *win = obj->getCurrentWindow();
if (win) {
win->focusNextTab(true);
+ return false;
}
return true;
diff --git a/src/vgraphvizhelper.cpp b/src/vgraphvizhelper.cpp
new file mode 100644
index 00000000..a26bc4b7
--- /dev/null
+++ b/src/vgraphvizhelper.cpp
@@ -0,0 +1,83 @@
+#include "vgraphvizhelper.h"
+
+#include
+#include
+
+#include "vconfigmanager.h"
+
+extern VConfigManager *g_config;
+
+#define TaskIdProperty "GraphvizTaskId"
+#define TaskFormatProperty "GraphvizTaskFormat"
+
+VGraphvizHelper::VGraphvizHelper(QObject *p_parent)
+ : QObject(p_parent)
+{
+ prepareCommand(m_program, m_args);
+}
+
+void VGraphvizHelper::processAsync(int p_id, const QString &p_format, const QString &p_text)
+{
+ QProcess *process = new QProcess(this);
+ process->setProperty(TaskIdProperty, p_id);
+ process->setProperty(TaskFormatProperty, p_format);
+ connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(handleProcessFinished(int, QProcess::ExitStatus)));
+
+ QStringList args(m_args);
+ args << ("-T" + p_format);
+
+ qDebug() << m_program << args;
+
+ process->start(m_program, args);
+ process->write(p_text.toUtf8());
+ process->closeWriteChannel();
+}
+
+void VGraphvizHelper::prepareCommand(QString &p_program, QStringList &p_args) const
+{
+ const QString &dot = g_config->getGraphvizDot();
+ if (dot.isEmpty()) {
+ p_program = "dot";
+ } else {
+ p_program = dot;
+ }
+
+ p_args.clear();
+}
+
+void VGraphvizHelper::handleProcessFinished(int p_exitCode, QProcess::ExitStatus p_exitStatus)
+{
+ QProcess *process = static_cast(sender());
+ int id = process->property(TaskIdProperty).toInt();
+ QString format = process->property(TaskFormatProperty).toString();
+ qDebug() << "process finished" << id << format << p_exitCode << p_exitStatus;
+ bool failed = true;
+ if (p_exitStatus == QProcess::NormalExit) {
+ if (p_exitCode < 0) {
+ qWarning() << "Graphviz fail" << p_exitCode;
+ } else {
+ failed = false;
+ QByteArray outBa = process->readAllStandardOutput();
+ if (format == "svg") {
+ emit resultReady(id, format, QString::fromLocal8Bit(outBa));
+ } else {
+ emit resultReady(id, format, QString::fromLocal8Bit(outBa.toBase64()));
+ }
+ }
+ } else {
+ qWarning() << "fail to start Graphviz process" << p_exitCode << p_exitStatus;
+ }
+
+ if (failed) {
+ QByteArray errBa = process->readAllStandardError();
+ if (!errBa.isEmpty()) {
+ QString errStr(QString::fromLocal8Bit(errBa));
+ qWarning() << "Graphviz stderr:" << errStr;
+ }
+
+ emit resultReady(id, format, "");
+ }
+
+ process->deleteLater();
+}
diff --git a/src/vgraphvizhelper.h b/src/vgraphvizhelper.h
new file mode 100644
index 00000000..ac49c12c
--- /dev/null
+++ b/src/vgraphvizhelper.h
@@ -0,0 +1,30 @@
+#ifndef VGRAPHVIZHELPER_H
+#define VGRAPHVIZHELPER_H
+
+#include
+
+#include
+#include
+
+class VGraphvizHelper : public QObject
+{
+ Q_OBJECT
+public:
+ explicit VGraphvizHelper(QObject *p_parent = nullptr);
+
+ void processAsync(int p_id, const QString &p_format, const QString &p_text);
+
+ void prepareCommand(QString &p_cmd, QStringList &p_args) const;
+
+signals:
+ void resultReady(int p_id, const QString &p_format, const QString &p_result);
+
+private slots:
+ void handleProcessFinished(int p_exitCode, QProcess::ExitStatus p_exitStatus);
+
+private:
+ QString m_program;
+ QStringList m_args;
+};
+
+#endif // VGRAPHVIZHELPER_H
diff --git a/src/vplantumlhelper.cpp b/src/vplantumlhelper.cpp
index f942cabd..9b2e1104 100644
--- a/src/vplantumlhelper.cpp
+++ b/src/vplantumlhelper.cpp
@@ -44,7 +44,7 @@ void VPlantUMLHelper::prepareCommand(QString &p_program, QStringList &p_args) co
int nbthread = QThread::idealThreadCount();
p_args << "-nbthread" << QString::number(nbthread > 0 ? nbthread : 1);
- const QString &dot = g_config->getPlantUMLDot();
+ const QString &dot = g_config->getGraphvizDot();
if (!dot.isEmpty()) {
p_args << "-graphvizdot";
p_args << dot;