Files
create/src/Gui/DAGView/DAGModel.h
blobfish 3e65723472 Core: Gui: DAGView: skeleton implemented
Need to enable through parameter BaseApp/Preferences/DAGView
2016-04-12 18:12:10 +02:00

355 lines
13 KiB
C++

/***************************************************************************
* Copyright (c) 2015 Thomas Anderson <blobfish[at]gmx.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef DAGMODEL_H
#define DAGMODEL_H
#include <memory>
#include <vector>
#include <boost/signal.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/reverse_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QBrush>
class QGraphicsSceneHoverEvent;
namespace App{class DocumentObject;}
namespace Gui
{
class Document;
class ViewProviderDocumentObject;
class SelectionChanges;
namespace DAG
{
/*all right I give up! the parenting combined with the zvalues is fubar!
* you can't control any kind of layering between children of separate parents
*/
class ViewEntryRectItem : public QGraphicsRectItem
{
public:
ViewEntryRectItem(QGraphicsItem* parent = 0);
void setBackgroundBrush(const QBrush &brushIn){backgroundBrush = brushIn;}
void setPreselectionBrush(const QBrush &brushIn){preSelectionBrush = brushIn;}
void setSelectionBrush(const QBrush &brushIn){selectionBrush = brushIn;}
void setBothBrush(const QBrush &brushIn){bothBrush = brushIn;}
void preHighlightOn(){preSelected = true;}
void preHighlightOff(){preSelected = false;}
void selectionOn(){selected = true;}
void selectionOff(){selected = false;}
bool isSelected(){return selected;}
bool isPreSelected(){return preSelected;}
protected:
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
private:
QBrush backgroundBrush; //!< brush used for background. not used yet.
QBrush selectionBrush; //!< brush used when selected.
QBrush preSelectionBrush; //!< brush used when pre selected.
QBrush bothBrush; //!< brush for when both selected and preSelected.
//start with booleans, may expand to state.
bool selected;
bool preSelected;
};
enum class VisibilityState
{
None = 0, //<! not determined.
On, //<! shown
Off, //<! hidden
};
/*! @brief Graph vertex information
*
* My data stored for each vertex;
*/
struct VertexProperty
{
VertexProperty();
std::shared_ptr<ViewEntryRectItem> rectangle; //!< background
std::shared_ptr<QGraphicsEllipseItem> point; //!< point
std::shared_ptr<QGraphicsPixmapItem> icon; //!< icon
std::shared_ptr<QGraphicsTextItem> text; //!< text
int row; //!< row for this entry.
int column; //!< column number containing the point.
int colorIndex; //!< index in forground brushes
VisibilityState lastVisibleState; //!< visibility test.
QPixmap pixmapEnabled;
QPixmap pixmapDisabled;
};
/*! @brief boost data for each vertex.
*
* needed to create an internal index for vertex. needed for listS.
* color is needed by some algorithms */
typedef boost::property
<
boost::vertex_index_t, std::size_t,
boost::property <boost::vertex_color_t, boost::default_color_type, VertexProperty>
> vertex_prop;
/*! @brief Graph edge information
*
* My data stored for each edge;
*/
struct EdgeProperty
{
//! Feature relation meta data.
enum class BranchTag
{
None = 0, //!< not defined.
Create, //!< create a new branch.
Continue, //!< continue a branch.
Terminate //!< terminate a branch.
};
BranchTag relation;
std::shared_ptr <QGraphicsPathItem> connector; //!< line representing link between nodes.
};
/*! @brief needed to create an internal index for graph edges. needed for setS.*/
typedef boost::property<boost::edge_index_t, std::size_t, EdgeProperty> edge_prop;
typedef boost::adjacency_list<boost::setS, boost::listS, boost::bidirectionalS, vertex_prop, edge_prop> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef boost::graph_traits<Graph>::edge_descriptor Edge;
typedef boost::graph_traits<Graph>::vertex_iterator VertexIterator;
typedef boost::graph_traits<Graph>::edge_iterator EdgeIterator;
typedef boost::graph_traits<Graph>::in_edge_iterator InEdgeIterator;
typedef boost::graph_traits<Graph>::out_edge_iterator OutEdgeIterator;
typedef boost::graph_traits<Graph>::adjacency_iterator VertexAdjacencyIterator;
typedef boost::reverse_graph<Graph, Graph&> GraphReversed;
typedef std::vector<Vertex> Path; //!< a path or any array of vertices
template <class GraphEW>
class Edge_writer {
public:
Edge_writer(const GraphEW &graphEWIn) : graphEW(graphEWIn) {}
template <class EdgeW>
void operator()(std::ostream& out, const EdgeW& edgeW) const
{
out << "[label=\"";
out << "edge";
out << "\"]";
}
private:
const GraphEW &graphEW;
};
template <class GraphVW>
class Vertex_writer {
public:
Vertex_writer(const GraphVW &graphVWIn) : graphVW(graphVWIn) {}
template <class VertexW>
void operator()(std::ostream& out, const VertexW& vertexW) const
{
out << "[label=\"";
out << graphVW[vertexW].text->toPlainText().toAscii().data();
out << "\"]";
}
private:
const GraphVW &graphVW;
};
template <class GraphIn>
void outputGraphviz(const GraphIn &graphIn, const std::string &filePath)
{
std::ofstream file(filePath.c_str());
boost::write_graphviz(file, graphIn, Vertex_writer<GraphIn>(graphIn),
Edge_writer<GraphIn>(graphIn));
}
//! get all the leaves of the templated graph. Not used right now.
template <class GraphIn>
class RakeLeaves
{
typedef boost::graph_traits<Graph>::vertex_descriptor GraphInVertex;
typedef std::vector<GraphInVertex> GraphInVertices;
public:
RakeLeaves(const GraphIn &graphIn) : graph(graphIn) {}
GraphInVertices operator()() const
{
GraphInVertices out;
BGL_FORALL_VERTICES_T(currentVertex, graph, GraphIn)
{
if (boost::out_degree(currentVertex, graph) == 0)
out.push_back(currentVertex);
}
return out;
}
private:
const GraphIn &graph;
};
//! get all the roots of the templated graph. Not used right now.
template <class GraphIn>
class DigRoots
{
typedef boost::graph_traits<Graph>::vertex_descriptor GraphInVertex;
typedef std::vector<GraphInVertex> GraphInVertices;
public:
DigRoots(const GraphIn &graphIn) : graph(graphIn) {}
GraphInVertices operator()() const
{
GraphInVertices out;
BGL_FORALL_VERTICES_T(currentVertex, graph, GraphIn)
{
if (boost::in_degree(currentVertex, graph) == 0)
out.push_back(currentVertex);
}
return out;
}
private:
const GraphIn &graph;
};
/*! Multi_index record. */
struct GraphLinkRecord
{
const App::DocumentObject *DObject; //!< document object
const Gui::ViewProviderDocumentObject *VPDObject; //!< view provider
const ViewEntryRectItem *rectItem; //!< qgraphics item.
std::string uniqueName; //!< name for document object.
Vertex vertex; //!< vertex in graph.
//@{
//! used as tags.
struct ByDObject{};
struct ByVPDObject{};
struct ByRectItem{};
struct ByUniqueName{};
struct ByVertex{};
//@}
};
namespace BMI = boost::multi_index;
typedef boost::multi_index_container
<
GraphLinkRecord,
BMI::indexed_by
<
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByDObject>,
BMI::member<GraphLinkRecord, const App::DocumentObject*, &GraphLinkRecord::DObject>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByVPDObject>,
BMI::member<GraphLinkRecord, const Gui::ViewProviderDocumentObject*, &GraphLinkRecord::VPDObject>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByRectItem>,
BMI::member<GraphLinkRecord, const ViewEntryRectItem*, &GraphLinkRecord::rectItem>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByUniqueName>,
BMI::member<GraphLinkRecord, std::string, &GraphLinkRecord::uniqueName>
>,
BMI::ordered_unique
<
BMI::tag<GraphLinkRecord::ByVertex>,
BMI::member<GraphLinkRecord, Vertex, &GraphLinkRecord::vertex>
>
>
> GraphLinkContainer;
class Model : public QGraphicsScene
{
Q_OBJECT
public:
Model(QObject *parentIn, const Gui::Document &documentIn);
virtual ~Model() override;
void awake(); //!< hooked up to event dispatcher for update when idle.
void selectionChanged(const SelectionChanges& msg);
protected:
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
virtual void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
private Q_SLOTS:
void updateSlot();
private:
Model(){}
//documentObject slots.
typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection;
Connection connectNewObject;
Connection connectDelObject;
Connection connectChgObject;
Connection connectRenObject;
Connection connectActObject;
Connection connectEdtObject;
Connection connectResObject;
Connection connectHltObject;
Connection connectExpObject;
void slotNewObject(const Gui::ViewProviderDocumentObject &VPDObjectIn);
void slotDeleteObject(const Gui::ViewProviderDocumentObject &VPDObjectIn);
void slotChangeObject(const Gui::ViewProviderDocumentObject &VPDObjectIn, const App::Property& propertyIn);
std::shared_ptr<GraphLinkContainer> graphLink;
std::shared_ptr<Graph> theGraph;
bool graphDirty;
const GraphLinkRecord& findRecord(Vertex vertexIn);
const GraphLinkRecord& findRecord(const App::DocumentObject* dObjectIn);
const GraphLinkRecord& findRecord(const Gui::ViewProviderDocumentObject* VPDObjectIn);
const GraphLinkRecord& findRecord(const ViewEntryRectItem* rectIn);
const GraphLinkRecord& findRecord(const std::string &stringIn);
void eraseRecord(const Gui::ViewProviderDocumentObject* VPDObjectIn);
void indexVerticesEdges();
void removeAllItems();
void updateVisible();
ViewEntryRectItem* getRectFromPosition(const QPointF &position); //!< can be nullptr
//! @name View Constants for spacing
//@{
float fontHeight; //!< height of the current qApp default font.
float verticalSpacing; //!< pixels between top and bottom of text to background rectangle.
float rowHeight; //!< height of background rectangle.
float iconSize; //!< size of icon to match font.
float pointSize; //!< size of the connection point.
float pointSpacing; //!< spacing between pofloat columns.
float pointToIcon; //!< spacing from last column points to icon.
float rowPadding; //!< spaces added to rectangle bacground width ends.
std::vector<QBrush> backgroundBrushes; //!< brushes to paint background rectangles.
std::vector<QBrush> forgroundBrushes; //!< brushes to paint points, connectors, text.
void setupViewConstants();
//@}
ViewEntryRectItem *currentPrehighlight;
};
}
}
#endif // DAGMODEL_H