16#include "qfiledialog.h"
17#include "qmessagebox.h"
19#include <QTemporaryFile>
29#include <mach-o/dyld.h>
33#include <sys/sysctl.h>
43#define WIDGET(t, f) ((t *)findChild<t *>(QStringLiteral(#f)))
49 std::vector<char> buf(512,
'\0');
54 buf.resize(buf.size() * 2);
58 ssize_t written = readlink(
path.c_str(), buf.
data(), buf.size());
61 if (
static_cast<size_t>(written) < buf.size()) {
81 uint32_t buf_size = 0;
82 int rc = _NSGetExecutablePath(
NULL, &buf_size);
86 std::vector<char>
path(buf_size);
89 if (_NSGetExecutablePath(
path.
data(), &buf_size) < 0) {
90 errout <<
"failed to get path for executable.\n";
95 for (std::string p =
path.
data();;) {
96 const std::string buf =
readln(p);
105 std::vector<char>
path;
110 size_t size =
path.empty() ? 1024 : (
path.size() * 2);
116 errout <<
"failed to get path for executable.\n";
120 }
while (rc ==
path.size());
144 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
145 static const size_t MIB_LENGTH =
sizeof(mib) /
sizeof(mib[0]);
150 if (sysctl(mib, MIB_LENGTH,
NULL, &buf_size,
NULL, 0) < 0)
152 assert(buf_size > 0);
155 std::vector<char> buf(buf_size,
'\0');
158 if (sysctl(mib, MIB_LENGTH, buf.data(), &buf_size,
NULL, 0) == 0)
165 errout <<
"failed to get path for executable.\n";
173 const char PATH_SEPARATOR =
'\\';
175 const char PATH_SEPARATOR =
'/';
179 std::string gvedit_exe =
find_me();
180 if (gvedit_exe ==
"")
186 size_t slash = gvedit_exe.rfind(PATH_SEPARATOR);
187 if (slash == std::string::npos) {
188 errout <<
"no path separator in path to self, " << gvedit_exe.c_str()
193 std::string bin = gvedit_exe.substr(0, slash);
194 slash = bin.rfind(PATH_SEPARATOR);
195 if (slash == std::string::npos) {
196 errout <<
"no path separator in directory containing self, " << bin.c_str()
201 std::string install_prefix = bin.substr(0, slash);
203 return install_prefix + PATH_SEPARATOR +
"share" + PATH_SEPARATOR +
204 "graphviz" + PATH_SEPARATOR +
"gvedit";
208 QComboBox *cbNameE) {
210 if (file.open(QIODevice::ReadOnly)) {
211 QTextStream stream(&file);
213 while (!stream.atEnd()) {
214 line = stream.readLine();
215 if (line.left(1) == QLatin1String(
":")) {
217 QStringList sl = line.split(u
':');
218 for (
int id = 0;
id < sl.count();
id++) {
222 if (sl[
id].contains(u
'G'))
223 cbNameG->addItem(attrName);
224 if (sl[
id].contains(u
'N'))
225 cbNameN->addItem(attrName);
226 if (sl[
id].contains(u
'E'))
227 cbNameE->addItem(attrName);
235 <<
"\" for reading\n";
245 for (idx =
fileName.length(); idx >= 0; idx--) {
257 activeWindow =
nullptr;
261 s = getenv(
"GVEDIT_PATH");
264 path = QString::fromUtf8(
s);
268 connect(
WIDGET(QPushButton, pbAdd), &QPushButton::clicked,
this,
269 &CFrmSettings::addSlot);
270 connect(
WIDGET(QPushButton, pbNew), &QPushButton::clicked,
this,
271 &CFrmSettings::newSlot);
272 connect(
WIDGET(QPushButton, pbOpen), &QPushButton::clicked,
this,
273 &CFrmSettings::openSlot);
274 connect(
WIDGET(QPushButton, pbSave), &QPushButton::clicked,
this,
275 &CFrmSettings::saveSlot);
276 connect(
WIDGET(QPushButton, btnOK), &QPushButton::clicked,
this,
277 &CFrmSettings::okSlot);
278 connect(
WIDGET(QPushButton, btnCancel), &QPushButton::clicked,
this,
279 &CFrmSettings::cancelSlot);
280 connect(
WIDGET(QPushButton, pbOut), &QPushButton::clicked,
this,
281 &CFrmSettings::outputSlot);
282 connect(
WIDGET(QPushButton, pbHelp), &QPushButton::clicked,
this,
283 &CFrmSettings::helpSlot);
285 connect(
WIDGET(QComboBox, cbScope),
286 QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
287 &CFrmSettings::scopeChangedSlot);
290 if (!
path.isEmpty()) {
292 WIDGET(QComboBox, cbNameN),
WIDGET(QComboBox, cbNameE));
294 setWindowIcon(QIcon(QStringLiteral(
":/images/icon.png")));
297void CFrmSettings::outputSlot() {
298 QString _filter = QStringLiteral(
"Output File(*.%1)")
299 .arg(
WIDGET(QComboBox, cbExtension)->currentText());
300 QString
fileName = QFileDialog::getSaveFileName(
this, tr(
"Save Graph As.."),
301 QStringLiteral(
"/"), _filter);
306void CFrmSettings::scopeChangedSlot(
int id) {
307 WIDGET(QComboBox, cbNameG)->setVisible(
id == 0);
308 WIDGET(QComboBox, cbNameN)->setVisible(
id == 1);
309 WIDGET(QComboBox, cbNameE)->setVisible(
id == 2);
312void CFrmSettings::addSlot() {
313 QString _scope =
WIDGET(QComboBox, cbScope)->currentText();
315 switch (
WIDGET(QComboBox, cbScope)->currentIndex()) {
317 _name =
WIDGET(QComboBox, cbNameG)->currentText();
320 _name =
WIDGET(QComboBox, cbNameN)->currentText();
323 _name =
WIDGET(QComboBox, cbNameE)->currentText();
326 QString _value =
WIDGET(QLineEdit, leValue)->text();
328 if (_value.trimmed().isEmpty())
329 QMessageBox::warning(
this, tr(
"GvEdit"),
330 tr(
"Please enter a value for selected attribute!"),
331 QMessageBox::Ok, QMessageBox::Ok);
333 QString
str = _scope + QLatin1Char(u
'[') + _name + QLatin1String(
"=\"");
334 if (
WIDGET(QTextEdit, teAttributes)->toPlainText().contains(
str)) {
335 QMessageBox::warning(
this, tr(
"GvEdit"),
336 tr(
"Attribute is already defined!"), QMessageBox::Ok,
340 str =
str + _value + QLatin1String(
"\"]");
341 WIDGET(QTextEdit, teAttributes)
342 ->setPlainText(
WIDGET(QTextEdit, teAttributes)->toPlainText() +
str +
348void CFrmSettings::helpSlot() {
349 QDesktopServices::openUrl(
350 QUrl(QStringLiteral(
"http://www.graphviz.org/doc/info/attrs.html")));
353void CFrmSettings::cancelSlot() { this->reject(); }
355void CFrmSettings::okSlot() {
360void CFrmSettings::newSlot() {
361 WIDGET(QTextEdit, teAttributes)->setPlainText(tr(
""));
364void CFrmSettings::openSlot() {
365 QString
fileName = QFileDialog::getOpenFileName(
366 this, tr(
"Open File"), QStringLiteral(
"/"), tr(
"Text file (*.*)"));
369 if (!file.open(QFile::ReadOnly | QFile::Text)) {
370 QMessageBox::warning(
this, tr(
"MDI"),
371 tr(
"Cannot read file %1:\n%2.")
373 .arg(file.errorString()));
377 QTextStream in(&file);
378 WIDGET(QTextEdit, teAttributes)->setPlainText(in.readAll());
382void CFrmSettings::saveSlot() {
384 if (
WIDGET(QTextEdit, teAttributes)->toPlainText().trimmed().isEmpty()) {
385 QMessageBox::warning(
this, tr(
"GvEdit"), tr(
"Nothing to save!"),
386 QMessageBox::Ok, QMessageBox::Ok);
390 QString
fileName = QFileDialog::getSaveFileName(
391 this, tr(
"Open File"), QStringLiteral(
"/"), tr(
"Text File(*.*)"));
395 if (!file.open(QFile::WriteOnly | QFile::Text)) {
396 QMessageBox::warning(
this, tr(
"MDI"),
397 tr(
"Cannot write file %1:\n%2.")
399 .arg(file.errorString()));
403 QTextStream
out(&file);
404 out <<
WIDGET(QTextEdit, teAttributes)->toPlainText();
409bool CFrmSettings::loadGraph(
MdiChild *m) {
420bool CFrmSettings::createLayout() {
426 WIDGET(QTextEdit, teAttributes)->toPlainText());
433 rdr.
data = bytes.constData();
454 QTemporaryFile tempFile;
455 tempFile.setAutoRemove(
false);
457 QString a = tempFile.fileName();
462void CFrmSettings::doPreview(
const QString &
fileName) {
477bool CFrmSettings::renderLayout() {
480 QString sfx =
WIDGET(QComboBox, cbExtension)->currentText();
483 if (
fileName.isEmpty() || sfx == QLatin1String(
"NONE"))
484 doPreview(QString());
498 if (outf.open(QIODevice::WriteOnly))
501 QString pathName = QDir::homePath();
502 pathName.append(u
'/').append(
fileName);
503 fileName = QDir::toNativeSeparators(pathName);
505 QStringLiteral(
"Output written to %1\n").arg(
fileName);
519bool CFrmSettings::loadLayouts() {
return false; }
521bool CFrmSettings::loadRenderers() {
return false; }
523void CFrmSettings::refreshContent() {
526 WIDGET(QComboBox, cbExtension)->setCurrentIndex(activeWindow->
renderIdx);
530 WIDGET(QLineEdit, leOutput)
533 WIDGET(QComboBox, cbExtension)->currentText());
537 WIDGET(QLineEdit, leValue)->clear();
540void CFrmSettings::saveContent() {
542 activeWindow->
renderIdx =
WIDGET(QComboBox, cbExtension)->currentIndex();
548 if (createLayout() && renderLayout()) {
553 return QDialog::Accepted;
557 if (this->loadGraph(m))
561 if (this->loadGraph(m))
564 return QDialog::Rejected;
573 if (this->loadGraph(m)) {
577 return QDialog::Rejected;
580void CFrmSettings::setActiveWindow(
MdiChild *m) { this->activeWindow = m; }
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
int runSettings(MdiChild *m)
int showSettings(MdiChild *m)
MdiChild * getActiveWindow()
std::unique_ptr< ImageViewer > previewFrm
bool loadPreview(const QString &fileName)
void setupUi(QDialog *Dialog)
bool loadAttrs(const QString &fileName, QComboBox *cbNameG, QComboBox *cbNameN, QComboBox *cbNameE)
QString stripFileExtension(const QString &fileName)
static std::string find_me(void)
find an absolute path to the current executable
int errorPipe(char *errMsg)
static std::string readln(const std::string &path)
readlink-alike but dynamically allocates
static std::string find_share(void)
find an absolute path to where Smyrna auxiliary files are stored
static QString buildTempFile()
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Agraph_t * agmemread(const char *cp)
reads a graph from the input string
void agsetfile(const char *)
sets the current file name for subsequent error reporting
int gvLayout(GVC_t *gvc, graph_t *g, const char *engine)
int gvRenderFilename(GVC_t *gvc, graph_t *g, const char *format, const char *filename)
char * fileName(ingraph_state *sp)
Return name of current file being processed.
static int layout(graph_t *g, layout_info *infop)