support Graphviz

This commit is contained in:
Le Tan 2018-04-07 09:56:36 +08:00
parent 11e111ed7b
commit 2206102945
18 changed files with 327 additions and 39 deletions

View File

@ -912,10 +912,13 @@ VMarkdownTab::VMarkdownTab(QWidget *p_parent)
m_plantUMLJarEdit = new VLineEdit(); m_plantUMLJarEdit = new VLineEdit();
m_plantUMLJarEdit->setToolTip(tr("Location to the PlantUML JAR executable for local PlantUML")); m_plantUMLJarEdit->setToolTip(tr("Location to the PlantUML JAR executable for local PlantUML"));
m_plantUMLDotEdit = new VLineEdit(); // Graphviz.
m_plantUMLDotEdit->setPlaceholderText(tr("Empty to detect automatically")); m_graphvizCB = new QCheckBox(tr("Graphviz"));
m_plantUMLDotEdit->setToolTip(tr("Location to the GraphViz executable for local PlantUML " m_graphvizCB->setToolTip(tr("Enable Graphviz for drawing graph"));
"(empty to let PlantUML detect it automatically)"));
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(); QFormLayout *mainLayout = new QFormLayout();
mainLayout->addRow(tr("Note open mode:"), m_openModeCombo); 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:"), m_plantUMLModeCombo);
mainLayout->addRow(tr("PlantUML server:"), m_plantUMLServerEdit); mainLayout->addRow(tr("PlantUML server:"), m_plantUMLServerEdit);
mainLayout->addRow(tr("PlantUML JAR:"), m_plantUMLJarEdit); 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); setLayout(mainLayout);
} }
@ -947,6 +951,10 @@ bool VMarkdownTab::loadConfiguration()
return false; return false;
} }
if (!loadGraphviz()) {
return false;
}
return true; return true;
} }
@ -968,6 +976,10 @@ bool VMarkdownTab::saveConfiguration()
return false; return false;
} }
if (!saveGraphviz()) {
return false;
}
return true; return true;
} }
@ -1044,7 +1056,6 @@ bool VMarkdownTab::loadPlantUML()
m_plantUMLModeCombo->setCurrentIndex(m_plantUMLModeCombo->findData(g_config->getPlantUMLMode())); m_plantUMLModeCombo->setCurrentIndex(m_plantUMLModeCombo->findData(g_config->getPlantUMLMode()));
m_plantUMLServerEdit->setText(g_config->getPlantUMLServer()); m_plantUMLServerEdit->setText(g_config->getPlantUMLServer());
m_plantUMLJarEdit->setText(g_config->getPlantUMLJar()); m_plantUMLJarEdit->setText(g_config->getPlantUMLJar());
m_plantUMLDotEdit->setText(g_config->getPlantUMLDot());
return true; return true;
} }
@ -1053,6 +1064,19 @@ bool VMarkdownTab::savePlantUML()
g_config->setPlantUMLMode(m_plantUMLModeCombo->currentData().toInt()); g_config->setPlantUMLMode(m_plantUMLModeCombo->currentData().toInt());
g_config->setPlantUMLServer(m_plantUMLServerEdit->text()); g_config->setPlantUMLServer(m_plantUMLServerEdit->text());
g_config->setPlantUMLJar(m_plantUMLJarEdit->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; return true;
} }

View File

@ -160,6 +160,9 @@ private:
bool loadPlantUML(); bool loadPlantUML();
bool savePlantUML(); bool savePlantUML();
bool loadGraphviz();
bool saveGraphviz();
// Default note open mode for markdown. // Default note open mode for markdown.
QComboBox *m_openModeCombo; QComboBox *m_openModeCombo;
@ -174,7 +177,10 @@ private:
QComboBox *m_plantUMLModeCombo; QComboBox *m_plantUMLModeCombo;
VLineEdit *m_plantUMLServerEdit; VLineEdit *m_plantUMLServerEdit;
VLineEdit *m_plantUMLJarEdit; VLineEdit *m_plantUMLJarEdit;
VLineEdit *m_plantUMLDotEdit;
// Graphviz.
QCheckBox *m_graphvizCB;
VLineEdit *m_graphvizDotEdit;
}; };
class VSettingsDialog : public QDialog class VSettingsDialog : public QDialog

