]> Some of my projects - graph.git/commitdiff
Almost there.
authorAPTX <marek321@gmail.com>
Tue, 13 Dec 2011 03:13:11 +0000 (04:13 +0100)
committerAPTX <marek321@gmail.com>
Tue, 13 Dec 2011 03:13:11 +0000 (04:13 +0100)
17 files changed:
colorlisteditor.cpp [new file with mode: 0644]
colorlisteditor.h [new file with mode: 0644]
defines.h [new file with mode: 0644]
edge.cpp [new file with mode: 0644]
edge.h [new file with mode: 0644]
edgemodel.cpp [new file with mode: 0644]
edgemodel.h [new file with mode: 0644]
graph.cpp [new file with mode: 0644]
graph.h [new file with mode: 0644]
graph.pro
mainwindow.cpp
mainwindow.h
mainwindow.ui
node.cpp [new file with mode: 0644]
node.h [new file with mode: 0644]
nodemodel.cpp [new file with mode: 0644]
nodemodel.h [new file with mode: 0644]

diff --git a/colorlisteditor.cpp b/colorlisteditor.cpp
new file mode 100644 (file)
index 0000000..b9e7a45
--- /dev/null
@@ -0,0 +1,28 @@
+#include "colorlisteditor.h"
+
+ColorListEditor::ColorListEditor(QWidget *widget) : QComboBox(widget)
+{
+       populateList();
+}
+
+QColor ColorListEditor::color() const
+{
+       return qVariantValue<QColor>(itemData(currentIndex(), Qt::DecorationRole));
+}
+
+void ColorListEditor::setColor(QColor color)
+{
+       setCurrentIndex(findData(color, int(Qt::DecorationRole)));
+}
+
+void ColorListEditor::populateList()
+{
+       QStringList colorNames = QColor::colorNames();
+
+       for (int i = 0; i < colorNames.size(); ++i) {
+               QColor color(colorNames[i]);
+
+               insertItem(i, colorNames[i]);
+               setItemData(i, color, Qt::DecorationRole);
+       }
+}
diff --git a/colorlisteditor.h b/colorlisteditor.h
new file mode 100644 (file)
index 0000000..e023e85
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef COLORLISTEDITOR_H
+#define COLORLISTEDITOR_H
+
+#include <QComboBox>
+
+class QColor;
+
+class ColorListEditor : public QComboBox
+{
+       Q_OBJECT
+       Q_PROPERTY(QColor color READ color WRITE setColor USER true)
+
+public:
+       ColorListEditor(QWidget *widget = 0);
+
+public:
+       QColor color() const;
+       void setColor(QColor c);
+
+private:
+       void populateList();
+};
+
+#endif // COLORLISTEDITOR_H
diff --git a/defines.h b/defines.h
new file mode 100644 (file)
index 0000000..9b9c108
--- /dev/null
+++ b/defines.h
@@ -0,0 +1,12 @@
+#ifndef DEFINES_H
+#define DEFINES_H
+
+#include <QList>
+
+class Node;
+class Edge;
+
+typedef QList<Node *> NodeList;
+typedef QList<Edge *> EdgeList;
+
+#endif // DEFINES_H
diff --git a/edge.cpp b/edge.cpp
new file mode 100644 (file)
index 0000000..beb35b5
--- /dev/null
+++ b/edge.cpp
@@ -0,0 +1,56 @@
+#include "edge.h"
+
+#include <QPainter>
+#include <QPen>
+#include <QGraphicsItem>
+#include "node.h"
+
+Edge::Edge(Node *startNode, Node *endNode) : m_startNode(startNode), m_endNode(endNode), m_weight(1)
+{
+
+}
+
+void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+       Q_UNUSED(option);
+       Q_UNUSED(widget);
+       painter->setPen(m_color);
+       painter->drawLine(m_startNode->pos(), m_endNode->pos());
+//     painter->drawText(boundingRect(), Qt::AlignCenter, QString::number(m_weight));
+}
+
+QRectF Edge::boundingRect() const
+{
+       QPointF tl(qMin(m_startNode->x(), m_endNode->x()), qMin(m_startNode->y(), m_endNode->y()));
+       QPointF br(qMax(m_startNode->x(), m_endNode->x()), qMax(m_startNode->y(), m_endNode->y()));
+       return QRectF(tl, br);
+}
+
+QPainterPath Edge::shape() const
+{
+       QPainterPath p;
+       p.moveTo(m_startNode->pos());
+       p.lineTo(m_endNode->pos());
+
+       QPainterPathStroker ps;
+       ps.setWidth(6);
+       return ps.createStroke(p);
+}
+
+QDataStream &operator<<(QDataStream &s, const Edge &edge)
+{
+       s << edge.weight();
+       s << edge.color();
+       return s;
+}
+
+QDataStream &operator>>(QDataStream &s, Edge &edge)
+{
+       int weight;
+       QColor color;
+       s >> weight;
+       s >> color;
+       edge.setWeight(weight);
+       edge.setColor(color);
+       return s;
+}
diff --git a/edge.h b/edge.h
new file mode 100644 (file)
index 0000000..90b8cee
--- /dev/null
+++ b/edge.h
@@ -0,0 +1,71 @@
+#ifndef EDGE_H
+#define EDGE_H
+
+#include <QGraphicsObject>
+
+#include "defines.h"
+
+class Edge : public QGraphicsObject
+{
+       Q_OBJECT
+       Q_PROPERTY(int weight READ weight WRITE setWeight)
+       Q_PROPERTY(QColor color READ color WRITE setColor)
+       Q_PROPERTY(Node *startNode READ startNode)
+       Q_PROPERTY(Node *endNode READ endNode)
+
+public:
+       enum { Type = UserType + 2};
+
+       Edge(Node *startNode, Node *endNode);
+
+       int type() const
+       {
+               return Type;
+       }
+
+       int weight() const
+       {
+               return m_weight;
+       }
+
+       QColor color() const
+       {
+               return m_color;
+       }
+
+       Node *startNode() const
+       {
+               return m_startNode;
+       }
+
+       Node *endNode() const
+       {
+               return m_endNode;
+       }
+
+       void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+       QRectF boundingRect() const;
+       QPainterPath shape() const;
+
+public slots:
+       void setWeight(int weight)
+       {
+               m_weight = weight;
+       }
+
+       void setColor(QColor color)
+       {
+               m_color = color;
+       }
+
+private:
+       int m_weight;
+       QColor m_color;
+       Node *m_startNode;
+       Node *m_endNode;
+};
+
+QDataStream &operator<<(QDataStream &s, const Edge &edge);
+QDataStream &operator>>(QDataStream &s, Edge &edge);
+
+#endif // EDGE_H
diff --git a/edgemodel.cpp b/edgemodel.cpp
new file mode 100644 (file)
index 0000000..974a9de
--- /dev/null
@@ -0,0 +1,115 @@
+#include "edgemodel.h"
+
+#include "graph.h"
+#include "node.h"
+#include "edge.h"
+
+EdgeModel::EdgeModel(Graph *graph, QObject *parent) :
+       QAbstractTableModel(parent), g(graph)
+{
+}
+
+Qt::ItemFlags EdgeModel::flags(const QModelIndex &index) const
+{
+       if (index.column() >= 2)
+               return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
+       return QAbstractTableModel::flags(index);
+}
+
+QVariant EdgeModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+       if (role != Qt::DisplayRole)
+               return QVariant();
+       if (orientation == Qt::Vertical)
+               return section + 1;
+
+       switch (section)
+       {
+               case 0:
+                       return "Start";
+               case 1:
+                       return "End";
+               case 2:
+                       return "Weight";
+               case 3:
+                       return "Color";
+               default:
+               break;
+       }
+       return QVariant();
+}
+
+int EdgeModel::rowCount(const QModelIndex &) const
+{
+       return g->m_edgeList.count();
+}
+
+int EdgeModel::columnCount(const QModelIndex &) const
+{
+       return 4;
+}
+
+QVariant EdgeModel::data(const QModelIndex &index, int role) const
+{
+       if (role != Qt::DisplayRole && role != Qt::EditRole)
+               return QVariant();
+
+       Edge *e = g->m_edgeList[index.row()];
+       switch (index.column())
+       {
+               case 0:
+                       return e->startNode()->label();
+               case 1:
+                       return e->endNode()->label();
+               case 2:
+                       return e->weight();
+               case 3:
+                       return e->color();
+               default:
+               break;
+       }
+       return QVariant();
+}
+
+bool EdgeModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+       if (role != Qt::DisplayRole && role != Qt::EditRole)
+               return false;
+
+       Edge *e = g->m_edgeList[index.row()];
+       bool ok;
+       int weight;
+       switch (index.column())
+       {
+               case 0:
+               case 1:
+                       return false;
+               case 2:
+                       weight = value.toInt(&ok);
+                       if (!ok)
+                               return false;
+                       e->setWeight(qMax(0, weight));
+                       e->update();
+                       return true;
+               case 3:
+                       e->setColor(value.value<QColor>());
+                       e->update();
+                       return true;
+               default:
+               break;
+       }
+       return false;
+}
+
+bool EdgeModel::removeRows(int row, int count, const QModelIndex &)
+{
+       for (int i = row; i < row + count; ++i)
+               g->removeEdge(g->m_edgeList.at(i));
+       return true;
+}
+
+void EdgeModel::edgeRemoved(int i)
+{
+       beginRemoveRows(QModelIndex(), i, i + 1);
+       endRemoveRows();
+}
diff --git a/edgemodel.h b/edgemodel.h
new file mode 100644 (file)
index 0000000..f49c89d
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef EDGEMODEL_H
+#define EDGEMODEL_H
+
+#include <QAbstractTableModel>
+
+#include "graph.h"
+
+class EdgeModel : public QAbstractTableModel
+{
+       friend Graph;
+       Q_OBJECT
+public:
+       explicit EdgeModel(Graph *graph, QObject *parent = 0);
+       
+       Qt::ItemFlags flags(const QModelIndex &index) const;
+       QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+       int rowCount(const QModelIndex &parent = QModelIndex()) const;
+       int columnCount(const QModelIndex &parent = QModelIndex()) const;
+       QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+       bool setData(const QModelIndex &index, const QVariant &value, int role);
+
+       bool removeRows(int row, int count, const QModelIndex &parent);
+signals:
+       
+public slots:
+
+private:
+       void edgeRemoved(int i);
+
+       Graph *g;
+};
+#else
+class EdgeModel;
+#endif // EDGEMODEL_H
diff --git a/graph.cpp b/graph.cpp
new file mode 100644 (file)
index 0000000..3931c6a
--- /dev/null
+++ b/graph.cpp
@@ -0,0 +1,285 @@
+#include "graph.h"
+
+#include "node.h"
+#include "edge.h"
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QDataStream>
+#include <QDebug>
+
+Graph::Graph(QObject *parent) :
+       QGraphicsScene(parent), m_nodeModel(new NodeModel(this, this)),
+       m_edgeModel(new EdgeModel(this, this)), m_mode(EditMode), lastNode(1), startNode(0)
+{
+
+}
+
+NodeList Graph::nodes() const
+{
+       return m_nodeList;
+}
+
+EdgeList Graph::edges() const
+{
+       return m_edgeList;
+}
+
+NodeModel *Graph::nodeModel() const
+{
+       return m_nodeModel;
+}
+
+EdgeModel *Graph::edgeModel() const
+{
+       return m_edgeModel;
+}
+
+void Graph::complete()
+{
+       for (int i = 0; i < m_nodeList.count(); ++i)
+       {
+               Node *startNode = m_nodeList[i];
+               EdgeList edges = startNode->outgoingEdges();
+               for (int j = 0; j < m_nodeList.count(); ++j)
+               {
+                       if (i == j)
+                               continue;
+                       Node *endNode = m_nodeList[j];
+                       bool found = false;
+                       for (int e = 0; e < edges.count(); ++e)
+                               if (edges.at(e)->endNode() == endNode)
+                               {
+                                       found = true;
+                                       break;
+                               }
+                       if (!found)
+                               addEdge(startNode, endNode);
+               }
+       }
+}
+
+Node *Graph::addNode(const QPointF &pos, const QString &label, const QColor &color)
+{
+       Node *node = new Node();
+       node->setPos(pos);
+       if (label.isEmpty())
+               node->setLabel(QString::number(lastNode++));
+       else
+               node->setLabel(label);
+       node->setColor(color);
+       node->setZValue(1);
+
+       m_nodeModel->beginInsertRows(QModelIndex(), m_nodeModel->rowCount(), m_nodeModel->rowCount());
+       m_nodeList.append(node);
+       addItem(node);
+       m_nodeModel->endInsertRows();
+       return node;
+}
+
+Edge *Graph::addEdge(Node *start, Node *end, int weight, const QColor &color)
+{
+       if (start == 0 || end == 0)
+               return 0;
+       Edge *edge = new Edge(start, end);
+       edge->setWeight(weight);
+       edge->setColor(color);
+
+       m_edgeModel->beginInsertRows(QModelIndex(), m_edgeModel->rowCount(), m_edgeModel->rowCount());
+       start->m_outgoingEdges.append(edge);
+       end->m_incomingEdges.append(edge);
+       m_edgeList.append(edge);
+       addItem(edge);
+       m_edgeModel->endInsertRows();
+       return edge;
+}
+
+void Graph::removeNode(Node *node)
+{
+       if (!m_nodeList.contains(node))
+               return;
+
+       while (node->outgoingEdges().count())
+               removeEdge(node->m_outgoingEdges.last());
+       while (node->incomingEdges().count())
+               removeEdge(node->m_incomingEdges.last());
+
+       int i = m_nodeList.indexOf(node);
+       m_nodeModel->beginRemoveRows(QModelIndex(), i, i);
+       removeItem(node);
+       m_nodeList.removeAt(i);
+       m_nodeModel->endRemoveRows();
+       node->deleteLater();
+}
+
+void Graph::removeEdge(Edge *edge)
+{
+       if (!m_edgeList.contains(edge))
+               return;
+
+       int i = m_edgeList.indexOf(edge);
+       m_edgeModel->beginRemoveRows(QModelIndex(), i, i);
+
+       removeItem(edge);
+       edge->startNode()->m_outgoingEdges.removeAll(edge);
+       edge->endNode()->m_incomingEdges.removeAll(edge);
+       m_edgeList.removeAt(i);
+       m_edgeModel->endRemoveRows();
+       edge->deleteLater();
+}
+
+void Graph::clear()
+{
+       QGraphicsScene::clear();
+       m_nodeList.clear();
+       m_edgeList.clear();
+       m_nodeModel->reset();
+       m_edgeModel->reset();
+
+       lastNode = 1;
+       startNode = 0;
+}
+
+void Graph::save(QIODevice *dev) const
+{
+       QDataStream s(dev);
+       QMap<Node *, int> ids;
+
+       s << QString("Graph") << (int)0xC00L;
+       s << QString("Node") << (int)0x80DE;
+
+       s << m_nodeList.count();
+       for (int i = 0; i < m_nodeList.count(); ++i)
+       {
+               s << *m_nodeList[i];
+               ids[m_nodeList[i]] = i;
+       }
+
+       s << QString("Edge") << (int)0xED4E;
+
+       s << m_edgeList.count();
+       for (int i = 0; i < m_edgeList.count(); ++i)
+               s << ids[m_edgeList.at(i)->startNode()]
+                 << ids[m_edgeList.at(i)->endNode()]
+                 << *m_edgeList[i];
+}
+
+bool Graph::load(QIODevice *dev)
+{
+       // TODO checks
+       QDataStream s(dev);
+       QString graph, node, edge;
+       int id, nid, eid;
+       s >> graph >> id >> node >> nid;
+
+       clear();
+
+       int nodeCount;
+       s >> nodeCount;
+
+       m_nodeList.reserve(nodeCount);
+       for (int i = 0; i < nodeCount; ++i)
+       {
+               Node *node = addNode();
+               s >> *node;
+       }
+
+       s >> edge >> eid;
+
+       int edgeCount;
+       s >> edgeCount;
+       m_edgeList.reserve(edgeCount);
+       for (int i = 0; i < edgeCount; ++i)
+       {
+               int startNodeId;
+               int endNodeId;
+               s >> startNodeId >> endNodeId;
+
+               Edge *edge = addEdge(m_nodeList[startNodeId], m_nodeList[endNodeId]);
+               s >> *edge;
+       }
+
+       m_nodeModel->reset();
+       m_edgeModel->reset();
+       return false;
+}
+
+void Graph::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+       if (m_mode == EditMode)
+               return QGraphicsScene::mousePressEvent(event);
+       event->ignore();
+}
+
+void Graph::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+       if (m_mode == EditMode)
+       {
+               QGraphicsScene::mouseMoveEvent(event);
+               m_nodeModel->dataChanged(m_nodeModel->index(0, 2), m_nodeModel->index(m_nodeList.count() - 1, 3));
+               return;
+       }
+       event->ignore();
+}
+
+void Graph::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+       if (m_mode == EditMode)
+               return QGraphicsScene::mouseReleaseEvent(event);
+       if (m_mode == AddNodeMode)
+       {
+               addNode(event->scenePos());
+               event->accept();
+               return;
+       }
+       if (m_mode == AddEdgeMode)
+       {
+               event->accept();
+               QGraphicsItem *item = itemAt(event->scenePos());
+               if (item == 0)
+                       return;
+               Node *node = qgraphicsitem_cast<Node *>(item);
+               if (node)
+               {
+                       if (!startNode)
+                       {
+                               startNode = node;
+                       }
+                       else
+                       {
+                               if (startNode != node)
+                               {
+                                       addEdge(startNode, node);
+                                       addEdge(node, startNode);
+                               }
+                               startNode = 0;
+                       }
+                       return;
+               }
+       }
+       if (m_mode == RemoveNode)
+       {
+               event->accept();
+               QGraphicsItem *item = itemAt(event->scenePos());
+               if (item == 0)
+                       return;
+               Node *node = qgraphicsitem_cast<Node *>(item);
+               if (node)
+               {
+                       removeNode(node);
+                       return;
+               }
+               Edge *edge = qgraphicsitem_cast<Edge *>(item);
+               if (edge)
+               {
+                       removeEdge(edge);
+                       return;
+               }
+       }
+       event->ignore();
+}
+
+void Graph::labelChanged() const
+{
+       m_edgeModel->dataChanged(m_edgeModel->index(0, 0), m_edgeModel->index(m_edgeList.count() - 1, 1));
+}
diff --git a/graph.h b/graph.h
new file mode 100644 (file)
index 0000000..5e2ec64
--- /dev/null
+++ b/graph.h
@@ -0,0 +1,81 @@
+#ifndef GRAPH_H
+#define GRAPH_H
+
+#include <QGraphicsScene>
+
+#include "defines.h"
+
+#include "nodemodel.h"
+#include "edgemodel.h"
+
+class Graph : public QGraphicsScene
+{
+       friend NodeModel;
+       friend EdgeModel;
+    Q_OBJECT
+       Q_PROPERTY(Mode mode READ mode WRITE setMode)
+
+public:
+       enum Mode {
+               EditMode,
+               AddNodeMode,
+               AddEdgeMode,
+               RemoveNode
+       };
+
+       explicit Graph(QObject *parent = 0);
+
+       NodeList nodes() const;
+       EdgeList edges() const;
+       NodeModel *nodeModel() const;
+       EdgeModel *edgeModel() const;
+
+       Mode mode() const
+       {
+               return m_mode;
+       }
+
+signals:
+    
+public slots:
+       void complete();
+
+       Node *addNode(const QPointF &pos = QPointF(), const QString &label = QString(), const QColor &color = QColor());
+       Edge *addEdge(Node *start, Node *end, int weight = 1, const QColor &color = QColor());
+
+       void removeNode(Node *node);
+       void removeEdge(Edge *edge);
+       void clear();
+
+       void setMode(Mode mode)
+       {
+               m_mode = mode;
+       }
+
+       void save(QIODevice *dev) const;
+       bool load(QIODevice *dev);
+
+protected:
+       void mousePressEvent(QGraphicsSceneMouseEvent *event);
+       void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+       void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+
+private:
+       void labelChanged() const;
+
+       NodeList m_nodeList;
+       EdgeList m_edgeList;
+
+       NodeModel *m_nodeModel;
+       EdgeModel *m_edgeModel;
+
+       Mode m_mode;
+
+       int lastNode;
+
+       // For adding edges
+       Node *startNode;
+};
+#else
+class Graph;
+#endif // GRAPH_H
index 4e2cd9d64d8fe8e711e9297eefcbc0768c4164bf..4ae7defe3698ba81357d1c4ba873780215e17a12 100644 (file)
--- a/graph.pro
+++ b/graph.pro
@@ -11,8 +11,32 @@ TEMPLATE = app
 
 
 SOURCES += main.cpp\
