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) (findChild<t *>(QStringLiteral(#f)))
47static std::string
readln(
const std::string &pathname) {
49 std::vector<char> buf(512,
'\0');
54 buf.resize(buf.size() * 2);
58 ssize_t written = readlink(pathname.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> pathname(buf_size);
89 if (_NSGetExecutablePath(pathname.data(), &buf_size) < 0) {
90 errout <<
"failed to get path for executable.\n";
95 for (std::string p = pathname.data();;) {
96 const std::string buf =
readln(p);
105 std::vector<char> pathname;
110 size_t size = pathname.empty() ? 1024 : (pathname.size() * 2);
111 pathname.resize(size);
114 rc = GetModuleFileNameA(
NULL, pathname.data(), pathname.size());
116 errout <<
"failed to get path for executable.\n";
120 }
while (rc == pathname.size());
122 return pathname.data();
127 std::string pathname =
readln(
"/proc/self/exe");
132 pathname =
readln(
"/proc/curproc/file");
137 pathname =
readln(
"/proc/curproc/exe");
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);
234 <<
"\" for reading\n";
254 activeWindow =
nullptr;
258 s = getenv(
"GVEDIT_PATH");
261 pathname = QString::fromUtf8(
s);
263 pathname = QString::fromStdString(
find_share());
265 connect(
WIDGET(QPushButton, pbAdd), &QPushButton::clicked,
this,
266 &CFrmSettings::addSlot);
267 connect(
WIDGET(QPushButton, pbNew), &QPushButton::clicked,
this,
268 &CFrmSettings::newSlot);
269 connect(
WIDGET(QPushButton, pbOpen), &QPushButton::clicked,
this,
270 &CFrmSettings::openSlot);
271 connect(
WIDGET(QPushButton, pbSave), &QPushButton::clicked,
this,
272 &CFrmSettings::saveSlot);
273 connect(
WIDGET(QPushButton, btnOK), &QPushButton::clicked,
this,
274 &CFrmSettings::okSlot);
275 connect(
WIDGET(QPushButton, btnCancel), &QPushButton::clicked,
this,
276 &CFrmSettings::cancelSlot);
277 connect(
WIDGET(QPushButton, pbOut), &QPushButton::clicked,
this,
278 &CFrmSettings::outputSlot);
279 connect(
WIDGET(QPushButton, pbHelp), &QPushButton::clicked,
this,
280 &CFrmSettings::helpSlot);
282 connect(
WIDGET(QComboBox, cbScope),
283 QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
284 &CFrmSettings::scopeChangedSlot);
287 if (!pathname.isEmpty()) {
288 loadAttrs(pathname + QLatin1String(
"/attrs.txt"),
290 WIDGET(QComboBox, cbNameE));
292 setWindowIcon(QIcon(QStringLiteral(
":/images/icon.png")));
295void CFrmSettings::outputSlot() {
296 QString _filter = QStringLiteral(
"Output File(*.%1)")
297 .arg(
WIDGET(QComboBox, cbExtension)->currentText());
298 QString
fileName = QFileDialog::getSaveFileName(
this, tr(
"Save Graph As.."),
299 QStringLiteral(
"/"), _filter);
304void CFrmSettings::scopeChangedSlot(
int id) {
305 WIDGET(QComboBox, cbNameG)->setVisible(
id == 0);
306 WIDGET(QComboBox, cbNameN)->setVisible(
id == 1);
307 WIDGET(QComboBox, cbNameE)->setVisible(
id == 2);
310void CFrmSettings::addSlot() {
311 QString _scope =
WIDGET(QComboBox, cbScope)->currentText();
313 switch (
WIDGET(QComboBox, cbScope)->currentIndex()) {
315 _name =
WIDGET(QComboBox, cbNameG)->currentText();
318 _name =
WIDGET(QComboBox, cbNameN)->currentText();
321 _name =
WIDGET(QComboBox, cbNameE)->currentText();
324 QString _value =
WIDGET(QLineEdit, leValue)->text();
326 if (_value.trimmed().isEmpty())
327 QMessageBox::warning(
this, tr(
"GvEdit"),
328 tr(
"Please enter a value for selected attribute!"),
329 QMessageBox::Ok, QMessageBox::Ok);
331 QString
str = _scope + QLatin1Char(u
'[') + _name + QLatin1String(
"=\"");
332 if (
WIDGET(QTextEdit, teAttributes)->toPlainText().contains(
str)) {
333 QMessageBox::warning(
this, tr(
"GvEdit"),
334 tr(
"Attribute is already defined!"), QMessageBox::Ok,
338 str =
str + _value + QLatin1String(
"\"]");
339 WIDGET(QTextEdit, teAttributes)
340 ->setPlainText(
WIDGET(QTextEdit, teAttributes)->toPlainText() +
str +
345void CFrmSettings::helpSlot() {
346 QDesktopServices::openUrl(
347 QUrl(QStringLiteral(
"http://www.graphviz.org/doc/info/attrs.html")));
350void CFrmSettings::cancelSlot() { this->reject(); }
352void CFrmSettings::okSlot() {
357void CFrmSettings::newSlot() {
358 WIDGET(QTextEdit, teAttributes)->setPlainText(tr(
""));
361void CFrmSettings::openSlot() {
362 QString
fileName = QFileDialog::getOpenFileName(
363 this, tr(
"Open File"), QStringLiteral(
"/"), tr(
"Text file (*.*)"));
366 if (!file.open(QFile::ReadOnly | QFile::Text)) {
367 QMessageBox::warning(
this, tr(
"MDI"),
368 tr(
"Cannot read file %1:\n%2.")
370 .arg(file.errorString()));
374 QTextStream in(&file);
375 WIDGET(QTextEdit, teAttributes)->setPlainText(in.readAll());
379void CFrmSettings::saveSlot() {
381 if (
WIDGET(QTextEdit, teAttributes)->toPlainText().trimmed().isEmpty()) {
382 QMessageBox::warning(
this, tr(
"GvEdit"), tr(
"Nothing to save!"),
383 QMessageBox::Ok, QMessageBox::Ok);
387 QString
fileName = QFileDialog::getSaveFileName(
388 this, tr(
"Open File"), QStringLiteral(
"/"), tr(
"Text File(*.*)"));
392 if (!file.open(QFile::WriteOnly | QFile::Text)) {
393 QMessageBox::warning(
this, tr(
"MDI"),
394 tr(
"Cannot write file %1:\n%2.")
396 .arg(file.errorString()));
400 QTextStream
out(&file);
401 out <<
WIDGET(QTextEdit, teAttributes)->toPlainText();
405bool CFrmSettings::loadGraph(
MdiChild *m) {
416bool CFrmSettings::createLayout() {
422 WIDGET(QTextEdit, teAttributes)->toPlainText());
429 rdr.
data = bytes.constData();
450 QTemporaryFile tempFile;
451 tempFile.setAutoRemove(
false);
453 QString a = tempFile.fileName();
457void CFrmSettings::doPreview(
const QString &
fileName) {
472bool CFrmSettings::renderLayout() {
475 QString sfx =
WIDGET(QComboBox, cbExtension)->currentText();
478 if (
fileName.isEmpty() || sfx == QLatin1String(
"NONE"))
479 doPreview(QString());
493 if (!outf.open(QIODevice::WriteOnly)) {
494 QString pathName = QDir::homePath();
495 pathName.append(u
'/').append(
fileName);
496 fileName = QDir::toNativeSeparators(pathName);
498 QStringLiteral(
"Output written to %1\n").arg(
fileName);
512bool CFrmSettings::loadLayouts() {
return false; }
514bool CFrmSettings::loadRenderers() {
return false; }
516void CFrmSettings::refreshContent() {
519 WIDGET(QComboBox, cbExtension)->setCurrentIndex(activeWindow->
renderIdx);
523 WIDGET(QLineEdit, leOutput)
526 WIDGET(QComboBox, cbExtension)->currentText());
530 WIDGET(QLineEdit, leValue)->clear();
533void CFrmSettings::saveContent() {
535 activeWindow->
renderIdx =
WIDGET(QComboBox, cbExtension)->currentIndex();
541 if (createLayout() && renderLayout()) {
546 return QDialog::Accepted;
550 if (this->loadGraph(m))
554 if (this->loadGraph(m))
556 return QDialog::Rejected;
564 if (this->loadGraph(m)) {
568 return QDialog::Rejected;
571void 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
static std::string readln(const std::string &pathname)
readlink-alike but dynamically allocates
int errorPipe(char *errMsg)
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)
textitem scanner parser str
char * fileName(ingraph_state *sp)
Return name of current file being processed.
static int layout(graph_t *g, layout_info *infop)