/** * Emits a signal to open an editor at the file and line matching the call * information of the current edge. * This slot is connected to the "Open Call" popup menu action (for edges). */ void GraphWidget::slotOpenCall() { GraphEdge* pEdge; QString sFile, sLine; // Make sure the menu item is an edge pEdge = dynamic_cast<GraphEdge*>(m_pMenuItem); if (pEdge != NULL && pEdge->getFile() != "") emit lineRequested(pEdge->getFile(), pEdge->getLine()); }
/** * Adds a call to the graph. * A call is made between two functions, the caller and the callee. * @param data Contains information on the call */ void GraphWidget::addCall(const CallData& data) { GraphNode* pCaller, * pCallee; GraphEdge* pEdge; // Find the relevant nodes (create new nodes if necessary) pCaller = addNode(data.m_sCaller); pCallee = addNode(data.m_sCallee); // Create a new edge pEdge = pCaller->addOutEdge(pCallee); pEdge->setCallInfo(data.m_sFile, data.m_sLine, data.m_sText); }
void GraphEdge::updateWithEdge(const GraphEdge& edge) { kDebug() << id() << edge.id(); m_arrowheads = edge.arrowheads(); m_colors = edge.colors(); m_dir = edge.dir(); GraphElement::updateWithElement(edge); if (canvasEdge()) { canvasEdge()->computeBoundingRect(); canvasEdge()->modelChanged(); } }
void DrawEdge(const GraphEdge& edge, const Graph& g) { glDisable(GL_LIGHTING); glBegin(GL_LINES); const GraphNode& from = g.GetNode(edge.GetFrom()); const GraphNode& to = g.GetNode(edge.GetTo()); const Vec2f& u = from.GetPos(); const Vec2f& v = to.GetPos(); glVertex3f(u.x, 0, u.y); glVertex3f(v.x, 0, v.y); glEnd(); glEnable(GL_LIGHTING); }
void DualGraph::saveGraph(const char *filename) { std::ofstream output(filename); for (NodeIter nit(this); !nit.end(); ++nit) { GraphNode *node = *nit; output << "v " << node->id() << "\n"; } for (EdgeIter eit(this); !eit.end(); ++eit) { GraphEdge *edge = *eit; output << "e " << edge->from()->id() << " " << edge->to()->id() << "\n"; } output.close(); }
QList<GraphEdge*> GraphView::getEdges() { QList<GraphEdge*> edges; QListIterator<QGraphicsItem*> it(scene()->items()); while (it.hasNext()) { GraphEdge* edge = dynamic_cast<GraphEdge*>(it.next()); if (edge && edge->isVisible()) edges.append(edge); } return edges; }
void GraphNode::moveTo(const QPointF& pt) { setCenter(pt); QListIterator<GraphEdge*> it(destinationEdges); while (it.hasNext()) it.next()->destinationUpdated(); it = QListIterator<GraphEdge*>(sourceEdges); while (it.hasNext()) { GraphEdge* edge = it.next(); // The undirected edges were already updated because the node is both source and destination if (!edge->isUndirected()) edge->sourceUpdated(); } }
bool Bfs::SearchWithTrail(int from, int to, Trail* trail) { // Need to remember which nodes we have already visited std::set<int> visited; Breadcrumbs breadcrumbs; // Breadth first uses a queue to hold nodes we will visit std::queue<GraphEdge> nodesToVisit; float cost = 0; // dummy value // Put dummy edge in stack to start search. TODO better way, e.g. do/while ? nodesToVisit.push(GraphEdge(from, from, cost)); while (!nodesToVisit.empty()) { GraphEdge e = nodesToVisit.front(); nodesToVisit.pop(); std::cout << "Trying edge from " << e.GetFrom() << " to " << e.GetTo() << "\n"; breadcrumbs[e.GetTo()] = e.GetFrom(); // map version //breadcrumbs.push_back(e); // vector version // In addition to here.... visited.insert(e.GetTo()); if (e.GetTo() == to) { // We have found the finish! std::cout << "Successfully got to the finish!\n"; MakeTrail(from, to, breadcrumbs, trail); return true; } else { // Push unvisited neighbours onto stack const EdgeList& edgelist = m_graph->GetEdgeList(e.GetTo()); for (EdgeList::const_iterator it = edgelist.begin(); it != edgelist.end(); ++it) { const GraphEdge& childEdge = *it; if (visited.count(childEdge.GetTo()) == 0) { nodesToVisit.push(childEdge); // ...we mark node as visited right away here visited.insert(childEdge.GetTo()); } } } } return false; }
void Graph :: preprocess(){ //we want all the edges to have pointer to the nodes its connecting //we also want all nodes to know about its adjacency nodes //we will do so by traversing all the edges for (int e=0; e< edgelist.size(); e++) { GraphEdge * thedg = edgelist.at(e); int frid = thedg->from; int toid = thedg->to; bool foundfrom = false; bool foundto = false; GraphNode * fromend; GraphNode * toend; //find these nodes in the adjlist for (int a=0; a<adjlist.size(); a++) { GraphNode * nd = adjlist.at(a); if (!foundfrom && nd->getnodeid() == frid) { fromend = nd; thedg->setFrom(fromend); fromend->addAdjacentEdge(thedg); foundfrom = true; } if (!foundto && nd->getnodeid() == toid) { toend = nd; thedg->setTo(toend); toend->addAdjacentEdge(thedg); foundto = true; } if(foundto && foundfrom){ fromend -> addAdjacentNode(toend); toend->addAdjacentNode(fromend); break; } } } }
/** * Checks if a tool tip is required for the given position. * NOTE: We currently return a tool tip for edges only * @param ptPos The position to query * @param rc Holds the tip's rectangle, upon return * @return The tip's text, or QString::null if no tip is required */ QString GraphWidget::getTip(const QPoint& ptPos, QRect& rc) { QPoint ptRealPos, ptTopLeft, ptBottomRight; QCanvasItemList il; QCanvasItemList::Iterator itr; GraphEdge* pEdge; QString sText, sFile, sLine; ptRealPos = viewportToContents(ptPos); ptRealPos /= m_dZoom; pEdge = NULL; // Check if there is an edge at this position il = canvas()->collisions(ptRealPos); for (itr = il.begin(); itr != il.end(); ++itr) { pEdge = dynamic_cast<GraphEdge*>(*itr); if (pEdge != NULL) break; } // No tip if no edge was found if (pEdge == NULL) return QString::null; // Set the rectangle for the tip (the tip is closed when the mouse leaves // this area) rc = pEdge->tipRect(); ptTopLeft = rc.topLeft(); ptBottomRight = rc.bottomRight(); ptTopLeft *= m_dZoom; ptBottomRight *= m_dZoom; ptTopLeft = contentsToViewport(ptTopLeft); ptBottomRight = contentsToViewport(ptBottomRight); rc = QRect(ptTopLeft, ptBottomRight); // Create a tip for this edge return pEdge->getTip(); }
void GraphView::setNodeRadius(int radius) { nodeRadius = radius; QListIterator<QGraphicsItem*> it(scene()->items()); while (it.hasNext()) { GraphNode* node = dynamic_cast<GraphNode*>(it.next()); if (node) node->setRadius(radius); } // After changing the radius of every node, we recalculate the edges it.toFront(); while (it.hasNext()) { GraphEdge* edge = dynamic_cast<GraphEdge*>(it.next()); if (edge) edge->updateDrawing(); } scene()->update(); }
/** * Writes a description of the graph to the given stream, using the Dot * language. * The method allows for both directed graphs and non-directed graphs, the * latter are required for drawing purposes (since Dot will not produce the * arrow heads and the splines terminate before reaching the nodes). * @param str The stream to write to * @param sType Either "graph" or "digraph" * @param sEdge The edge connector ("--" or "->") * @param bWriteCall true to write call information, false otherwise */ void GraphWidget::write(QTextStream& str, const QString& sType, const QString& sEdge, bool bWriteCall) { QFont font; QDictIterator<GraphNode> itr(m_dictNodes); GraphEdge* pEdge; Encoder enc; font = Config().getFont(KScopeConfig::Graph); // Header str << sType << " G {\n"; // Graph attributes str << "\tgraph [rankdir=" << Config().getGraphOrientation() << ", " << "kscope_zoom=" << m_dZoom << "];\n"; // Default node attributes str << "\tnode [shape=box, height=\"0.01\", style=filled, " << "fillcolor=\"" << Config().getColor(KScopeConfig::GraphNode).name() << "\", " << "fontcolor=\"" << Config().getColor(KScopeConfig::GraphText).name() << "\", " << "fontname=\"" << font.family() << "\", " << "fontsize=" << QString::number(font.pointSize()) << "];\n"; // Iterate over all nodes for (; itr.current(); ++itr) { // Write a node str << "\t" << itr.current()->getFunc() << ";\n"; // Iterate over all edges leaving this node QDictIterator<GraphEdge> itrEdge(itr.current()->getOutEdges()); for (; itrEdge.current(); ++itrEdge) { pEdge = itrEdge.current(); str << "\t" << pEdge->getHead()->getFunc() << sEdge << pEdge->getTail()->getFunc(); // Write call information if (bWriteCall) { str << " [" << "kscope_file=\"" << pEdge->getFile() << "\"," << "kscope_line=" << pEdge->getLine() << "," << "kscope_text=\"" << enc.encode(pEdge->getText()) << "\"" << "]"; } str << ";\n"; } } // Close the graph str << "}\n"; }
bool Dfs::SearchWithTrail(int from, int to, Trail* trail) { std::set<int> visited; Breadcrumbs breadcrumbs; std::stack<GraphEdge> nodesToVisit; float cost = 0; // Put dummy edge in stack nodesToVisit.push(GraphEdge(from, from, cost)); while (!nodesToVisit.empty()) { GraphEdge e = nodesToVisit.top(); nodesToVisit.pop(); std::cout << "Trying edge from " << e.GetFrom() << " to " << e.GetTo() << "\n"; breadcrumbs[e.GetTo()] = e.GetFrom(); // map version // breadcrumbs.push_back(e); // vector version visited.insert(e.GetTo()); if (e.GetTo() == to) { // We have found the finish! Loop back through the breadcrumbs to create the trail. MakeTrail(from, to, breadcrumbs, trail); return true; } else { // Push unvisited neighbours onto stack const EdgeList& edgelist = m_graph->GetEdgeList(e.GetTo()); for (EdgeList::const_iterator it = edgelist.begin(); it != edgelist.end(); ++it) { const GraphEdge& childEdge = *it; if (visited.count(childEdge.GetTo()) == 0) { nodesToVisit.push(childEdge); } } } } return false; }
bool Dfs::SearchNoTrail(int from, int to) { // Need to remember which nodes we have already visited std::set<int> visited; // Depth first uses a stack to hold nodes we will visit std::stack<GraphEdge> nodesToVisit; float cost = 0; // dummy value // Put dummy edge in stack to start search. TODO better way, e.g. do/while ? nodesToVisit.push(GraphEdge(from, from, cost)); while (!nodesToVisit.empty()) { GraphEdge e = nodesToVisit.top(); nodesToVisit.pop(); std::cout << "Trying edge from " << e.GetFrom() << " to " << e.GetTo() << "\n"; visited.insert(e.GetTo()); if (e.GetTo() == to) { // We have found the finish! return true; } else { // Push unvisited neighbours onto stack const EdgeList& edgelist = m_graph->GetEdgeList(e.GetTo()); for (EdgeList::const_iterator it = edgelist.begin(); it != edgelist.end(); ++it) { const GraphEdge& childEdge = *it; if (visited.count(childEdge.GetTo()) == 0) { nodesToVisit.push(childEdge); } } } } return false; }
/** * Displays an edge on the canvas. * Sets the parameters used for drawing the edge on the canvas. * @param sCaller Identifies the edge's head node * @param sCallee Identifies the edge's tail node * @param arrCurve Control points for the edge's spline */ void GraphWidget::drawEdge(const QString& sCaller, const QString& sCallee, const QPointArray& arrCurve) { GraphNode* pCaller, * pCallee; GraphEdge* pEdge; // Find the edge pCaller = addNode(sCaller); pCallee = addNode(sCallee); pEdge = pCaller->addOutEdge(pCallee); // Set the visual aspects of the edge pEdge->setPoints(arrCurve, s_ai); pEdge->setZ(1.0); pEdge->setPen(QPen(Qt::black)); pEdge->setBrush(QBrush(Qt::black)); // Draw the edge pEdge->show(); }
//void GraphEdge::adjust() void GraphEdge::updateGeometry() { if (!sourceNode_ || !destNode_) return; //sourceNode_->adjustSize(); //destNode_->adjustSize(); // line from center of sourceNode_ to center of destNode_ QRectF sSBR (sourceNode_->sceneBoundingRect()); QRectF dSBR (destNode_->sceneBoundingRect()); QLineF centerline(sSBR.center(), dSBR.center()); // set the source and destination points if(!sSBR.intersects(dSBR)) { QPointF po; if(QLineF::BoundedIntersection == centerline.intersect(QLineF(sSBR.topLeft(), sSBR.topRight()), &po)) sourcePoint = po; else if(QLineF::BoundedIntersection == centerline.intersect(QLineF(sSBR.bottomRight(), sSBR.topRight()), &po)) sourcePoint = po; else if(QLineF::BoundedIntersection == centerline.intersect(QLineF(sSBR.bottomLeft(), sSBR.bottomRight()), &po)) sourcePoint = po; else if(QLineF::BoundedIntersection == centerline.intersect(QLineF(sSBR.topLeft(), sSBR.bottomLeft()), &po)) sourcePoint = po; if(QLineF::BoundedIntersection == centerline.intersect(QLineF(dSBR.topLeft(), dSBR.topRight()), &po)) destPoint = po; else if(QLineF::BoundedIntersection == centerline.intersect(QLineF(dSBR.bottomRight(), dSBR.topRight()), &po)) destPoint = po; else if(QLineF::BoundedIntersection == centerline.intersect(QLineF(dSBR.bottomLeft(), dSBR.bottomRight()), &po)) destPoint = po; else if(QLineF::BoundedIntersection == centerline.intersect(QLineF(dSBR.topLeft(), dSBR.bottomLeft()), &po)) destPoint = po; } else { sourcePoint = destPoint = (sSBR.bottomLeft().y() < dSBR.bottomLeft().y()) ? sSBR.bottomLeft() : dSBR.bottomLeft(); } QLineF line(sourcePoint, destPoint); // set label centered in the middle of the arrow QRectF label (label_->boundingRect()); label.translate(line.pointAt(0.5)); if(sourcePoint != destPoint) label.translate(-label.width()/2, -label.height()/2); // avoid overlapping bool overlapped; while(true) { overlapped = false; Graph *graph = reinterpret_cast<Graph *>(scene()); if(!graph) break; Edges::const_iterator i = graph->edges_.constBegin(); while (i != graph->edges_.constEnd()) { GraphEdge *e = i.value(); if(e != this && e->label()->geometry().intersects(label)) { label.moveTo(label.x(), label.y() + 1 + e->label()->geometry().intersected(label).height()); overlapped = true; } ++i; } // node overlapping Nodes::const_iterator j = graph->nodes_.constBegin(); while (j != graph->nodes_.constEnd()) { GraphNode *n = j.value(); if(n->geometry().intersects(label)) { label.moveTo(label.x(), label.y() + 1 + n->geometry().intersected(label).height()); overlapped = true; } ++j; } if(!overlapped) break; }; label_->setGeometry(label); labelRect_ = label; prepareGeometryChange(); QGraphicsLayoutItem::updateGeometry(); }
DualGraph* generateGraph(std::vector<Patch*>& patches) { DualGraph *dualGraph = new DualGraph; std::map<Vertex*, std::vector<Patch*> > ver2patchMap; for (auto p : patches) { GraphNode *node = dualGraph->addNode(); p->graphNode = node; for (auto v : p->vertices) { auto pvec = ver2patchMap[v]; for (size_t i = 0; i < pvec.size(); ++i) { Patch *p0 = pvec[i]; dualGraph->addEdge(p0->graphNode, node); dualGraph->addEdge(node, p0->graphNode); } ver2patchMap[v].push_back(p); } } //well.. let's print out the dualgraph //convert the dual graph to cm //first, the position, each center of the cluster std::ofstream dgfile("dualgraph.cm"); for (auto p : patches) { GraphNode *gnode = p->graphNode; dgfile << "Vertex " << gnode->id() + 1 << " " << p->center[0] << " " << p->center[1] << " " << p->center[2] << "\n"; } for (auto p : patches) { GraphNode *gnode = p->graphNode; for (GraphNode::EdgeIter eit(gnode); !eit.end(); ++eit) { GraphEdge *edge = *eit; if (edge->to()->id() > gnode->id()) { dgfile << "Edge " << edge->from()->id() + 1 << " " << edge->to()->id() + 1 << "\n"; } } } dualGraph->saveMetis("dualgraph.metis"); dgfile.close(); std::vector <std::string> edgestr; std::set<Vertex*> vertices; double total_boundary_length = 0; int boundary_count = 0; for (auto p : patches) { std::set<Vertex*> pvertices; for (auto he : p->boundary) { if (!he->twin()) { total_boundary_length += (he->source()->point() - he->target()->point()).norm(); ++boundary_count; if ( ver2patchMap[he->source()].size() == 1) { //continue; } vertices.insert(he->source()); auto itpair = pvertices.insert(he->source()); if (itpair.second) { p->corners.push_back(he->source()); } if ( ver2patchMap[he->target()].size() == 1) { // continue; } vertices.insert(he->target()); itpair = pvertices.insert(he->target()); if (itpair.second) { p->corners.push_back(he->target()); } } if ( ver2patchMap[he->source()].size() >= 3) { vertices.insert(he->source()); auto itpair = pvertices.insert(he->source()); if (itpair.second) { p->corners.push_back(he->source()); } } if ( ver2patchMap[he->target()].size() >= 3) { vertices.insert(he->target()); auto itpair = pvertices.insert(he->target()); if (itpair.second) { p->corners.push_back(he->target()); } } } } avg_length = total_boundary_length / boundary_count; std::map<Vertex*, int> prevOrder, nowOrder; std::ofstream output("graph.m"); int vid = 1; for (auto v : vertices) { output << "Vertex " << vid << " " << v->point()[0] << " " << v->point()[1] << " " << v->point()[2] << "\n"; prevOrder[v] = v->index(); nowOrder[v] = vid++; } int fid = 0; for (auto p : patches) { output << "Face " << ++fid << " "; for (auto v : p->corners) { output << nowOrder[v] << " "; } output << "\n"; } for (auto v : vertices) { v->index() = prevOrder[v]; } return dualGraph; }
void Graph :: preprocessauthorgraph(){ //we want all the edges to have pointer to the nodes its connecting //we also want all nodes to know about its adjacency nodes //we will do so by traversing all the edges //for this particular data we have to work with string id's for (int e=0; e< edgelist.size(); e++) { GraphEdge * thedg = edgelist.at(e); string frst = thedg->strfrom; string tostr = thedg->strto; bool foundfrom = false; bool foundto = false; GraphNode * fromend; GraphNode * toend; //find these nodes in the adjlist for (int a=0; a<adjlist.size(); a++) { GraphNode * nd = adjlist.at(a); if (!foundfrom && nd->getstrid() == frst) { fromend = nd; fromend->addAdjacentEdge(thedg); thedg->from = fromend -> getnodeid(); thedg->setFrom(fromend); foundfrom = true; } if (!foundto && nd->getstrid() == tostr) { toend = nd; thedg->setTo(toend); toend->addAdjacentEdge(thedg); thedg->to = toend -> getnodeid(); foundto = true; } if(foundto && foundfrom){ fromend -> addAdjacentNode(toend); toend->addAdjacentNode(fromend); break; } } } //change labels to be the first letters for (int a=0; a<adjlist.size(); a++) { string lab = adjlist.at(a)->getLabel(); istringstream iss(lab); vector<string> names; do { string sub; iss >> sub; names.push_back(sub); //cout << "Substring: " << sub << endl; } while (iss); //form the new string string newlabel; newlabel += names[0].substr(0,1); newlabel += names[1].substr(0,1); /* for(int i=0; i<names.size(); i++){ newlabel += names[i].substr(0, 1); } */ adjlist.at(a)->setShortLabel(newlabel); //printf("old label: %s, new label: %s \n", lab.c_str(), newlabel.c_str()); } ramdomizePositions(false); //since author graph has no initial positions // we have to assign positions }
//엣지를 추가한다. void SparseGraph::AddEdge(GraphEdge edge) { //엣지의 양끝이 유효한 노드인지 확인한다. assert((edge.GetFrom() < m_iNextNodeIndex) && (edge.GetTo() < m_iNextNodeIndex) && "<SparseGraph::AddEdge>: invalid node index"); //유효한 노드이면 if ((m_Nodes[edge.GetTo()].GetIndex() != -1) && (m_Nodes[edge.GetFrom()].GetIndex() != -1)) { //유니크한 엣지인지 확인한다. if (UniqueEdge(edge.GetFrom(), edge.GetTo())) { m_Edges[edge.GetFrom()].push_back(edge); } //거꾸로 방향도 확인한다. if (UniqueEdge(edge.GetTo(), edge.GetFrom())) { GraphEdge NewEdge = edge; NewEdge.SetTo(edge.GetFrom()); NewEdge.SetFrom(edge.GetTo()); m_Edges[edge.GetTo()].push_back(NewEdge); } } }
void GraphView::addEdgeCommand(bool undirected) { if (edgeSource) { GraphNode* edgeDestination = dynamic_cast<GraphNode*>(selectedItem); if (edgeDestination && edgeSource != edgeDestination) { GraphEdge* existingEdge = NULL; bool drawAsArc(false); QListIterator<GraphEdge*> it(edgeSource->getDestinationEdges()); while (it.hasNext() && !existingEdge) { GraphEdge* edge = it.next(); if (edge->getSourceNode() == edgeDestination) existingEdge = edge; } if (existingEdge) { if (!existingEdge->isUndirected()) { if (weightedGraph && !undirectedGraph && currentAction == ADD_DIRECTED_EDGE) { existingEdge->setDrawAsArc(true); drawAsArc = true; existingEdge = NULL; } else undoStack->push(new ChangeEdgeDirectionCommand(existingEdge, false, true)); } } else { it = QListIterator<GraphEdge*>(edgeSource->getSourceEdges()); while (it.hasNext() && !existingEdge) { GraphEdge* edge = it.next(); if (edge->getDestinationNode() == edgeDestination) { existingEdge = edge; if (currentAction == ADD_UNDIRECTED_EDGE) undoStack->push(new ChangeEdgeDirectionCommand(existingEdge, false, true)); } } } if (existingEdge) { scene()->removeItem(currentEdge); delete currentEdge; } else { currentEdge->setDestinationNode(edgeDestination); currentEdge->setDrawAsArc(drawAsArc); undoStack->push(new AddEdgeCommand(currentEdge, this)); } currentEdge = NULL; edgeSource = NULL; } } else if (selectedItem) { edgeSource = dynamic_cast<GraphNode*>(selectedItem); currentEdge = new GraphEdge(edgeSource, edgeSource->getCenter(), undirected, !undirectedGraph, weightedGraph, false); // Setting the Z value makes sure the selection of nodes are made correct currentEdge->setZValue(-1); scene()->addItem(currentEdge); } updateStatus(); }
void GraphView::executeContextMenu(const QPoint& menuPosition) { QMenu menu; GraphNode* node = dynamic_cast<GraphNode*>(selectedItem); GraphEdge* edge = dynamic_cast<GraphEdge*>(selectedItem); if (node) { QAction *changeLabelAction = menu.addAction("Change label"); QAction *deleteAction = menu.addAction("Delete vertex"); QAction *selectedAction = menu.exec(menuPosition); if (selectedAction == changeLabelAction) changeLabel(node); else if (selectedAction == deleteAction) removeItemCommand(node); } else if (edge){ QAction *changeWeightAction(NULL); if (weightedGraph) changeWeightAction = menu.addAction("Change weight"); QAction *changeDirectionSDAction(NULL); QAction *changeDirectionDSAction(NULL); QAction *changeUndirectedAction(NULL); if (!undirectedGraph) { QMenu *changeDirectionMenu = new QMenu("Change direction"); menu.addMenu(changeDirectionMenu); QString sourceLabel = edge->getSourceNode()->getLabel(); if (sourceLabel.isEmpty()) sourceLabel = "no_label"; QString destinationLabel = edge->getDestinationNode()->getLabel(); if (destinationLabel.isEmpty()) destinationLabel = "no_label"; changeDirectionSDAction = changeDirectionMenu->addAction(sourceLabel + " -> " + destinationLabel); changeDirectionDSAction = changeDirectionMenu->addAction(destinationLabel + " -> " + sourceLabel); changeUndirectedAction = changeDirectionMenu->addAction("Change to undirected"); if (edge->isUndirected()) changeUndirectedAction->setEnabled(false); else changeDirectionSDAction->setEnabled(false); } QAction *deleteAction = menu.addAction("Delete edge"); QAction *selectedAction = menu.exec(menuPosition); if (selectedAction) { if (selectedAction == deleteAction) removeItemCommand(edge); else if (selectedAction == changeWeightAction) changeWeight(edge); else if (selectedAction == changeDirectionSDAction) undoStack->push(new ChangeEdgeDirectionCommand(edge, false, false)); else if (selectedAction == changeDirectionDSAction) undoStack->push(new ChangeEdgeDirectionCommand(edge, true, false)); else if (selectedAction == changeUndirectedAction) undoStack->push(new ChangeEdgeDirectionCommand(edge, false, true)); } } }