-        mainwindow.cpp
+        mainwindow.cpp \
+    graph.cpp \
+    node.cpp \
+    edge.cpp \
+    nodemodel.cpp \
+    edgemodel.cpp \
+    colorlisteditor.cpp
 
-HEADERS  += mainwindow.h
+HEADERS  += mainwindow.h \
+    graph.h \
+    node.h \
+    edge.h \
+    defines.h \
+    nodemodel.h \
+    edgemodel.h \
+    colorlisteditor.h
 
 FORMS    += mainwindow.ui
+
+
+
+
+
+
+
+
+
+
+
index 49d64fce7cedf4ed8c5e0124cfe43e90c23c6ab6..9631debb0692d30d742923157e443e2101e8383a 100644 (file)
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
 
+#include <QItemEditorFactory>
+#include <QFile>
+#include "colorlisteditor.h"
+
+#include "graph.h"
+#include "node.h"
+#include "edge.h"
+
+#include <QDebug>
+
 MainWindow::MainWindow(QWidget *parent) :
     QMainWindow(parent),
     ui(new Ui::MainWindow)
 {
     ui->setupUi(this);
+
+       modes = new QActionGroup(this);
+       modes->addAction(ui->actionEditMode);
+       modes->addAction(ui->actionAddNodeMode);
+       modes->addAction(ui->actionAddEdgeMode);
+       modes->addAction(ui->actionRemoveMode);
+       ui->actionEditMode->setChecked(true);
+       ui->modeToolBar->addActions(modes->actions());
+
+       QItemEditorCreatorBase *colorListCreator = new QStandardItemEditorCreator<ColorListEditor>();
+//     QItemEditorFactory::defaultFactory()->registerEditor(QVariant::Color, colorListCreator);
+
+       graph = new Graph(this);
+
+       connect(modes, SIGNAL(triggered(QAction*)), this, SLOT(modeChanged(QAction*)));
+
+       Node *n1, *n2;
+       Edge *e;
+       n1 = graph->addNode();
+       n1->setColor(QColor(255,0,0));
+       n2 = graph->addNode();
+       n2->setPos(100, 100);
+       n2->setColor(QColor(0,255,0));
+
+       e = graph->addEdge(n1, n2);
+       e->setColor(QColor(0,0,255));
+
+       ui->graphView->setScene(graph);
+       ui->nodeView->setModel(graph->nodeModel());
+       ui->edgeView->setModel(graph->edgeModel());
 }
 
 MainWindow::~MainWindow()
 {
     delete ui;
 }
