summaryrefslogtreecommitdiff
path: root/src/data
diff options
context:
space:
mode:
authorAleks Kissinger <aleks0@gmail.com>2018-03-17 19:01:02 -0400
committerAleks Kissinger <aleks0@gmail.com>2018-03-17 19:01:02 -0400
commit3cea1514203a451c0a8806d276807863b463a78f (patch)
treed6850ab0f41a6d85f3504e8c92fcecf79b37689b /src/data
parent39c2c74c664a6c770639ead8f45322352cacb997 (diff)
added saving, style application, and copy and paste
Diffstat (limited to 'src/data')
-rw-r--r--src/data/edge.cpp22
-rw-r--r--src/data/edge.h1
-rw-r--r--src/data/graph.cpp82
-rw-r--r--src/data/graph.h25
-rw-r--r--src/data/graphelementdata.cpp17
-rw-r--r--src/data/graphelementdata.h6
-rw-r--r--src/data/node.cpp35
-rw-r--r--src/data/node.h7
-rw-r--r--src/data/nodestyle.cpp10
-rw-r--r--src/data/nodestyle.h10
-rw-r--r--src/data/tikzdocument.cpp45
-rw-r--r--src/data/tikzdocument.h3
12 files changed, 239 insertions, 24 deletions
diff --git a/src/data/edge.cpp b/src/data/edge.cpp
index e4d5d69..d3396e8 100644
--- a/src/data/edge.cpp
+++ b/src/data/edge.cpp
@@ -25,6 +25,28 @@ Edge::~Edge()
delete _edgeNode;
}
+/*!
+ * @brief Edge::copy makes a deep copy of an edge.
+ * @param nodeTable is an optional pointer to a table mapping the old source/target
+ * node pointers to their new, copied versions. This is used when making a copy of
+ * an entire (sub)graph.
+ * @return a copy of the edge
+ */
+Edge *Edge::copy(QMap<Node*,Node*> *nodeTable)
+{
+ Edge *e;
+ if (nodeTable == 0) e = new Edge(_source, _target);
+ else e = new Edge(nodeTable->value(_source), nodeTable->value(_target));
+ e->setData(_data->copy());
+ e->setBasicBendMode(_basicBendMode);
+ e->setBend(_bend);
+ e->setInAngle(_inAngle);
+ e->setOutAngle(_outAngle);
+ e->setWeight(_weight);
+ e->updateControls();
+ return e;
+}
+
Node *Edge::source() const
{
return _source;
diff --git a/src/data/edge.h b/src/data/edge.h
index 595b094..f010acd 100644
--- a/src/data/edge.h
+++ b/src/data/edge.h
@@ -13,6 +13,7 @@ class Edge : public QObject
public:
explicit Edge(Node *s, Node *t, QObject *parent = 0);
~Edge();
+ Edge *copy(QMap<Node *, Node *> *nodeTable = 0);
Node *source() const;
Node *target() const;
diff --git a/src/data/graph.cpp b/src/data/graph.cpp
index ba9a4c6..7a5fedc 100644
--- a/src/data/graph.cpp
+++ b/src/data/graph.cpp
@@ -54,6 +54,32 @@ void Graph::removeEdge(Edge *e)
_edges.removeOne(e);
}
+int Graph::maxIntName()
+{
+ int max = -1;
+ int i;
+ bool ok;
+ foreach (Node *n, _nodes) {
+ i = n->name().toInt(&ok);
+ if (ok && i > max) max = i;
+ }
+ return max;
+}
+
+QString Graph::freshNodeName()
+{
+ return QString::number(maxIntName() + 1);
+}
+
+void Graph::renameApart(Graph *graph)
+{
+ int i = graph->maxIntName() + 1;
+ foreach (Node *n, _nodes) {
+ n->setName(QString::number(i));
+ i++;
+ }
+}
+
GraphElementData *Graph::data() const
{
return _data;
@@ -92,21 +118,27 @@ QString Graph::tikz()
{
QString str;
QTextStream code(&str);
+ int line = 0;
code << "\\begin{tikzpicture}" << _data->tikz() << "\n";
+ line++;
if (hasBbox()) {
code << "\t\\path [use as bounding box] ("
<< _bbox.topLeft().x() << "," << _bbox.topLeft().y()
<< ") rectangle ("
<< _bbox.bottomRight().x() << "," << _bbox.bottomRight().y()
<< ");\n";
+ line++;
}
- if (!_nodes.isEmpty())
+ if (!_nodes.isEmpty()) {
code << "\t\\begin{pgfonlayer}{nodelayer}\n";
+ line++;
+ }
Node *n;
foreach (n, _nodes) {
+ n->setTikzLine(line);
code << "\t\t\\node ";
if (!n->data()->isEmpty())
@@ -115,17 +147,23 @@ QString Graph::tikz()
code << "(" << n->name() << ") at ("
<< n->point().x() << ", " << n->point().y()
<< ") {" << n->label() << "};\n";
+ line++;
}
- if (!_nodes.isEmpty())
+ if (!_nodes.isEmpty()) {
code << "\t\\end{pgfonlayer}\n";
+ line++;
+ }
- if (!_edges.isEmpty())
+ if (!_edges.isEmpty()) {
code << "\t\\begin{pgfonlayer}{edgelayer}\n";
+ line++;
+ }
Edge *e;
foreach (e, _edges) {
+ e->updateData();
code << "\t\t\\draw ";
if (!e->data()->isEmpty())
@@ -153,17 +191,53 @@ QString Graph::tikz()
}
code << ";\n";
+ line++;
}
- if (!_edges.isEmpty())
+ if (!_edges.isEmpty()) {
code << "\t\\end{pgfonlayer}\n";
+ line++;
+ }
code << "\\end{tikzpicture}\n";
+ line++;
code.flush();
return str;
}
+Graph *Graph::copyOfSubgraphWithNodes(QSet<Node *> nds)
+{
+ Graph *g = new Graph();
+ g->setData(_data->copy());
+ QMap<Node*,Node*> nodeTable;
+ foreach (Node *n, nds) {
+ Node *n1 = n->copy();
+ nodeTable.insert(n, n1);
+ g->addNode(n1);
+ }
+ foreach (Edge *e, edges()) {
+ if (nds.contains(e->source()) || nds.contains(e->target())) {
+ g->addEdge(e->copy(&nodeTable));
+ }
+ }
+
+ return g;
+}
+
+void Graph::insertGraph(Graph *graph)
+{
+ QMap<Node*,Node*> nodeTable;
+ foreach (Node *n, graph->nodes()) {
+ Node *n1 = n->copy();
+ nodeTable.insert(n, n1);
+ addNode(n1);
+ }
+ foreach (Edge *e, graph->edges()) {
+ addEdge(e->copy(&nodeTable));
+ }
+}
+
void Graph::setBbox(const QRectF &bbox)
{
_bbox = bbox;
diff --git a/src/data/graph.h b/src/data/graph.h
index c25d51b..4d575e4 100644
--- a/src/data/graph.h
+++ b/src/data/graph.h
@@ -27,6 +27,15 @@ public:
void addEdge(Edge *e);
void addEdge(Edge *e, int index);
void removeEdge(Edge *e);
+ int maxIntName();
+ QString freshNodeName();
+
+ /*!
+ * \brief renameApart assigns fresh names to all of the nodes in "this",
+ * with respect to the given graph
+ * \param graph
+ */
+ void renameApart(Graph *graph);
GraphElementData *data() const;
void setData(GraphElementData *data);
@@ -40,6 +49,22 @@ public:
void clearBbox();
QString tikz();
+
+ /*!
+ * \brief copyOfSubgraphWithNodes produces a copy of the full subgraph
+ * with the given nodes. Used for cutting and copying to clipboard.
+ * \param nds
+ * \return
+ */
+ Graph *copyOfSubgraphWithNodes(QSet<Node*> nds);
+
+ /*!
+ * \brief insertGraph inserts a copy of the given graph. Prior to calling this
+ * method, the node names in the given graph should be made fresh via
+ * "renameApart".
+ * \param graph
+ */
+ void insertGraph(Graph *graph);
signals:
public slots:
diff --git a/src/data/graphelementdata.cpp b/src/data/graphelementdata.cpp
index 43f7516..63c8cea 100644
--- a/src/data/graphelementdata.cpp
+++ b/src/data/graphelementdata.cpp
@@ -3,9 +3,14 @@
#include <QDebug>
#include <QTextStream>
-GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent)
+GraphElementData::GraphElementData(QVector<GraphElementProperty> init, QObject *parent) : QAbstractItemModel(parent)
{
root = new GraphElementProperty();
+ _properties = init;
+}
+
+GraphElementData::GraphElementData(QObject *parent) : QAbstractItemModel(parent) {
+ root = new GraphElementProperty();
}
GraphElementData::~GraphElementData()
@@ -13,6 +18,11 @@ GraphElementData::~GraphElementData()
delete root;
}
+GraphElementData *GraphElementData::copy()
+{
+ return new GraphElementData(_properties);
+}
+
void GraphElementData::setProperty(QString key, QString value)
{
GraphElementProperty m(key, true);
@@ -170,3 +180,8 @@ bool GraphElementData::isEmpty()
{
return _properties.isEmpty();
}
+
+QVector<GraphElementProperty> GraphElementData::properties() const
+{
+ return _properties;
+}
diff --git a/src/data/graphelementdata.h b/src/data/graphelementdata.h
index 0d43bb8..319edf7 100644
--- a/src/data/graphelementdata.h
+++ b/src/data/graphelementdata.h
@@ -13,8 +13,11 @@ class GraphElementData : public QAbstractItemModel
{
Q_OBJECT
public:
+ explicit GraphElementData(QVector<GraphElementProperty> init,
+ QObject *parent = 0);
explicit GraphElementData(QObject *parent = 0);
~GraphElementData();
+ GraphElementData *copy();
void setProperty(QString key, QString value);
void unsetProperty(QString key);
void setAtom(QString atom);
@@ -22,7 +25,6 @@ public:
QString property(QString key);
bool atom(QString atom);
-
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
@@ -55,6 +57,8 @@ public:
QString tikz();
bool isEmpty();
+ QVector<GraphElementProperty> properties() const;
+
signals:
public slots:
diff --git a/src/data/node.cpp b/src/data/node.cpp
index c78f49c..085bdf5 100644
--- a/src/data/node.cpp
+++ b/src/data/node.cpp
@@ -3,11 +3,11 @@
#include <QDebug>
-Node::Node(QObject *parent) : QObject(parent)
+Node::Node(QObject *parent) : QObject(parent), _tikzLine(-1)
{
_data = new GraphElementData();
_style = noneStyle;
- _styleName = "none";
+ _data->setProperty("style", "none");
}
Node::~Node()
@@ -15,6 +15,17 @@ Node::~Node()
delete _data;
}
+Node *Node::copy() {
+ Node *n1 = new Node();
+ n1->setName(name());
+ n1->setData(data()->copy());
+ n1->setPoint(point());
+ n1->setLabel(label());
+ n1->attachStyle();
+ n1->setTikzLine(tikzLine());
+ return n1;
+}
+
QPointF Node::point() const
{
return _point;
@@ -54,26 +65,36 @@ void Node::setData(GraphElementData *data)
{
delete _data;
_data = data;
- if (_data->property("style") != 0) _styleName = _data->property("style");
}
QString Node::styleName() const
{
- return _styleName;
+ return _data->property("style");
}
void Node::setStyleName(const QString &styleName)
{
- _styleName = styleName;
+ _data->setProperty("style", styleName);
}
void Node::attachStyle()
{
- if (_styleName == "none") _style = noneStyle;
- else _style = tikzit->styles()->nodeStyle(_styleName);
+ QString nm = styleName();
+ if (nm == "none") _style = noneStyle;
+ else _style = tikzit->styles()->nodeStyle(nm);
}
NodeStyle *Node::style() const
{
return _style;
}
+
+int Node::tikzLine() const
+{
+ return _tikzLine;
+}
+
+void Node::setTikzLine(int tikzLine)
+{
+ _tikzLine = tikzLine;
+}
diff --git a/src/data/node.h b/src/data/node.h
index ee70835..241d1ca 100644
--- a/src/data/node.h
+++ b/src/data/node.h
@@ -15,6 +15,8 @@ public:
explicit Node(QObject *parent = 0);
~Node();
+ Node *copy();
+
QPointF point() const;
void setPoint(const QPointF &point);
@@ -33,6 +35,9 @@ public:
void attachStyle();
NodeStyle *style() const;
+ int tikzLine() const;
+ void setTikzLine(int tikzLine);
+
signals:
public slots:
@@ -41,9 +46,9 @@ private:
QPointF _point;
QString _name;
QString _label;
- QString _styleName;
NodeStyle *_style;
GraphElementData *_data;
+ int _tikzLine;
};
#endif // NODE_H
diff --git a/src/data/nodestyle.cpp b/src/data/nodestyle.cpp
index e38d3a3..302ab84 100644
--- a/src/data/nodestyle.cpp
+++ b/src/data/nodestyle.cpp
@@ -24,13 +24,13 @@ QString NodeStyle::name() const
return _name;
}
-NodeShape NodeStyle::shape() const
+NodeStyle::Shape NodeStyle::shape() const
{
QString sh = _data->property("shape");
- if (sh.isNull()) return NodeShape::Circle;
- else if (sh == "circle") return NodeShape::Circle;
- else if (sh == "rectangle") return NodeShape::Rectangle;
- else return NodeShape::Circle;
+ if (sh.isNull()) return NodeStyle::Circle;
+ else if (sh == "circle") return NodeStyle::Circle;
+ else if (sh == "rectangle") return NodeStyle::Rectangle;
+ else return NodeStyle::Circle;
}
QColor NodeStyle::fillColor() const
diff --git a/src/data/nodestyle.h b/src/data/nodestyle.h
index 58c0c12..0b9f282 100644
--- a/src/data/nodestyle.h
+++ b/src/data/nodestyle.h
@@ -9,20 +9,20 @@
#include <QPainterPath>
#include <QIcon>
-enum NodeShape {
- Rectangle, UpTriangle, DownTriangle, Circle
-};
-
class NodeStyle
{
public:
+ enum Shape {
+ Rectangle, UpTriangle, DownTriangle, Circle
+ };
+
NodeStyle();
NodeStyle(QString name, GraphElementData *data);
bool isNone();
GraphElementData *data() const;
QString name() const;
- NodeShape shape() const;
+ Shape shape() const;
QColor fillColor() const;
QColor strokeColor() const;
int strokeThickness() const;
diff --git a/src/data/tikzdocument.cpp b/src/data/tikzdocument.cpp
index a3fa961..eeb4e14 100644
--- a/src/data/tikzdocument.cpp
+++ b/src/data/tikzdocument.cpp
@@ -3,9 +3,12 @@
#include <QSettings>
#include <QTextStream>
#include <QMessageBox>
+#include <QFileDialog>
+#include "tikzit.h"
#include "tikzdocument.h"
#include "tikzassembler.h"
+#include "mainwindow.h"
TikzDocument::TikzDocument(QObject *parent) : QObject(parent)
{
@@ -71,6 +74,41 @@ void TikzDocument::open(QString fileName)
}
}
+void TikzDocument::save() {
+ if (_fileName == "") {
+ saveAs();
+ } else {
+ refreshTikz();
+ QFile file(_fileName);
+ QFileInfo fi(file);
+ _shortName = fi.fileName();
+ QSettings settings("tikzit", "tikzit");
+ settings.setValue("previous-file-path", fi.absolutePath());
+
+ if (file.open(QIODevice::ReadWrite)) {
+ QTextStream stream(&file);
+ stream << _tikz;
+ file.close();
+ tikzit->activeWindow()->updateFileName();
+ } else {
+ QMessageBox::warning(0, "Save Failed", "Could not open file: '" + _fileName + "' for writing.");
+ }
+ }
+}
+
+void TikzDocument::saveAs() {
+ QSettings settings("tikzit", "tikzit");
+ QString fileName = QFileDialog::getSaveFileName(tikzit->activeWindow(),
+ tr("Save File As"),
+ settings.value("previous-file-path").toString(),
+ tr("TiKZ Files (*.tikz)"));
+
+ if (!fileName.isEmpty()) {
+ _fileName = fileName;
+ save();
+ }
+}
+
QString TikzDocument::shortName() const
{
return _shortName;
@@ -80,3 +118,10 @@ bool TikzDocument::parseSuccess() const
{
return _parseSuccess;
}
+
+void TikzDocument::refreshTikz()
+{
+ _tikz = _graph->tikz();
+ if (MainWindow *w = dynamic_cast<MainWindow*>(parent()))
+ w->refreshTikz();
+}
diff --git a/src/data/tikzdocument.h b/src/data/tikzdocument.h
index d3a18b1..edb1beb 100644
--- a/src/data/tikzdocument.h
+++ b/src/data/tikzdocument.h
@@ -22,11 +22,14 @@ public:
QString tikz() const;
QUndoStack *undoStack() const;
bool parseSuccess() const;
+ void refreshTikz();
void open(QString fileName);
QString shortName() const;
+ void saveAs();
+ void save();
private:
Graph *_graph;
QString _tikz;