View File

@ -25,6 +25,7 @@ var updateHtml = function(html) {
var codes = document.getElementsByTagName('code'); var codes = document.getElementsByTagName('code');
mermaidIdx = 0; mermaidIdx = 0;
plantUMLIdx = 0; plantUMLIdx = 0;
graphvizIdx = 0;
for (var i = 0; i < codes.length; ++i) { for (var i = 0; i < codes.length; ++i) {
var code = codes[i]; var code = codes[i];
if (code.parentElement.tagName.toLowerCase() == 'pre') { if (code.parentElement.tagName.toLowerCase() == 'pre') {
@ -59,9 +60,15 @@ var updateHtml = function(html) {
renderPlantUMLOneLocal(code); renderPlantUMLOneLocal(code);
} }
continue;
} else if (VEnableGraphviz
&& code.classList.contains('language-dot')) {
// Graphviz code block.
renderGraphvizOneLocal(code);
continue; continue;
} }
if (listContainsRegex(code.classList, /language-.*/)) { if (listContainsRegex(code.classList, /language-.*/)) {
hljs.highlightBlock(code); hljs.highlightBlock(code);
} }

View File

@ -116,6 +116,7 @@ var updateText = function(text) {
renderMermaid('lang-mermaid'); renderMermaid('lang-mermaid');
renderFlowchart(['lang-flowchart', 'lang-flow']); renderFlowchart(['lang-flowchart', 'lang-flow']);
renderPlantUML('lang-puml'); renderPlantUML('lang-puml');
renderGraphviz('lang-dot');
addClassToCodeBlock(); addClassToCodeBlock();
renderCodeBlockLineNumber(); renderCodeBlockLineNumber();

View File

@ -1,3 +1,5 @@
var channelInitialized = false;
var content; var content;
// Current header index in all headers. // Current header index in all headers.
@ -45,6 +47,18 @@ if (typeof VPlantUMLServer == 'undefined') {
VPlantUMLServer = 'http://www.plantuml.com/plantuml'; 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. // Add a caption (using alt text) under the image.
var VImageCenterClass = 'img-center'; var VImageCenterClass = 'img-center';
var VImageCaptionClass = 'img-caption'; var VImageCaptionClass = 'img-caption';
@ -123,14 +137,7 @@ var htmlContent = function() {
new QWebChannel(qt.webChannelTransport, new QWebChannel(qt.webChannelTransport,
function(channel) { function(channel) {
content = channel.objects.content; 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); content.requestScrollToAnchor.connect(scrollToAnchor);
if (typeof highlightText == "function") { if (typeof highlightText == "function") {
@ -148,6 +155,19 @@ new QWebChannel(qt.webChannelTransport,
} }
content.plantUMLResultReady.connect(handlePlantUMLResult); 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'; var VHighlightedAnchorClass = 'highlighted-anchor';
@ -686,6 +706,33 @@ var renderPlantUMLOneLocal = function(code) {
plantUMLIdx++; 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 isImageBlock = function(img) {
var pn = img.parentNode; var pn = img.parentNode;
return (pn.children.length == 1) && (pn.textContent == ''); return (pn.children.length == 1) && (pn.textContent == '');
@ -1260,7 +1307,8 @@ var specialCodeBlock = function(lang) {
return (VEnableMathjax && lang == 'mathjax') return (VEnableMathjax && lang == 'mathjax')
|| (VEnableMermaid && lang == 'mermaid') || (VEnableMermaid && lang == 'mermaid')
|| (VEnableFlowchart && (lang == 'flowchart' || lang == 'flow')) || (VEnableFlowchart && (lang == 'flowchart' || lang == 'flow'))
|| (VPlantUMLMode != 0 && lang == 'puml'); || (VPlantUMLMode != 0 && lang == 'puml')
|| (VEnableGraphviz && lang == 'dot');
}; };
var handlePlantUMLResult = function(id, format, result) { var handlePlantUMLResult = function(id, format, result) {
@ -1282,3 +1330,22 @@ var handlePlantUMLResult = function(id, format, result) {
finishOneAsyncJob(); 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();
};

View File

@ -60,6 +60,7 @@ var updateText = function(text) {
renderMermaid('lang-mermaid'); renderMermaid('lang-mermaid');
renderFlowchart(['lang-flowchart', 'lang-flow']); renderFlowchart(['lang-flowchart', 'lang-flow']);
renderPlantUML('lang-puml'); renderPlantUML('lang-puml');
renderGraphviz('lang-dot');
addClassToCodeBlock(); addClassToCodeBlock();
renderCodeBlockLineNumber(); renderCodeBlockLineNumber();

View File

@ -49,7 +49,12 @@ var mdHasTocSection = function(markdown) {
return n != -1; 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'); var codes = doc.getElementsByTagName('code');
for (var i = 0; i < codes.length; ++i) { for (var i = 0; i < codes.length; ++i) {
var code = codes[i]; var code = codes[i];
@ -68,6 +73,9 @@ var highlightCodeBlocks = function(doc, enableMermaid, enableFlowchart, enableMa
} else if (enablePlantUML && code.classList.contains('language-puml')) { } else if (enablePlantUML && code.classList.contains('language-puml')) {
// PlantUML code block. // PlantUML code block.
continue; continue;
} else if (enableGraphviz && code.classList.contains('language-dot')) {
// Graphviz code block.
continue;
} }
if (listContainsRegex(code.classList, /language-.*/)) { if (listContainsRegex(code.classList, /language-.*/)) {
@ -89,10 +97,16 @@ var updateText = function(text) {
placeholder.innerHTML = html; placeholder.innerHTML = html;
handleToc(needToc); handleToc(needToc);
insertImageCaption(); insertImageCaption();
highlightCodeBlocks(document, VEnableMermaid, VEnableFlowchart, VEnableMathjax, VPlantUMLMode != 0); highlightCodeBlocks(document,
VEnableMermaid,
VEnableFlowchart,
VEnableMathjax,
VPlantUMLMode != 0,
VEnableGraphviz);
renderMermaid('language-mermaid'); renderMermaid('language-mermaid');
renderFlowchart(['language-flowchart', 'language-flow']); renderFlowchart(['language-flowchart', 'language-flow']);
renderPlantUML('language-puml'); renderPlantUML('language-puml');
renderGraphviz('language-dot');
addClassToCodeBlock(); addClassToCodeBlock();
renderCodeBlockLineNumber(); renderCodeBlockLineNumber();

View File

@ -49,6 +49,9 @@ enable_flowchart=false
; 2 - local PlantUML ; 2 - local PlantUML
plantuml_mode=0 plantuml_mode=0
; Enable Graphviz
enable_graphviz=false
; -1 - calculate the factor ; -1 - calculate the factor
web_zoom_factor=-1 web_zoom_factor=-1
@ -277,8 +280,8 @@ plantuml_server=http://www.plantuml.com/plantuml
; PlantUML JAR location ; PlantUML JAR location
plantuml_jar= plantuml_jar=
; PlantUML Graphviz Dot location ; Graphviz Dot location
plantuml_dot= graphviz_dot=
[shortcuts] [shortcuts]
; Define shortcuts here, with each item in the form "operation=keysequence". ; Define shortcuts here, with each item in the form "operation=keysequence".

View File

@ -126,7 +126,8 @@ SOURCES += main.cpp\
vhelpue.cpp \ vhelpue.cpp \
vlistfolderue.cpp \ vlistfolderue.cpp \
dialog/vfixnotebookdialog.cpp \ dialog/vfixnotebookdialog.cpp \
vplantumlhelper.cpp vplantumlhelper.cpp \
vgraphvizhelper.cpp
HEADERS += vmainwindow.h \ HEADERS += vmainwindow.h \
vdirectorytree.h \ vdirectorytree.h \
@ -243,7 +244,8 @@ HEADERS += vmainwindow.h \
vhelpue.h \ vhelpue.h \
vlistfolderue.h \ vlistfolderue.h \
dialog/vfixnotebookdialog.h \ dialog/vfixnotebookdialog.h \
vplantumlhelper.h vplantumlhelper.h \
vgraphvizhelper.h
RESOURCES += \ RESOURCES += \
vnote.qrc \ vnote.qrc \

View File

@ -736,6 +736,13 @@ QString VUtils::generateHtmlTemplate(const QString &p_template,
extraFile += QString("<script>var VPlantUMLFormat = '%1';</script>\n").arg(format); extraFile += QString("<script>var VPlantUMLFormat = '%1';</script>\n").arg(format);
} }
if (g_config->getEnableGraphviz()) {
extraFile += "<script>var VEnableGraphviz = true;</script>\n";
QString format = p_isPDF ? "png" : "svg";
extraFile += QString("<script>var VGraphvizFormat = '%1';</script>\n").arg(format);
}
if (g_config->getEnableImageCaption()) { if (g_config->getEnableImageCaption()) {
extraFile += "<script>var VEnableImageCaption = true;</script>\n"; extraFile += "<script>var VEnableImageCaption = true;</script>\n";
} }

View File

@ -288,7 +288,9 @@ void VConfigManager::initialize()
m_plantUMLMode = getConfigFromSettings("global", "plantuml_mode").toInt(); m_plantUMLMode = getConfigFromSettings("global", "plantuml_mode").toInt();
m_plantUMLServer = getConfigFromSettings("web", "plantuml_server").toString(); m_plantUMLServer = getConfigFromSettings("web", "plantuml_server").toString();
m_plantUMLJar = getConfigFromSettings("web", "plantuml_jar").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() void VConfigManager::initSettings()

View File

@ -210,6 +210,9 @@ public:
bool getEnableMathjax() const; bool getEnableMathjax() const;
void setEnableMathjax(bool p_enabled); void setEnableMathjax(bool p_enabled);
bool getEnableGraphviz() const;
void setEnableGraphviz(bool p_enabled);
int getPlantUMLMode() const; int getPlantUMLMode() const;
void setPlantUMLMode(int p_mode); void setPlantUMLMode(int p_mode);
@ -469,8 +472,8 @@ public:
const QString &getPlantUMLJar() const; const QString &getPlantUMLJar() const;
void setPlantUMLJar(const QString &p_jarPath); void setPlantUMLJar(const QString &p_jarPath);
const QString &getPlantUMLDot() const; const QString &getGraphvizDot() const;
void setPlantUMLDot(const QString &p_dotPath); void setGraphvizDot(const QString &p_dotPath);
private: private:
// Look up a config from user and default settings. // Look up a config from user and default settings.
@ -634,6 +637,11 @@ private:
// Enable Mathjax. // Enable Mathjax.
bool m_enableMathjax; bool m_enableMathjax;
// Enable Graphviz.
bool m_enableGraphviz;
QString m_graphvizDot;
// Zoom factor of the QWebEngineView. // Zoom factor of the QWebEngineView.
qreal m_webZoomFactor; qreal m_webZoomFactor;
@ -871,8 +879,6 @@ private:
QString m_plantUMLJar; QString m_plantUMLJar;
QString m_plantUMLDot;
// The name of the config file in each directory, obsolete. // The name of the config file in each directory, obsolete.
// Use c_dirConfigFile instead. // Use c_dirConfigFile instead.
static const QString c_obsoleteDirConfigFile; static const QString c_obsoleteDirConfigFile;
@ -1351,6 +1357,21 @@ inline void VConfigManager::setEnableMathjax(bool p_enabled)
setConfigToSettings("global", "enable_mathjax", m_enableMathjax); 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 inline int VConfigManager::getPlantUMLMode() const
{ {
return m_plantUMLMode; return m_plantUMLMode;
@ -2217,18 +2238,18 @@ inline void VConfigManager::setPlantUMLJar(const QString &p_jarPath)
setConfigToSettings("web", "plantuml_jar", 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; return;
} }
m_plantUMLDot = p_dotPath; m_graphvizDot = p_dotPath;
setConfigToSettings("web", "plantuml_dot", p_dotPath); setConfigToSettings("web", "graphviz_dot", p_dotPath);
} }
#endif // VCONFIGMANAGER_H #endif // VCONFIGMANAGER_H

View File

@ -4,12 +4,14 @@
#include "vfile.h" #include "vfile.h"
#include "vplantumlhelper.h" #include "vplantumlhelper.h"
#include "vgraphvizhelper.h"
VDocument::VDocument(const VFile *v_file, QObject *p_parent) VDocument::VDocument(const VFile *v_file, QObject *p_parent)
: QObject(p_parent), : QObject(p_parent),
m_file(v_file), m_file(v_file),
m_readyToHighlight(false), 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) { if (!m_plantUMLHelper) {
m_plantUMLHelper = new VPlantUMLHelper(this); m_plantUMLHelper = new VPlantUMLHelper(this);
connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady, connect(m_plantUMLHelper, &VPlantUMLHelper::resultReady,
this, [this](int p_id, const QString &p_format, const QString &p_result) { this, &VDocument::plantUMLResultReady);
emit plantUMLResultReady(p_id, p_format, p_result);
});
} }
m_plantUMLHelper->processAsync(p_id, p_format, p_text); 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);
}

View File

@ -8,6 +8,7 @@
class VFile; class VFile;
class VPlantUMLHelper; class VPlantUMLHelper;
class VGraphvizHelper;
class VDocument : public QObject class VDocument : public QObject
{ {
@ -86,6 +87,9 @@ public slots:
// Web-side call this to process PlantUML locally. // Web-side call this to process PlantUML locally.
void processPlantUML(int p_id, const QString &p_format, const QString &p_text); 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: signals:
void textChanged(const QString &text); void textChanged(const QString &text);
@ -124,6 +128,8 @@ signals:
void plantUMLResultReady(int p_id, const QString &p_format, const QString &p_result); 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: private:
QString m_toc; QString m_toc;
QString m_header; QString m_header;
@ -145,6 +151,8 @@ private:
VWordCountInfo m_wordCountInfo; VWordCountInfo m_wordCountInfo;
VPlantUMLHelper *m_plantUMLHelper; VPlantUMLHelper *m_plantUMLHelper;
VGraphvizHelper *m_graphvizHelper;
}; };
inline bool VDocument::isReadyToHighlight() const inline bool VDocument::isReadyToHighlight() const

View File

@ -1012,6 +1012,7 @@ bool VEditArea::activateNextTabByCaptain(void *p_target, void *p_data)
VEditWindow *win = obj->getCurrentWindow(); VEditWindow *win = obj->getCurrentWindow();
if (win) { if (win) {
win->focusNextTab(true); win->focusNextTab(true);
return false;
} }
return true; return true;

83
src/vgraphvizhelper.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "vgraphvizhelper.h"
#include <QDebug>
#include <QThread>
#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<QProcess *>(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();
}

30
src/vgraphvizhelper.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef VGRAPHVIZHELPER_H
#define VGRAPHVIZHELPER_H
#include <QObject>
#include <QStringList>
#include <QProcess>
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

View File

@ -44,7 +44,7 @@ void VPlantUMLHelper::prepareCommand(QString &p_program, QStringList &p_args) co
int nbthread = QThread::idealThreadCount(); int nbthread = QThread::idealThreadCount();
p_args << "-nbthread" << QString::number(nbthread > 0 ? nbthread : 1); p_args << "-nbthread" << QString::number(nbthread > 0 ? nbthread : 1);
const QString &dot = g_config->getPlantUMLDot(); const QString &dot = g_config->getGraphvizDot();
if (!dot.isEmpty()) { if (!dot.isEmpty()) {
p_args << "-graphvizdot"; p_args << "-graphvizdot";
p_args << dot; p_args << dot;