+
+void MainWindow::modeChanged(QAction *action)
+{
+       if (action == ui->actionAddNodeMode)
+               graph->setMode(Graph::AddNodeMode);
+       else if (action == ui->actionAddEdgeMode)
+               graph->setMode(Graph::AddEdgeMode);
+       else if (action == ui->actionRemoveMode)
+               graph->setMode(Graph::RemoveNode);
+       else
+               graph->setMode(Graph::EditMode);
+}
+
+void MainWindow::on_actionSave_triggered()
+{
+       QFile f("out.txt");
+       if (!f.open(QIODevice::WriteOnly))
+       {
+               qDebug() << "Cannot open file";
+               return;
+       }
+       graph->save(&f);
+}
+
+void MainWindow::on_actionOpen_triggered()
+{
+       QFile f("out.txt");
+       if (!f.open(QIODevice::ReadOnly))
+       {
+               qDebug() << "Cannot open file";
+               return;
+       }
+       graph->load(&f);
+}
+
+void MainWindow::on_actionCompleteCurrentGraph_triggered()
+{
+       graph->complete();
+}
+
+void MainWindow::on_actionGenerateGraph_triggered()
+{
+       graph->clear();
+
+       static const int N = 5;
+
+       for (int i = 0; i < N; ++i)
+       {
+               for (int j = 0; j < N; ++j)
+               {
+                       Node *n = graph->addNode(QPointF(j * 100, i * 100));
+                       if (j != 0)
+                       {
+                               Node *o = graph->nodes()[graph->nodes().count() - 2];
+                               graph->addEdge(o, n);
+                               graph->addEdge(n, o);
+                       }
+                       if (i != 0)
+                       {
+                               Node *o = graph->nodes()[graph->nodes().count() - N - 1];
+                               graph->addEdge(o, n);
+                               graph->addEdge(n, o);
+                       }
+               }
+       }
+}
+
+void MainWindow::on_actionClearAll_triggered()
+{
+       graph->clear();
+}
index 112fda1c455b3bb60a114acc90d87b3320a592ff..a790cf8c56d24cc7f9adfcba0f01ec7788b82a15 100644 (file)
@@ -7,6 +7,9 @@ namespace Ui {
 class MainWindow;
 }
 
