--- /dev/null
+#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);
+ }
+}
--- /dev/null
+#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
--- /dev/null
+#ifndef DEFINES_H
+#define DEFINES_H
+
+#include <QList>
+
+class Node;
+class Edge;
+
+typedef QList<Node *> NodeList;
+typedef QList<Edge *> EdgeList;
+
+#endif // DEFINES_H
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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();
+}
--- /dev/null
+#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
--- /dev/null
+#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));
+}
--- /dev/null
+#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
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
+
+
+
+
+
+
+
+
+
+
+
#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();
+}
class MainWindow;
}
+class Graph;
+class QActionGroup;
+
class MainWindow : public QMainWindow
{
Q_OBJECT
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
+<?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>
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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