diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 6c288ffa7..5df779e1a 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -264,6 +264,7 @@ set(Gui_MOC_HDRS TaskView/TaskView.h DAGView/DAGView.h DAGView/DAGModel.h + DAGView/DAGRectItem.h ) #qt4_wrap_cpp(Gui_MOC_SRCS ${Gui_MOC_HDRS}) fc_wrap_cpp(Gui_MOC_SRCS ${Gui_MOC_HDRS}) @@ -561,6 +562,9 @@ SET(Dock_Windows_CPP_SRCS ProjectView.cpp DAGView/DAGView.cpp DAGView/DAGModel.cpp + DAGView/DAGRectItem.cpp + DAGView/DAGModelGraph.cpp + DAGView/DAGFilter.cpp ) SET(Dock_Windows_HPP_SRCS CombiView.h @@ -575,6 +579,9 @@ SET(Dock_Windows_HPP_SRCS ProjectView.h DAGView/DAGView.h DAGView/DAGModel.h + DAGView/DAGRectItem.h + DAGView/DAGModelGraph.h + DAGView/DAGFilter.h ) SET(Dock_Windows_SRCS ${Dock_Windows_CPP_SRCS} diff --git a/src/Gui/DAGView/DAGFilter.cpp b/src/Gui/DAGView/DAGFilter.cpp new file mode 100644 index 000000000..dc9857f50 --- /dev/null +++ b/src/Gui/DAGView/DAGFilter.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include +#include + + +#include "DAGFilter.h" + +using namespace Gui; +using namespace DAG; + +FilterBase::FilterBase() : name(QString::fromAscii("empty name")), enabled(true), type(Type::Exclusion) +{ + +} + +FilterOrigin::FilterOrigin() : FilterBase() +{ + name = QObject::tr("Origin"); +} + +bool FilterOrigin::goFilter(const Vertex &vertexIn, const Graph &graphIn, const GraphLinkContainer &linkIn) const +{ + Base::Type originType = Base::Type::fromName("App::Origin"); + assert (originType != Base::Type::badType()); + //if child of origin hide. + InEdgeIterator it, itEnd; + for (boost::tie(it, itEnd) = boost::in_edges(vertexIn, graphIn); it != itEnd; ++it) + { + Vertex source = boost::source(*it, graphIn); + const GraphLinkRecord &sourceRecord = findRecord(source, linkIn); + if + ( + (sourceRecord.DObject->getTypeId() == originType) && + (boost::in_degree(vertexIn, graphIn) == 1) + ) + return true; + } + return false; +} + +FilterTyped::FilterTyped(const std::string &typeIn) : FilterBase(), type(typeIn) +{ + name = QString::fromStdString(typeIn); +} + +bool FilterTyped::goFilter(const Gui::DAG::Vertex& vertexIn, const Graph& graphIn, const GraphLinkContainer& linkIn) const +{ + if (type.empty()) + return false; + Base::Type theType = Base::Type::fromName(type.c_str()); + if (theType == Base::Type::badType()) + return false; + + const GraphLinkRecord &sourceRecord = findRecord(vertexIn, linkIn); + if (sourceRecord.DObject->getTypeId() == theType) + return true; + + return false; +} + + diff --git a/src/Gui/DAGView/DAGFilter.h b/src/Gui/DAGView/DAGFilter.h new file mode 100644 index 000000000..0ceb90aae --- /dev/null +++ b/src/Gui/DAGView/DAGFilter.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 DAGFILTER_H +#define DAGFILTER_H + +#include + +#include "DAGModelGraph.h" + +namespace Gui +{ + class ViewProviderDocumentObject; + namespace DAG + { + class FilterBase + { + public: + enum class Type + { + None = 0, //!< no type designation. shouldn't be used. + Inclusion, + Exclusion + }; + FilterBase(); + //! @return is whether we have a match or not. + virtual bool goFilter(const Vertex &vertexIn, const Graph &graphIn, const GraphLinkContainer &linkIn) const = 0; + QString name; + bool enabled; + Type type; + }; + + /*! Hide all children of app::origin that are not + * used by subsequent features + */ + class FilterOrigin : public FilterBase + { + public: + FilterOrigin(); + virtual bool goFilter(const Vertex &vertexIn, const Graph &graphIn, const GraphLinkContainer &linkIn) const override; + }; + + /*! Hide nodes of type*/ + class FilterTyped : public FilterBase + { + public: + explicit FilterTyped(const std::string &typeIn); + std::string type; + virtual bool goFilter(const Vertex &vertexIn, const Graph &graphIn, const GraphLinkContainer &linkIn) const override; + }; + } +} + +#endif // DAGFILTER_H diff --git a/src/Gui/DAGView/DAGModel.cpp b/src/Gui/DAGView/DAGModel.cpp index 0ceb98441..73366047d 100644 --- a/src/Gui/DAGView/DAGModel.cpp +++ b/src/Gui/DAGView/DAGModel.cpp @@ -89,14 +89,6 @@ void LineEdit::keyPressEvent(QKeyEvent *eventIn) QLineEdit::keyPressEvent(eventIn); } - -ViewEntryRectItem::ViewEntryRectItem(QGraphicsItem* parent) : QGraphicsRectItem(parent) -{ - selected = false; - preSelected = false; - editing = false; -} - //I dont think I should have to call invalidate //and definitely not on the whole scene! //if we have performance problems, this will definitely @@ -107,112 +99,6 @@ ViewEntryRectItem::ViewEntryRectItem(QGraphicsItem* parent) : QGraphicsRectItem( // update(boundingRect()); //note: I haven't tried this again since I turned BSP off. -void ViewEntryRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) -{ - //TODO figure out how to mimic painting of itemviews. QStyle, QStyledItemDelegate. - - QBrush brush = backgroundBrush; - if (selected) - brush = selectionBrush; - if (preSelected) - brush = preSelectionBrush; - if (selected && preSelected) - brush = bothBrush; - if (editing) - brush = editBrush; - - //heights are negative. - float radius = std::min(this->rect().width(), std::fabs(this->rect().height())) * 0.1; - painter->setBrush(brush); - painter->setPen(this->pen()); //should be Qt::NoPen. - painter->drawRoundedRect(this->rect(), radius, radius); - -// QGraphicsRectItem::paint(painter, option, widget); -} - -VertexProperty::VertexProperty() : - rectangle(new ViewEntryRectItem()), - point(new QGraphicsEllipseItem()), - visibleIcon(new QGraphicsPixmapItem()), - stateIcon(new QGraphicsPixmapItem()), - icon(new QGraphicsPixmapItem()), - text(new QGraphicsTextItem()), - row(0), - column(0), - lastVisibleState(VisibilityState::None), - dagVisible(true) -{ - //All flags are disabled by default. - this->rectangle->setFlags(QGraphicsItem::ItemIsSelectable); - - //set z values. - this->rectangle->setZValue(-1000.0); - this->point->setZValue(1000.0); - this->visibleIcon->setZValue(0.0); - this->stateIcon->setZValue(0.0); - this->icon->setZValue(0.0); - this->text->setZValue(0.0); -} - -EdgeProperty::EdgeProperty() : relation(BranchTag::None) -{ - -} - -const GraphLinkRecord& Model::findRecord(Vertex vertexIn) -{ - typedef GraphLinkContainer::index::type List; - const List &list = graphLink->get(); - List::const_iterator it = list.find(vertexIn); - assert(it != list.end()); - return *it; -} - -const GraphLinkRecord& Model::findRecord(const App::DocumentObject* dObjectIn) -{ - typedef GraphLinkContainer::index::type List; - const List &list = graphLink->get(); - List::const_iterator it = list.find(dObjectIn); - assert(it != list.end()); - return *it; -} - -const GraphLinkRecord& Model::findRecord(const ViewProviderDocumentObject* VPDObjectIn) -{ - typedef GraphLinkContainer::index::type List; - const List &list = graphLink->get(); - List::const_iterator it = list.find(VPDObjectIn); - assert(it != list.end()); - return *it; -} - -const GraphLinkRecord& Model::findRecord(const ViewEntryRectItem* rectIn) -{ - typedef GraphLinkContainer::index::type List; - const List &list = graphLink->get(); - List::const_iterator it = list.find(rectIn); - assert(it != list.end()); - return *it; -} - -const GraphLinkRecord& Model::findRecord(const std::string &stringIn) -{ - typedef GraphLinkContainer::index::type List; - const List &list = graphLink->get(); - List::const_iterator it = list.find(stringIn); - assert(it != list.end()); - return *it; -} - -void Model::eraseRecord(const ViewProviderDocumentObject* VPDObjectIn) -{ - typedef GraphLinkContainer::index::type List; - const List &list = graphLink->get(); - List::iterator it = list.find(VPDObjectIn); - assert(it != list.end()); - graphLink->get().erase(it); -} - Model::Model(QObject *parentIn, const Gui::Document &documentIn) : QGraphicsScene(parentIn) { //turned off BSP as it was giving inconsistent discovery of items @@ -222,6 +108,7 @@ Model::Model(QObject *parentIn, const Gui::Document &documentIn) : QGraphicsScen theGraph = std::shared_ptr(new Graph()); graphLink = std::shared_ptr(new GraphLinkContainer()); setupViewConstants(); + setupFilters(); graphDirty = false; currentPrehighlight = nullptr; @@ -275,12 +162,38 @@ Model::~Model() removeAllItems(); } +void Model::setupFilters() +{ +// filters.push_back(std::shared_ptr(new FilterOrigin())); +// filters.push_back(std::shared_ptr(new FilterTyped("PartDesign::Body"))); +// filters.push_back(std::shared_ptr(new FilterTyped("App::Part"))); +} + void Model::setupViewConstants() { - QFontMetrics fontMetric(qApp->font()); + ParameterGrp::handle group = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DAGView"); + + //get font point size. + int fontPointSize = group->GetInt("FontPointSize", 0); + group->SetInt("FontPointSize", fontPointSize); //ensure entry exists. + if (fontPointSize != 0) + { + QFont tempFont(this->font()); + tempFont.setPointSize(fontPointSize); + this->setFont(tempFont); + } + + //get direction + direction = group->GetFloat("Direction", 1.0); + if (direction != -1.0 && direction != 1.0) + direction = 1.0; + group->SetFloat("Direction", direction); //ensure entry exists. + + QFontMetrics fontMetric(this->font()); fontHeight = fontMetric.height(); verticalSpacing = 1.0; - rowHeight = (fontHeight + 2.0 * verticalSpacing) * -1.0; //pixel space top and bottom. + rowHeight = (fontHeight + 2.0 * verticalSpacing) * direction; //pixel space top and bottom. iconSize = fontHeight; pointSize = fontHeight / 2.0; pointSpacing = pointSize; @@ -288,7 +201,7 @@ void Model::setupViewConstants() iconToIcon = iconSize * 0.25; iconToText = iconSize / 2.0; rowPadding = fontHeight; - backgroundBrushes = {qApp->palette().base(), qApp->palette().alternateBase()}; + backgroundBrushes = {this->palette().base(), this->palette().alternateBase()}; forgroundBrushes = { QBrush(Qt::red), @@ -337,13 +250,14 @@ void Model::slotNewObject(const ViewProviderDocumentObject &VPDObjectIn) (*theGraph)[virginVertex].icon->setPixmap(VPDObjectIn.getIcon().pixmap(iconSize, iconSize)); (*theGraph)[virginVertex].stateIcon->setPixmap(passPixmap); + (*theGraph)[virginVertex].text->setFont(this->font()); graphDirty = true; } void Model::slotDeleteObject(const ViewProviderDocumentObject &VPDObjectIn) { - Vertex vertex = findRecord(&VPDObjectIn).vertex; + Vertex vertex = findRecord(&VPDObjectIn, *graphLink).vertex; //remove items from scene. removeVertexItemsFromScene(vertex); @@ -360,7 +274,7 @@ void Model::slotDeleteObject(const ViewProviderDocumentObject &VPDObjectIn) boost::clear_vertex(vertex, *theGraph); boost::remove_vertex(vertex, *theGraph); - eraseRecord(&VPDObjectIn); + eraseRecord(&VPDObjectIn, *graphLink); graphDirty = true; } @@ -378,7 +292,7 @@ void Model::slotChangeObject(const ViewProviderDocumentObject &VPDObjectIn, cons //renaming of objects. if (std::string("Label") == name) { - const GraphLinkRecord &record = findRecord(&VPDObjectIn); + const GraphLinkRecord &record = findRecord(&VPDObjectIn, *graphLink); auto *text = (*theGraph)[record.vertex].text.get(); text->setPlainText(QString::fromUtf8(record.DObject->Label.getValue())); } @@ -394,7 +308,7 @@ void Model::slotChangeObject(const ViewProviderDocumentObject &VPDObjectIn, cons if (linkTypes.find(propertyIn.getTypeId().getName()) != linkTypes.end()) { - const GraphLinkRecord &record = findRecord(&VPDObjectIn); + const GraphLinkRecord &record = findRecord(&VPDObjectIn, *graphLink); boost::clear_vertex(record.vertex, *theGraph); graphDirty = true; } @@ -402,14 +316,14 @@ void Model::slotChangeObject(const ViewProviderDocumentObject &VPDObjectIn, cons void Model::slotInEdit(const ViewProviderDocumentObject& VPDObjectIn) { - ViewEntryRectItem *rect = (*theGraph)[findRecord(&VPDObjectIn).vertex].rectangle.get(); + RectItem *rect = (*theGraph)[findRecord(&VPDObjectIn, *graphLink).vertex].rectangle.get(); rect->editingStart(); this->invalidate(); } void Model::slotResetEdit(const ViewProviderDocumentObject& VPDObjectIn) { - ViewEntryRectItem *rect = (*theGraph)[findRecord(&VPDObjectIn).vertex].rectangle.get(); + RectItem *rect = (*theGraph)[findRecord(&VPDObjectIn, *graphLink).vertex].rectangle.get(); rect->editingFinished(); this->invalidate(); } @@ -463,7 +377,7 @@ void Model::selectionChanged(const SelectionChanges& msg) { BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) { - ViewEntryRectItem *rect = (*theGraph)[currentVertex].rectangle.get(); + RectItem *rect = (*theGraph)[currentVertex].rectangle.get(); assert(rect); rect->selectionOff(); highlightConnectorOff(currentVertex); @@ -476,8 +390,8 @@ void Model::selectionChanged(const SelectionChanges& msg) assert(in); std::string name(in); assert(!name.empty()); - const GraphLinkRecord &record = findRecord(name); - ViewEntryRectItem *rect = (*theGraph)[record.vertex].rectangle.get(); + const GraphLinkRecord &record = findRecord(name, *graphLink); + RectItem *rect = (*theGraph)[record.vertex].rectangle.get(); assert(rect); return rect; }; @@ -486,18 +400,18 @@ void Model::selectionChanged(const SelectionChanges& msg) { if (msg.pObjectName) { - ViewEntryRectItem *rect = getRectangle(msg.pObjectName); + RectItem *rect = getRectangle(msg.pObjectName); rect->selectionOn(); - highlightConnectorOn(findRecord(std::string(msg.pObjectName)).vertex); + highlightConnectorOn(findRecord(std::string(msg.pObjectName), *graphLink).vertex); } } else if(msg.Type == SelectionChanges::RmvSelection) { if (msg.pObjectName) { - ViewEntryRectItem *rect = getRectangle(msg.pObjectName); + RectItem *rect = getRectangle(msg.pObjectName); rect->selectionOff(); - highlightConnectorOff(findRecord(std::string(msg.pObjectName)).vertex); + highlightConnectorOff(findRecord(std::string(msg.pObjectName), *graphLink).vertex); } } else if(msg.Type == SelectionChanges::SetSelection) @@ -508,9 +422,9 @@ void Model::selectionChanged(const SelectionChanges& msg) for (const auto &selection : selections) { assert(selection.FeatName); - ViewEntryRectItem *rect = getRectangle(selection.FeatName); + RectItem *rect = getRectangle(selection.FeatName); rect->selectionOn(); - highlightConnectorOn(findRecord(selection.FeatName).vertex); + highlightConnectorOn(findRecord(selection.FeatName, *graphLink).vertex); } } else if(msg.Type == SelectionChanges::ClrSelection) @@ -546,11 +460,11 @@ void Model::updateSlot() //we have to do this first and in isolation because everything is dependent on an up to date graph. BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) { - const App::DocumentObject *currentDObject = findRecord(currentVertex).DObject; + const App::DocumentObject *currentDObject = findRecord(currentVertex, *graphLink).DObject; std::vector otherDObjects = currentDObject->getOutList(); for (auto ¤tOtherDObject : otherDObjects) { - Vertex otherVertex = findRecord(currentOtherDObject).vertex; + Vertex otherVertex = findRecord(currentOtherDObject, *graphLink).vertex; bool result; Edge edge; boost::tie(edge, result) = boost::add_edge(currentVertex, otherVertex, *theGraph); @@ -562,31 +476,31 @@ void Model::updateSlot() } } - - - //TODO apply filters. - - //test filter. just to test layout engine with dagVisible. -// Base::Type originType = Base::Type::fromName("App::Origin"); -// assert (originType != Base::Type::badType()); -// BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) -// { -// //if child of origin hide. -// InEdgeIterator it, itEnd; -// for (boost::tie(it, itEnd) = boost::in_edges(currentVertex, *theGraph); it != itEnd; ++it) -// { -// Vertex source = boost::source(*it, *theGraph); -// const GraphLinkRecord &sourceRecord = findRecord(source); -// if -// ( -// (sourceRecord.DObject->getTypeId() == originType) && -// (boost::in_degree(currentVertex, *theGraph) == 1) -// ) -// (*theGraph)[currentVertex].dagVisible = false; -// } -// } - - + //apply filters. + BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) + { + (*theGraph)[currentVertex].dagVisible = true; //default to shown. + for (const auto ¤tFilter : filters) + { + if (!currentFilter->enabled || currentFilter->type != FilterBase::Type::Exclusion) + continue; + if (currentFilter->goFilter(currentVertex, *theGraph, *graphLink)) + (*theGraph)[currentVertex].dagVisible = false; + } + } + //inclusion takes precedence. Separate loop because filters might probe + //children and parents. So we want to ensure all exclusions are done + //before inclusions start. + BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) + { + for (const auto ¤tFilter : filters) + { + if (!currentFilter->enabled || currentFilter->type != FilterBase::Type::Inclusion) + continue; + if (currentFilter->goFilter(currentVertex, *theGraph, *graphLink)) + (*theGraph)[currentVertex].dagVisible = true; + } + } //sync scene items to graph vertex dagVisible. BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) @@ -644,6 +558,8 @@ void Model::updateSlot() boost::tie(it, itEnd) = boost::out_edges(currentVertex, *theGraph); for (;it != itEnd; ++it) { +// std::cout << std::endl << "name: " << findRecord(currentVertex, *graphLink).DObject->Label.getValue() << std::endl; + Vertex target = boost::target(*it, *theGraph); parentVertices.push_back(target); int currentParentIndex = (*theGraph)[target].topoSortIndex; @@ -653,18 +569,27 @@ void Model::updateSlot() Path::const_iterator end = sorted.begin() + (*theGraph)[currentVertex].topoSortIndex; // 1 before Path::const_iterator it; for (it = start; it != end; ++it) + { +// std::cout << " parent: " << findRecord(*it, *graphLink).DObject->Label.getValue() << std::endl; + columnMask |= (*theGraph)[*it].column; + } farthestParentIndex = currentParentIndex; } } -// std::cout << "mask for " << findRecord(currentVertex).DObject->Label.getValue() << " " << -// columnMask.to_string() << std::endl; + //have to create a smaller subset to get through std::cout. +// std::bitset<8> testSet; +// for (unsigned int index = 0; index < testSet.size(); ++index) +// testSet[index]= columnMask[index]; +// std::cout << "mask for " << findRecord(currentVertex, *graphLink).DObject->Label.getValue() << " " << +// testSet.to_string() << std::endl; //now we should have a mask representing the columns that are being used. //this is from the lowest parent, in the topo sort, to last entry. - //try to use the same column as one of the parents. - int destinationColumn = maxColumn + 1; //default to new column + + //try to use the same column as one of the parents.(*theGraph)[*it].column + int destinationColumn = 0; //default to first column for (const auto ¤tParent : parentVertices) { if (((*theGraph)[currentParent].column & columnMask).none()) @@ -676,6 +601,18 @@ void Model::updateSlot() break; } } + //if destination not valid look for the first open column. + if (columnMask.test(destinationColumn)) + { + for (std::size_t index = 0; index < columnMask.size(); ++index) + { + if (! columnMask.test(index)) + { + destinationColumn = index; + break; + } + } + } currentColumn = destinationColumn; } @@ -684,33 +621,37 @@ void Model::updateSlot() maxColumn = std::max(currentColumn, maxColumn); QBrush currentBrush(forgroundBrushes.at(currentColumn % forgroundBrushes.size())); - + auto *rectangle = (*theGraph)[currentVertex].rectangle.get(); rectangle->setRect(-rowPadding, 0.0, rowPadding, rowHeight); //calculate actual length later. rectangle->setTransform(QTransform::fromTranslate(0, rowHeight * currentRow)); rectangle->setBackgroundBrush(backgroundBrushes[currentRow % backgroundBrushes.size()]); auto *point = (*theGraph)[currentVertex].point.get(); - point->setRect(0.0, 0.0, -pointSize, -pointSize); + point->setRect(0.0, 0.0, pointSize, pointSize); point->setTransform(QTransform::fromTranslate(pointSpacing * currentColumn, - rowHeight * currentRow + rowHeight / 2.0 + pointSize / 2.0)); + rowHeight * currentRow + rowHeight / 2.0 - pointSize / 2.0)); point->setBrush(currentBrush); + float cheat = 0.0; + if (direction == -1) + cheat = rowHeight; + auto *visiblePixmap = (*theGraph)[currentVertex].visibleIcon.get(); - visiblePixmap->setTransform(QTransform::fromTranslate(0.0, rowHeight * currentRow + rowHeight)); //calculate x location later. + visiblePixmap->setTransform(QTransform::fromTranslate(0.0, rowHeight * currentRow + cheat)); //calculate x location later. auto *statePixmap = (*theGraph)[currentVertex].stateIcon.get(); - statePixmap->setTransform(QTransform::fromTranslate(0.0, rowHeight * currentRow + rowHeight)); //calculate x location later. + statePixmap->setTransform(QTransform::fromTranslate(0.0, rowHeight * currentRow + cheat)); //calculate x location later. auto *pixmap = (*theGraph)[currentVertex].icon.get(); - pixmap->setTransform(QTransform::fromTranslate(0.0, rowHeight * currentRow + rowHeight)); //calculate x location later. + pixmap->setTransform(QTransform::fromTranslate(0.0, rowHeight * currentRow + cheat)); //calculate x location later. auto *text = (*theGraph)[currentVertex].text.get(); - text->setPlainText(QString::fromUtf8(findRecord(currentVertex).DObject->Label.getValue())); + text->setPlainText(QString::fromUtf8(findRecord(currentVertex, *graphLink).DObject->Label.getValue())); text->setDefaultTextColor(currentBrush.color()); maxTextLength = std::max(maxTextLength, static_cast(text->boundingRect().width())); text->setTransform(QTransform::fromTranslate - (0.0, rowHeight * currentRow + rowHeight - verticalSpacing * 2.0)); //calculate x location later. + (0.0, rowHeight * currentRow - verticalSpacing * 2.0 + cheat)); //calculate x location later. (*theGraph)[currentVertex].lastVisibleState = VisibilityState::None; //force visual update for color. //store column and row int the graph. use for connectors later. @@ -719,7 +660,7 @@ void Model::updateSlot() //our list is topo sorted so all dependents should be located, so we can build the connectors. //will have some more logic for connector path, simple for now. - float currentX = pointSpacing * currentColumn - pointSize / 2.0; + float currentX = pointSpacing * currentColumn + pointSize / 2.0; float currentY = rowHeight * currentRow + rowHeight / 2.0; OutEdgeIterator it, itEnd; boost::tie(it, itEnd) = boost::out_edges(currentVertex, *theGraph); @@ -728,7 +669,7 @@ void Model::updateSlot() Vertex target = boost::target(*it, *theGraph); if (!(*theGraph)[target].dagVisible) continue; //we don't make it here if source isn't visible. So don't have to worry about that. - float dependentX = pointSpacing * static_cast(std::log2((*theGraph)[target].column.to_ulong())) - pointSize / 2.0; //on center. + float dependentX = pointSpacing * static_cast(std::log2((*theGraph)[target].column.to_ulong())) + pointSize / 2.0; //on center. float dependentY = rowHeight * (*theGraph)[target].row + rowHeight / 2.0; QGraphicsPathItem *pathItem = (*theGraph)[*it].connector.get(); @@ -742,20 +683,24 @@ void Model::updateSlot() //connector with bend. float radius = pointSpacing / 1.9; //no zero length line. - path.lineTo(currentX, dependentY - radius); + path.lineTo(currentX, dependentY + radius * direction); - float yPosition = dependentY - 2.0 * radius; + float yPosition; + if (direction == -1.0) + yPosition = dependentY - 2.0 * radius; + else + yPosition = dependentY; float width = 2.0 * radius; float height = width; if (dependentX > currentX) //radius to the right. { QRectF arcRect(currentX, yPosition, width, height); - path.arcTo(arcRect, 180.0, 90.0); + path.arcTo(arcRect, 180.0, 90.0 * -direction); } else //radius to the left. { QRectF arcRect(currentX - 2.0 * radius, yPosition, width, height); - path.arcTo(arcRect, 0.0, -90.0); + path.arcTo(arcRect, 0.0, 90.0 * direction); } path.lineTo(dependentX, dependentY); } @@ -874,7 +819,7 @@ void Model::updateStates() BGL_FORALL_VERTICES(currentVertex, *theGraph, Graph) { - const GraphLinkRecord &record = findRecord(currentVertex); + const GraphLinkRecord &record = findRecord(currentVertex, *graphLink); auto *visiblePixmap = (*theGraph)[currentVertex].visibleIcon.get(); VisibilityState currentVisibilityState = (record.VPDObject->isShow()) ? (VisibilityState::On) : (VisibilityState::Off); @@ -909,13 +854,13 @@ void Model::updateStates() } } -ViewEntryRectItem* Model::getRectFromPosition(const QPointF& position) +RectItem* Model::getRectFromPosition(const QPointF& position) { - ViewEntryRectItem *rect = nullptr; + RectItem *rect = nullptr; auto theItems = this->items(position, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder); for (auto *currentItem : theItems) { - rect = dynamic_cast(currentItem); + rect = dynamic_cast(currentItem); if (rect) break; } @@ -933,7 +878,7 @@ void Model::mouseMoveEvent(QGraphicsSceneMouseEvent* event) } }; - ViewEntryRectItem *rect = getRectFromPosition(event->scenePos()); + RectItem *rect = getRectFromPosition(event->scenePos()); if (!rect) { clearPrehighlight(); @@ -960,15 +905,15 @@ void Model::mousePressEvent(QGraphicsSceneMouseEvent* event) QListselection = collidingItems(&intersectionLine); for (auto currentItem = selection.begin(); currentItem != selection.end(); ++currentItem) { - ViewEntryRectItem *rect = dynamic_cast(*currentItem); + RectItem *rect = dynamic_cast(*currentItem); if (!rect) continue; - const GraphLinkRecord &selectionRecord = findRecord(rect); + const GraphLinkRecord &selectionRecord = findRecord(rect, *graphLink); Gui::Selection().addSelection(selectionRecord.DObject->getDocument()->getName(), selectionRecord.DObject->getNameInDocument()); } }; - auto toggleSelect = [](const App::DocumentObject *dObjectIn, ViewEntryRectItem *rectIn) + auto toggleSelect = [](const App::DocumentObject *dObjectIn, RectItem *rectIn) { if (rectIn->isSelected()) Gui::Selection().rmvSelection(dObjectIn->getDocument()->getName(), dObjectIn->getNameInDocument()); @@ -981,10 +926,10 @@ void Model::mousePressEvent(QGraphicsSceneMouseEvent* event) if (event->button() == Qt::LeftButton) { - ViewEntryRectItem *rect = getRectFromPosition(event->scenePos()); + RectItem *rect = getRectFromPosition(event->scenePos()); if (rect) { - const GraphLinkRecord &record = findRecord(rect); + const GraphLinkRecord &record = findRecord(rect, *graphLink); //don't like that I am doing this again here after getRectFromPosition call. QGraphicsItem *item = itemAt(event->scenePos()); @@ -1048,7 +993,7 @@ void Model::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) auto selections = getAllSelected(); if(selections.size() != 1) return; - const GraphLinkRecord &record = findRecord(selections.front()); + const GraphLinkRecord &record = findRecord(selections.front(), *graphLink); Gui::Document* doc = Gui::Application::Instance->getDocument(record.DObject->getDocument()); MDIView *view = doc->getActiveView(); if (view) @@ -1075,10 +1020,10 @@ std::vector Model::getAllSelected() void Model::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { - ViewEntryRectItem *rect = getRectFromPosition(event->scenePos()); + RectItem *rect = getRectFromPosition(event->scenePos()); if (rect) { - const GraphLinkRecord &record = findRecord(rect); + const GraphLinkRecord &record = findRecord(rect, *graphLink); //don't like that I am doing this again here after getRectFromPosition call. QGraphicsItem *item = itemAt(event->scenePos()); @@ -1124,8 +1069,6 @@ void Model::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) void Model::onRenameSlot() { -// std::cout << std::endl << "inside rename slot" << std::endl << std::endl; - assert(proxy == nullptr); std::vector selections = getAllSelected(); assert(selections.size() == 1); @@ -1149,7 +1092,7 @@ void Model::renameAcceptedSlot() std::vector selections = getAllSelected(); assert(selections.size() == 1); - const GraphLinkRecord &record = findRecord(selections.front()); + const GraphLinkRecord &record = findRecord(selections.front(), *graphLink); LineEdit *lineEdit = dynamic_cast(proxy->widget()); assert(lineEdit); @@ -1180,7 +1123,7 @@ void Model::editingStartSlot() int edit = action->data().toInt(); auto selections = getAllSelected(); assert(selections.size() == 1); - const GraphLinkRecord &record = findRecord(selections.front()); + const GraphLinkRecord &record = findRecord(selections.front(), *graphLink); Gui::Document* doc = Gui::Application::Instance->getDocument(record.DObject->getDocument()); MDIView *view = doc->getActiveView(); if (view) @@ -1193,7 +1136,7 @@ void Model::editingFinishedSlot() { auto selections = getAllSelected(); assert(selections.size() == 1); - const GraphLinkRecord &record = findRecord(selections.front()); + const GraphLinkRecord &record = findRecord(selections.front(), *graphLink); Gui::Document* doc = Gui::Application::Instance->getDocument(record.DObject->getDocument()); doc->commitCommand(); doc->resetEdit(); @@ -1236,13 +1179,13 @@ void Model::visiblyIsolate(Gui::DAG::Vertex sourceIn) static std::vector skipTypes = buildSkipTypes(); for (const auto ¤tVertex : connectedVertices) { - const GraphLinkRecord &record = findRecord(currentVertex); + const GraphLinkRecord &record = findRecord(currentVertex, *graphLink); if (testSkipType(record.DObject, skipTypes)) continue; const_cast(record.VPDObject)->hide(); //const hack } - const GraphLinkRecord &sourceRecord = findRecord(sourceIn); + const GraphLinkRecord &sourceRecord = findRecord(sourceIn, *graphLink); if (!testSkipType(sourceRecord.DObject, skipTypes)) const_cast(sourceRecord.VPDObject)->show(); //const hack } diff --git a/src/Gui/DAGView/DAGModel.h b/src/Gui/DAGView/DAGModel.h index d429426d4..4825b750c 100644 --- a/src/Gui/DAGView/DAGModel.h +++ b/src/Gui/DAGView/DAGModel.h @@ -25,29 +25,20 @@ #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include #include +#include "DAGRectItem.h" +#include "DAGModelGraph.h" +#include "DAGFilter.h" + class QGraphicsSceneHoverEvent; class QGraphicsProxyWidget; -namespace App{class DocumentObject;} - namespace Gui { class Document; @@ -68,257 +59,6 @@ namespace Gui virtual void keyPressEvent(QKeyEvent*); }; - /*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 setEditingBrush(const QBrush &brushIn){editBrush = 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;} - void editingStart(){editing = true;} - void editingFinished(){editing = false;} - bool isEditing(){return editing;} - 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. - QBrush editBrush; //!< brush used when object is in edit mode. - //start with booleans, may expand to state. - bool selected; - bool preSelected; - bool editing; - }; - - enum class VisibilityState - { - None = 0, // ColumnMask; - - /*! @brief Graph vertex information - * - * My data stored for each vertex; - */ - struct VertexProperty - { - VertexProperty(); - std::shared_ptr rectangle; //!< background - std::shared_ptr point; //!< point - std::shared_ptr visibleIcon; //!< visible Icon - std::shared_ptr stateIcon; //!< visible Icon - std::shared_ptr icon; //!< icon - std::shared_ptr text; //!< text - int row; //!< row for this entry. - ColumnMask column; //!< column number containing the point. - int topoSortIndex; - VisibilityState lastVisibleState; //!< visibility test. - FeatureState lastFeatureState; //!< feature state test. - bool dagVisible; //!< should entry be visible in the DAG view. - }; - /*! @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 - > vertex_prop; - - /*! @brief Graph edge information - * - * My data stored for each edge; - */ - struct EdgeProperty - { - //! Feature relation meta data. Not used right now. - enum class BranchTag - { - None = 0, //!< not defined. - Create, //!< create a new branch. - Continue, //!< continue a branch. - Terminate //!< terminate a branch. - }; - EdgeProperty(); - BranchTag relation; - std::shared_ptr connector; //!< line representing link between nodes. - }; - /*! @brief needed to create an internal index for graph edges. needed for setS.*/ - typedef boost::property edge_prop; - - typedef boost::adjacency_list Graph; - typedef boost::graph_traits::vertex_descriptor Vertex; - typedef boost::graph_traits::edge_descriptor Edge; - typedef boost::graph_traits::vertex_iterator VertexIterator; - typedef boost::graph_traits::edge_iterator EdgeIterator; - typedef boost::graph_traits::in_edge_iterator InEdgeIterator; - typedef boost::graph_traits::out_edge_iterator OutEdgeIterator; - typedef boost::graph_traits::adjacency_iterator VertexAdjacencyIterator; - typedef boost::reverse_graph GraphReversed; - typedef std::vector Path; //!< a path or any array of vertices - - template - class Edge_writer { - public: - Edge_writer(const GraphEW &graphEWIn) : graphEW(graphEWIn) {} - template - void operator()(std::ostream& out, const EdgeW& edgeW) const - { - out << "[label=\""; - out << "edge"; - out << "\"]"; - } - private: - const GraphEW &graphEW; - }; - - template - class Vertex_writer { - public: - Vertex_writer(const GraphVW &graphVWIn) : graphVW(graphVWIn) {} - template - void operator()(std::ostream& out, const VertexW& vertexW) const - { - out << "[label=\""; - out << graphVW[vertexW].text->toPlainText().toAscii().data(); - out << "\"]"; - } - private: - const GraphVW &graphVW; - }; - - template - void outputGraphviz(const GraphIn &graphIn, const std::string &filePath) - { - std::ofstream file(filePath.c_str()); - boost::write_graphviz(file, graphIn, Vertex_writer(graphIn), - Edge_writer(graphIn)); - } - - //! get all the leaves of the templated graph. Not used right now. - template - class RakeLeaves - { - typedef boost::graph_traits::vertex_descriptor GraphInVertex; - typedef std::vector 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 DigRoots - { - typedef boost::graph_traits::vertex_descriptor GraphInVertex; - typedef std::vector 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, - BMI::member - >, - BMI::ordered_unique - < - BMI::tag, - BMI::member - >, - BMI::ordered_unique - < - BMI::tag, - BMI::member - >, - BMI::ordered_unique - < - BMI::tag, - BMI::member - >, - BMI::ordered_unique - < - BMI::tag, - BMI::member - > - > - > GraphLinkContainer; - class Model : public QGraphicsScene { Q_OBJECT @@ -365,24 +105,18 @@ namespace Gui std::shared_ptr 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 addVertexItemsToScene(const Vertex &vertexIn); void removeVertexItemsFromScene(const Vertex &vertexIn); void updateStates(); - ViewEntryRectItem* getRectFromPosition(const QPointF &position); //!< can be nullptr + RectItem* getRectFromPosition(const QPointF &position); //!< can be nullptr //! @name View Constants for spacing //@{ float fontHeight; //!< height of the current qApp default font. + float direction; //!< controls top to bottom or bottom to top direction. 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. @@ -397,7 +131,7 @@ namespace Gui void setupViewConstants(); //@} - ViewEntryRectItem *currentPrehighlight; + RectItem *currentPrehighlight; enum class SelectionMode { @@ -420,25 +154,13 @@ namespace Gui QAction *editingFinishedAction; QGraphicsProxyWidget *proxy = nullptr; void finishRename(); - }; - - /*! @brief Get connected components. - */ - class ConnectionVisitor : public boost::default_bfs_visitor - { - public: - ConnectionVisitor(std::vector &verticesIn) : vertices(verticesIn){} - template - void discover_vertex(TVertex vertex, TGraph &graph) - { - vertices.push_back(vertex); - } - private: - std::vector &vertices; + //filters + void setupFilters(); + typedef std::vector > FilterContainer; + FilterContainer filters; }; } - } #endif // DAGMODEL_H diff --git a/src/Gui/DAGView/DAGModelGraph.cpp b/src/Gui/DAGView/DAGModelGraph.cpp new file mode 100644 index 000000000..ffdb339a5 --- /dev/null +++ b/src/Gui/DAGView/DAGModelGraph.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 * + * * + ***************************************************************************/ + +#include "DAGModelGraph.h" + +using namespace Gui; +using namespace DAG; + +VertexProperty::VertexProperty() : + rectangle(new RectItem()), + point(new QGraphicsEllipseItem()), + visibleIcon(new QGraphicsPixmapItem()), + stateIcon(new QGraphicsPixmapItem()), + icon(new QGraphicsPixmapItem()), + text(new QGraphicsTextItem()), + row(0), + column(0), + lastVisibleState(VisibilityState::None), + dagVisible(true) +{ + //set z values. + this->rectangle->setZValue(-1000.0); + this->point->setZValue(1000.0); + this->visibleIcon->setZValue(0.0); + this->stateIcon->setZValue(0.0); + this->icon->setZValue(0.0); + this->text->setZValue(0.0); +} + +EdgeProperty::EdgeProperty() : relation(BranchTag::None) +{ + +} + +const GraphLinkRecord& Gui::DAG::findRecord(Vertex vertexIn, const GraphLinkContainer &containerIn) +{ + typedef GraphLinkContainer::index::type List; + const List &list = containerIn.get(); + List::const_iterator it = list.find(vertexIn); + assert(it != list.end()); + return *it; +} + +const GraphLinkRecord& Gui::DAG::findRecord(const App::DocumentObject* dObjectIn, const GraphLinkContainer &containerIn) +{ + typedef GraphLinkContainer::index::type List; + const List &list = containerIn.get(); + List::const_iterator it = list.find(dObjectIn); + assert(it != list.end()); + return *it; +} + +const GraphLinkRecord& Gui::DAG::findRecord(const ViewProviderDocumentObject* VPDObjectIn, const GraphLinkContainer &containerIn) +{ + typedef GraphLinkContainer::index::type List; + const List &list = containerIn.get(); + List::const_iterator it = list.find(VPDObjectIn); + assert(it != list.end()); + return *it; +} + +const GraphLinkRecord& Gui::DAG::findRecord(const RectItem* rectIn, const GraphLinkContainer &containerIn) +{ + typedef GraphLinkContainer::index::type List; + const List &list = containerIn.get(); + List::const_iterator it = list.find(rectIn); + assert(it != list.end()); + return *it; +} + +const GraphLinkRecord& Gui::DAG::findRecord(const std::string &stringIn, const GraphLinkContainer &containerIn) +{ + typedef GraphLinkContainer::index::type List; + const List &list = containerIn.get(); + List::const_iterator it = list.find(stringIn); + assert(it != list.end()); + return *it; +} + +void Gui::DAG::eraseRecord(const ViewProviderDocumentObject* VPDObjectIn, GraphLinkContainer &containerIn) +{ + typedef GraphLinkContainer::index::type List; + const List &list = containerIn.get(); + List::iterator it = list.find(VPDObjectIn); + assert(it != list.end()); + containerIn.get().erase(it); +} \ No newline at end of file diff --git a/src/Gui/DAGView/DAGModelGraph.h b/src/Gui/DAGView/DAGModelGraph.h new file mode 100644 index 000000000..069cb993b --- /dev/null +++ b/src/Gui/DAGView/DAGModelGraph.h @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 DAGMODELGRAPH_H +#define DAGMODELGRAPH_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DAGRectItem.h" + +namespace App{class DocumentObject;} + +namespace Gui +{ + class ViewProviderDocumentObject; + + namespace DAG + { + enum class VisibilityState + { + None = 0, // ColumnMask; + + /*! @brief Graph vertex information + * + * My data stored for each vertex; + */ + struct VertexProperty + { + VertexProperty(); + std::shared_ptr rectangle; //!< background + std::shared_ptr point; //!< point + std::shared_ptr visibleIcon; //!< visible Icon + std::shared_ptr stateIcon; //!< visible Icon + std::shared_ptr icon; //!< icon + std::shared_ptr text; //!< text + int row; //!< row for this entry. + ColumnMask column; //!< column number containing the point. + int topoSortIndex; + VisibilityState lastVisibleState; //!< visibility test. + FeatureState lastFeatureState; //!< feature state test. + bool dagVisible; //!< should entry be visible in the DAG view. + }; + /*! @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 + > vertex_prop; + + /*! @brief Graph edge information + * + * My data stored for each edge; + */ + struct EdgeProperty + { + //! Feature relation meta data. Not used right now. + enum class BranchTag + { + None = 0, //!< not defined. + Create, //!< create a new branch. + Continue, //!< continue a branch. + Terminate //!< terminate a branch. + }; + EdgeProperty(); + BranchTag relation; + std::shared_ptr connector; //!< line representing link between nodes. + }; + /*! @brief needed to create an internal index for graph edges. needed for setS.*/ + typedef boost::property edge_prop; + + typedef boost::adjacency_list Graph; + typedef boost::graph_traits::vertex_descriptor Vertex; + typedef boost::graph_traits::edge_descriptor Edge; + typedef boost::graph_traits::vertex_iterator VertexIterator; + typedef boost::graph_traits::edge_iterator EdgeIterator; + typedef boost::graph_traits::in_edge_iterator InEdgeIterator; + typedef boost::graph_traits::out_edge_iterator OutEdgeIterator; + typedef boost::graph_traits::adjacency_iterator VertexAdjacencyIterator; + typedef boost::reverse_graph GraphReversed; + typedef std::vector Path; //!< a path or any array of vertices + + template + class Edge_writer { + public: + Edge_writer(const GraphEW &graphEWIn) : graphEW(graphEWIn) {} + template + void operator()(std::ostream& out, const EdgeW& edgeW) const + { + out << "[label=\""; + out << "edge"; + out << "\"]"; + } + private: + const GraphEW &graphEW; + }; + + template + class Vertex_writer { + public: + Vertex_writer(const GraphVW &graphVWIn) : graphVW(graphVWIn) {} + template + void operator()(std::ostream& out, const VertexW& vertexW) const + { + out << "[label=\""; + out << graphVW[vertexW].text->toPlainText().toAscii().data(); + out << "\"]"; + } + private: + const GraphVW &graphVW; + }; + + template + void outputGraphviz(const GraphIn &graphIn, const std::string &filePath) + { + std::ofstream file(filePath.c_str()); + boost::write_graphviz(file, graphIn, Vertex_writer(graphIn), + Edge_writer(graphIn)); + } + + //! get all the leaves of the templated graph. Not used right now. + template + class RakeLeaves + { + typedef boost::graph_traits::vertex_descriptor GraphInVertex; + typedef std::vector 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 DigRoots + { + typedef boost::graph_traits::vertex_descriptor GraphInVertex; + typedef std::vector 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; + }; + + /*! @brief Get connected components. + */ + class ConnectionVisitor : public boost::default_bfs_visitor + { + public: + ConnectionVisitor(std::vector &verticesIn) : vertices(verticesIn){} + + template + void discover_vertex(TVertex vertex, TGraph &graph) + { + vertices.push_back(vertex); + } + private: + std::vector &vertices; + }; + + /*! Multi_index record. */ + struct GraphLinkRecord + { + const App::DocumentObject *DObject; //!< document object + const Gui::ViewProviderDocumentObject *VPDObject; //!< view provider + const RectItem *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, + BMI::member + >, + BMI::ordered_unique + < + BMI::tag, + BMI::member + >, + BMI::ordered_unique + < + BMI::tag, + BMI::member + >, + BMI::ordered_unique + < + BMI::tag, + BMI::member + >, + BMI::ordered_unique + < + BMI::tag, + BMI::member + > + > + > GraphLinkContainer; + + const GraphLinkRecord& findRecord(Vertex vertexIn, const GraphLinkContainer &containerIn); + const GraphLinkRecord& findRecord(const App::DocumentObject* dObjectIn, const GraphLinkContainer &containerIn); + const GraphLinkRecord& findRecord(const Gui::ViewProviderDocumentObject* VPDObjectIn, const GraphLinkContainer &containerIn); + const GraphLinkRecord& findRecord(const RectItem* rectIn, const GraphLinkContainer &containerIn); + const GraphLinkRecord& findRecord(const std::string &stringIn, const GraphLinkContainer &containerIn); + void eraseRecord(const Gui::ViewProviderDocumentObject* VPDObjectIn, GraphLinkContainer &containerIn); + } +} + +#endif // DAGMODELGRAPH_H diff --git a/src/Gui/DAGView/DAGRectItem.cpp b/src/Gui/DAGView/DAGRectItem.cpp new file mode 100644 index 000000000..1b15d5544 --- /dev/null +++ b/src/Gui/DAGView/DAGRectItem.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#endif + +#include "DAGRectItem.h" + +using namespace Gui; +using namespace DAG; + +RectItem::RectItem(QGraphicsItem* parent) : QGraphicsRectItem(parent) +{ + selected = false; + preSelected = false; + editing = false; +} + +void RectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + //TODO figure out how to mimic painting of itemviews. QStyle, QStyledItemDelegate. + + QBrush brush = backgroundBrush; + if (selected) + brush = selectionBrush; + if (preSelected) + brush = preSelectionBrush; + if (selected && preSelected) + brush = bothBrush; + if (editing) + brush = editBrush; + + //heights are negative. + float radius = std::min(this->rect().width(), std::fabs(this->rect().height())) * 0.1; + painter->setBrush(brush); + painter->setPen(this->pen()); //should be Qt::NoPen. + painter->drawRoundedRect(this->rect(), radius, radius); + +// QGraphicsRectItem::paint(painter, option, widget); +} + +#include diff --git a/src/Gui/DAGView/DAGRectItem.h b/src/Gui/DAGView/DAGRectItem.h new file mode 100644 index 000000000..a8fd6bd5b --- /dev/null +++ b/src/Gui/DAGView/DAGRectItem.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (c) 2015 Thomas Anderson * + * * + * 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 DAGRECTITEM_H +#define DAGRECTITEM_H + +#include +#include + +namespace Gui +{ + 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 RectItem : public QGraphicsRectItem + { + public: + RectItem(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 setEditingBrush(const QBrush &brushIn){editBrush = 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;} + void editingStart(){editing = true;} + void editingFinished(){editing = false;} + bool isEditing(){return editing;} + 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. + QBrush editBrush; //!< brush used when object is in edit mode. + //start with booleans, may expand to state. + bool selected; + bool preSelected; + bool editing; + }; + } +} + +#endif // DAGRECTITEM_H