+class Graph;
+class QActionGroup;
+
 class MainWindow : public QMainWindow
 {
     Q_OBJECT
@@ -15,8 +18,21 @@ public:
     explicit MainWindow(QWidget *parent = 0);
     ~MainWindow();
     
+private slots:
+       void modeChanged(QAction *action);
+       void on_actionSave_triggered();
+       void on_actionOpen_triggered();
+
+       void on_actionCompleteCurrentGraph_triggered();
+       void on_actionGenerateGraph_triggered();
+       void on_actionClearAll_triggered();
+
 private:
     Ui::MainWindow *ui;
+
+    Graph *graph;
+
+       QActionGroup *modes;
 };
 
 #endif // MAINWINDOW_H
index 6050363fa71ed2da04105077f9fef06150d05ee2..406d8b997d4ea761e49b7f5ae4e20860a9f920fc 100644 (file)
+<?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
  <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow" >
-  <property name="geometry" >
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>400</width>
-    <height>300</height>
+    <width>781</width>
+    <height>598</height>
    </rect>
   </property>
-  <property name="windowTitle" >
-   <string>MainWindow</string>
+  <property name="windowTitle">
+   <string>PMC</string>
   </property>
-  <widget class="QMenuBar" name="menuBar" />
-  <widget class="QToolBar" name="mainToolBar" />
-  <widget class="QWidget" name="centralWidget" />
-  <widget class="QStatusBar" name="statusBar" />
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <property name="margin">
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="QGraphicsView" name="graphView">
+      <property name="frameShape">
+       <enum>QFrame::NoFrame</enum>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>781</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuFile">
+    <property name="title">
+     <string>File</string>
+    </property>
+    <addaction name="actionOpen"/>
+    <addaction name="actionSave"/>
+    <addaction name="separator"/>
+    <addaction name="actionQuit"/>
+   </widget>
+   <widget class="QMenu" name="menuGraph">
+    <property name="title">
+     <string>Graph</string>
+    </property>
+    <addaction name="actionCompleteCurrentGraph"/>
+    <addaction name="separator"/>
+    <addaction name="actionGenerateGraph"/>
+    <addaction name="separator"/>
+    <addaction name="actionClearAll"/>
+   </widget>
+   <addaction name="menuFile"/>
+   <addaction name="menuGraph"/>
+  </widget>
+  <widget class="QToolBar" name="modeToolBar">
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+  <widget class="QDockWidget" name="nodeWidget">
+   <property name="windowTitle">
+    <string>Nodes</string>
+   </property>
+   <attribute name="dockWidgetArea">
+    <number>2</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents">
+    <layout class="QVBoxLayout" name="verticalLayout_2">
+     <property name="margin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QTableView" name="nodeView"/>
+     </item>
+    </layout>
+   </widget>
+  </widget>
+  <widget class="QDockWidget" name="edgeWidget">
+   <property name="windowTitle">
+    <string>Edges</string>
+   </property>
+   <attribute name="dockWidgetArea">
+    <number>2</number>
+   </attribute>
+   <widget class="QWidget" name="dockWidgetContents_2">
+    <layout class="QVBoxLayout" name="verticalLayout_3">
+     <property name="margin">
+      <number>0</number>
+     </property>
+     <item>
+      <widget class="QTableView" name="edgeView"/>
+     </item>
+    </layout>
+   </widget>
+  </widget>
+  <action name="actionEditMode">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Edit Mode</string>
+   </property>
+   <property name="toolTip">
+    <string>Edit Mode</string>
+   </property>
+  </action>
+  <action name="actionAddNodeMode">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Add Node Mode</string>
+   </property>
+   <property name="toolTip">
+    <string>Add Node Mode</string>
+   </property>
+  </action>
+  <action name="actionAddEdgeMode">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Add Edge Mode</string>
+   </property>
+   <property name="toolTip">
+    <string>Add Edge Mode</string>
+   </property>
+  </action>
+  <action name="actionRemoveMode">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Remove Mode</string>
+   </property>
+   <property name="toolTip">
+    <string>Remove Mode</string>
+   </property>
+  </action>
+  <action name="actionOpen">
+   <property name="text">
+    <string>Open...</string>
+   </property>
+  </action>
+  <action name="actionSave">
+   <property name="text">
+    <string>Save...</string>
+   </property>
+  </action>
+  <action name="actionQuit">
+   <property name="text">
+    <string>Quit</string>
+   </property>
+  </action>
+  <action name="actionClearAll">
+   <property name="text">
+    <string>Clear all</string>
+   </property>
+  </action>
+  <action name="actionGenerateGraph">
+   <property name="text">
+    <string>Generate Graph</string>
+   </property>
+  </action>
+  <action name="actionCompleteCurrentGraph">
+   <property name="text">
+    <string>Complete Current Graph</string>
+   </property>
+  </action>
  </widget>
- <layoutDefault spacing="6" margin="11" />
- <pixmapfunction></pixmapfunction>
+ <layoutdefault spacing="6" margin="11"/>
  <resources/>
  <connections/>
 </ui>
diff --git a/node.cpp b/node.cpp
new file mode 100644 (file)
index 0000000..ab17af3
--- /dev/null
+++ b/node.cpp
@@ -0,0 +1,64 @@
+#include "node.h"
+
+#include <QPainter>
+
+#include "edge.h"
+#include "graph.h"
+
+Node::Node(QGraphicsObject *parent) : QGraphicsObject(parent)
+{
+       setFlag(QGraphicsItem::ItemIsMovable);
+}
+
+void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+       Q_UNUSED(option);
+       Q_UNUSED(widget);
+
+       QBrush b(m_color);
+       painter->setBrush(b);
+       painter->drawEllipse(QRectF(-size/2, -size/2, size, size));
+       painter->drawText(QPointF(size/2, size), m_label);
+}
+
+QRectF Node::boundingRect() const
+{
+       return QRectF(-size/2, -size/2, size + m_label.length() * 9, size * 1.7);
+}
+
+QPainterPath Node::shape() const
+{
+       QPainterPath p;
+       p.addEllipse(QRectF(-size/2, -size/2, size, size));
+       return p;
+}
+
+void Node::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+       QGraphicsObject::mouseMoveEvent(event);
+       scene()->update();
+}
+
+const qreal Node::size = 20;
+
+QDataStream &operator<<(QDataStream &s, const Node &node)
+{
+       s << node.label();
+       s << node.color();
+       s << node.pos();
+       return s;
+}
+
+QDataStream &operator>>(QDataStream &s, Node &node)
+{
+       QString label;
+       QColor color;
+       QPointF pos;
+       s >> label;
+       s >> color;
+       s >> pos;
+       node.setLabel(label);
+       node.setColor(color);
+       node.setPos(pos);
+       return s;
+}
diff --git a/node.h b/node.h
new file mode 100644 (file)
index 0000000..7b1be17
--- /dev/null
+++ b/node.h
@@ -0,0 +1,79 @@
+#ifndef NODE_H
+#define NODE_H
+
+#include <QGraphicsObject>
+
+#include "graph.h"
+
+#include <QDataStream>
+
+class Node : public QGraphicsObject
+{
+       friend Graph;
+       Q_OBJECT
+       Q_PROPERTY(QString label READ label WRITE setLabel)
+       Q_PROPERTY(QColor color READ color WRITE setColor)
+       Q_PROPERTY(EdgeList outgoingEdges READ outgoingEdges)
+       Q_PROPERTY(EdgeList incomingEdges READ incomingEdges)
+
+public:
+       enum { Type = UserType + 1};
+
+       Node(QGraphicsObject *parent = 0);
+
+       int type() const
+       {
+               return Type;
+       }
+
+       QString label() const
+       {
+               return m_label;
+       }
+
+       QColor color() const
+       {
+               return m_color;
+       }
+
+       EdgeList outgoingEdges() const
+       {
+               return m_outgoingEdges;
+       }
+
+       EdgeList incomingEdges() const
+       {
+               return m_incomingEdges;
+       }
+
+       void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+       QRectF boundingRect() const;
+       QPainterPath shape() const;
+
+       void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+
+public slots:
+       void setLabel(QString label)
+       {
+               m_label = label;
+       }
+
+       void setColor(QColor color)
+       {
+               m_color = color;
+       }
+
+private:
+       QString m_label;
+       QColor m_color;
+
+       EdgeList m_outgoingEdges;
+       EdgeList m_incomingEdges;
+
+       static const qreal size;
+};
+
+QDataStream &operator<<(QDataStream &s, const Node &node);
+QDataStream &operator>>(QDataStream &s, Node &node);
+
+#endif // NODE_H
diff --git a/nodemodel.cpp b/nodemodel.cpp
new file mode 100644 (file)
index 0000000..b2a2596
--- /dev/null
@@ -0,0 +1,112 @@
+#include "nodemodel.h"
+
+#include <QColor>
+
+#include "node.h"
+
+#include <QDebug>
+
+NodeModel::NodeModel(Graph *graph, QObject *parent) :
+       QAbstractTableModel(parent), g(graph)
+{
+}
+
+Qt::ItemFlags NodeModel::flags(const QModelIndex &index) const
+{
+       return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
+}
+
+QVariant NodeModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+       if (role != Qt::DisplayRole)
+               return QVariant();
+       if (orientation == Qt::Vertical)
+               return section + 1;
+
+       switch (section)
+       {
+               case 0:
+                       return "Label";
+               case 1:
+                       return "Color";
+               case 2:
+                       return "X";
+               case 3:
+                       return "Y";
+               default:
+               break;
+       }
+       return QVariant();
+}
+
+int NodeModel::rowCount(const QModelIndex &) const
+{
+       return g->m_nodeList.count();
+}
+
+int NodeModel::columnCount(const QModelIndex &) const
+{
+       return 4;
+}
+
+QVariant NodeModel::data(const QModelIndex &index, int role) const
+{
+       Node *n = g->m_nodeList[index.row()];
+       if (role == Qt::DecorationRole && index.column() == 1)
+               return n->color();
+
+       if (role == Qt::DisplayRole || role == Qt::EditRole)
+               switch (index.column())
+               {
+                       case 0:
+                               return n->label();
+                       case 1:
+                               return n->color();
+                       case 2:
+                               return n->x();
+                       case 3:
+                               return n->y();
+                       default:
+                       break;
+               }
+       return QVariant();
+}
+
+bool NodeModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+       if (role != Qt::DisplayRole && role != Qt::EditRole)
+               return false;
+
+       Node *n = g->m_nodeList[index.row()];
+       bool ok;
+       qreal r;
+       switch (index.column())
+       {
+               case 0:
+                       n->setLabel(value.toString());
+                       n->update();
+                       g->labelChanged();
+                       return true;
+               case 1:
+                       n->setColor(value.value<QColor>());
+                       n->update();
+                       return true;
+               case 2:
+                       r = value.toReal(&ok);
+                       if (!ok)
+                               return false;
+                       n->setX(r);
+                       n->scene()->update();
+                       return true;
+               case 3:
+                       r = value.toReal(&ok);
+                       if (!ok)
+                               return false;
+                       n->setY(r);
+                       n->scene()->update();
+                       return true;
+               default:
+               break;
+       }
+       return false;
+}
diff --git a/nodemodel.h b/nodemodel.h
new file mode 100644 (file)
index 0000000..1c6f20d
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef NODEMODEL_H
+#define NODEMODEL_H
+
+#include <QAbstractTableModel>
+
+#include "graph.h"
+
+class NodeModel : public QAbstractTableModel
+{
+       friend Graph;
+       Q_OBJECT
+public:
+       explicit NodeModel(Graph *graph, QObject *parent = 0);
+
+       Qt::ItemFlags flags(const QModelIndex &index) const;
+       QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+       int rowCount(const QModelIndex &parent = QModelIndex()) const;
+       int columnCount(const QModelIndex &parent = QModelIndex()) const;
+       QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+       bool setData(const QModelIndex &index, const QVariant &value, int role);
+       
+signals:
+       
+public slots:
+
+private:
+       Graph *g;
+};
+#else
+class NodeModel;
+#endif // NODEMODEL_H