graphwidget.cpp
来自「This a source insight software in Linux.」· C++ 代码 · 共 1,093 行 · 第 1/2 页
CPP
1,093 行
* @param nY The vertical origin of the area to draw * @param nWidth The width of the area to draw * @param nHeight The height of the area to draw */void GraphWidget::drawContents(QPainter* pPainter, int nX, int nY, int nWidth, int nHeight){ // Draw the contents of the canvas QCanvasView::drawContents(pPainter, nX, nY, nWidth, nHeight); // Erase the canvas's area border if (canvas() != NULL) { QRect rect = canvas()->rect(); pPainter->setBrush(QBrush()); // Null brush pPainter->setPen(Config().getColor(KScopeConfig::GraphBack)); pPainter->drawRect(-1, -1, rect.width() + 2, rect.height() + 2); }}/** * Handles mouse clicks over the graph view. * @param pEvent Includes information on the mouse press event */void GraphWidget::contentsMousePressEvent(QMouseEvent* pEvent){ QPoint ptRealPos; QCanvasItemList il; QCanvasItemList::Iterator itr; QString sFunc; GraphNode* pNode; GraphEdge* pEdge; pNode = NULL; pEdge = NULL; // Handle right-clicks only if (pEvent->button() != Qt::RightButton) { QCanvasView::contentsMousePressEvent(pEvent); return; } // Take the zoom factor into consideration ptRealPos = pEvent->pos(); ptRealPos /= m_dZoom; // Check if an item was clicked il = canvas()->collisions(ptRealPos); for (itr = il.begin(); itr != il.end(); ++itr) { if (dynamic_cast<GraphNode*>(*itr) != NULL) pNode = dynamic_cast<GraphNode*>(*itr); else if (dynamic_cast<GraphEdge*>(*itr) != NULL) pEdge = dynamic_cast<GraphEdge*>(*itr); } // Handle clicks over different types of items if (pNode != NULL) { // Show a context menu for nodes showNodeMenu(pNode, pEvent->globalPos()); } else if (pEdge != NULL) { // Show a context menu for edges showEdgeMenu(pEdge, pEvent->globalPos()); } else { // Take the default action QCanvasView::contentsMousePressEvent(pEvent); }}/** * 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";}/** * Removes all edges attached to a function node at the given direction. * Any strongly connected components that are no longer connected to that * function are deleted. * @param pGraphNode The node for which to remove the edges * @param bOut true for outgoing edges, false for incoming */void GraphWidget::removeEdges(GraphNode* pNode, bool bOut){ QDictIterator<GraphNode> itr(m_dictNodes); // Remove the edges if (bOut) pNode->removeOutEdges(); else pNode->removeInEdges(); // Find all weakly connected components attached to this node pNode->dfs(); // Delete all unmarked nodes, reset marked ones while (itr.current()) { if (!(*itr)->dfsVisited()) { m_dictNodes.remove((*itr)->getFunc()); } else { (*itr)->dfsReset(); ++itr; } }}/** * Shows a popup menu for a node. * This menu is shown after a node has been right-clicked. * @param pNode The node for which to show the menu * @param ptPos The position of the menu */void GraphWidget::showNodeMenu(GraphNode* pNode, const QPoint& ptPos){ // Remember the node m_pMenuItem = pNode; // Show the popup menu. if (pNode->isMultiCall()) m_pMultiCallPopup->popup(ptPos); else m_pNodePopup->popup(ptPos);}/** * Shows a popup menu for an edge. * This menu is shown after an edge has been right-clicked. * @param pEdge The edge for which to show the menu * @param ptPos The position of the menu */void GraphWidget::showEdgeMenu(GraphEdge* pEdge, const QPoint& ptPos){ // Remember the edge m_pMenuItem = pEdge; // Show the popup menu. m_pEdgePopup->popup(ptPos);}void GraphWidget::slotRepaint(){ setUpdatesEnabled(true); canvas()->update();}/** * Adds an entry to the tree, as the child of the active item. * Called by a CscopeFrontend object, when a new entry was received in its * whole from the Cscope back-end process. The entry contains the data of a * function calling the function described by the active item. * @param pToken The first token in the entry */void GraphWidget::slotDataReady(FrontendToken* pToken){ CallData data; QString sFunc; // Get the file name data.m_sFile = pToken->getData(); pToken = pToken->getNext(); // Get the function name sFunc = pToken->getData(); pToken = pToken->getNext(); // Get the line number (do not accept global information on a call tree) data.m_sLine = pToken->getData(); if (data.m_sLine.toUInt() == 0) return; pToken = pToken->getNext(); // Get the line's text data.m_sText = pToken->getData(); // Determine the caller and the callee if (m_bCalled) { data.m_sCaller = m_sQueriedFunc; data.m_sCallee = sFunc; } else { data.m_sCaller = sFunc; data.m_sCallee = m_sQueriedFunc; } // Add the call to the graph addCall(data);}/** * Displays search progress information. * This slot is connected to the progress() signal emitted by a * CscopeFrontend object. * @param nProgress The current progress value * @param nTotal The expected final value */void GraphWidget::slotProgress(int nProgress, int nTotal){ m_progress.setProgress(nProgress, nTotal);}/** * Disables the expandability feature of an item, if no functions calling it * were found. * @param nRecords Number of records reported by the query */void GraphWidget::slotFinished(uint /*nRecords*/){ // Destroy the progress bar m_progress.finished(); // Redraw the graph draw();}/** * Adds a multiple call node when a query results in too many entries. * This slot is attached to the aborted() signal of the Cscope process. */void GraphWidget::slotAborted(){ addMultiCall(m_sQueriedFunc, m_bCalled);}/** * Shows functions called from the current function node. * This slot is connected to the "Show Called Functions" popup menu * action. */void GraphWidget::slotShowCalled(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Run a query for called functions m_sQueriedFunc = pNode->getFunc(); m_bCalled = true; m_pCscope->query(CscopeFrontend::Called, m_sQueriedFunc, Config().getGraphMaxNodeDegree());}/** * Shows a list of function calls from the current node. * The list is displayed in a query dialogue. The user can the select which * calls should be displayed in the graph. * This slot is connected to the "List Called Functions" popup menu * action. */void GraphWidget::slotListCalled(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; QueryViewDlg dlg; // Show the query view dialogue dlg.query(CscopeFrontend::Called, pNode->getFunc()); if (dlg.exec() != QDialog::Accepted) return; // The OK button was clicked, replace current calls with the listed ones removeEdges(pNode, true); QueryView::Iterator itr; CallData data; data.m_sCaller = pNode->getFunc(); // Add all listed calls for (itr = dlg.getIterator(); !itr.isEOF(); itr.next()) { data.m_sCallee = itr.getFunc(); data.m_sFile = itr.getFile(); data.m_sLine = itr.getLine(); data.m_sText = itr.getText(); addCall(data); } // Redraw the graph draw();}/** * Hides functions called from the current function node. * This slot is connected to the "Hide Called Functions" popup menu * action. */void GraphWidget::slotHideCalled(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Remove edges and redraw the graph removeEdges(pNode, true); draw();}/** * Shows functions calling tothe current function node. * This slot is connected to the "Show Calling Functions" popup menu * action. */void GraphWidget::slotShowCalling(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Run a query for called functions m_sQueriedFunc = pNode->getFunc(); m_bCalled = false; m_pCscope->query(CscopeFrontend::Calling, m_sQueriedFunc, Config().getGraphMaxNodeDegree());}/** * Shows a list of function calls to the current node. * The list is displayed in a query dialogue. The user can the select which * calls should be displayed in the graph. * This slot is connected to the "List Calling Functions" popup menu * action. */void GraphWidget::slotListCalling(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; QueryViewDlg dlg; // Show the query view dialogue dlg.query(CscopeFrontend::Calling, pNode->getFunc()); if (dlg.exec() != QDialog::Accepted) return; // The OK button was clicked, replace current calls with the listed ones removeEdges(pNode, false); QueryView::Iterator itr; CallData data; data.m_sCallee = pNode->getFunc(); // Add all listed calls for (itr = dlg.getIterator(); !itr.isEOF(); itr.next()) { data.m_sCaller = itr.getFunc(); data.m_sFile = itr.getFile(); data.m_sLine = itr.getLine(); data.m_sText = itr.getText(); addCall(data); } // Redraw the graph draw();}/** * Hides functions calling to the current function node. * This slot is connected to the "Hide CallingFunctions" popup menu * action. */void GraphWidget::slotHideCalling(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Remove edges and redraw the graph removeEdges(pNode, false); draw();}/** * Looks up the definition of the current function node. * This slot is connected to the "Find Definition" popup menu action. */void GraphWidget::slotFindDef(){ GraphNode* pNode; QueryViewDlg* pDlg; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Create a query view dialogue pDlg = new QueryViewDlg(QueryViewDlg::DestroyOnSelect, this); // Display a line when it is selected in the dialogue connect(pDlg, SIGNAL(lineRequested(const QString&, uint)), this, SIGNAL(lineRequested(const QString&, uint))); // Start the query pDlg->query(CscopeFrontend::Definition, pNode->getFunc());}/** * Deletes a node from the graph (alogn with all edges connected to this * node). * The node removed is the one over which the context menu was invoked. * This slot is connected to the "Remove" popup menu action. */void GraphWidget::slotRemoveNode(){ GraphNode* pNode; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Delete the node and redraw the graph. delete pNode; draw();}/** * Shows the list of calls that is represented by a single multi-call node. * This slot handles the "Details..." command of the multi-call node menu. */void GraphWidget::slotMultiCallDetails(){/* GraphNode* pNode; QString sFunc; uint nType; // Make sure the menu item is a node pNode = dynamic_cast<GraphNode*>(m_pMenuItem); if (pNode == NULL) return; // Get the required information from the node sFunc = GET_NODE_ATTR(pNode->getNode(), "kscope_multi_parent"); nType = IS_TRUE(GET_NODE_ATTR(pNode->getNode(), "kscope_multi_called")) ? CscopeFrontend::Called : CscopeFrontend::Calling; QueryViewDlg dlg; dlg.query(nType, sFunc); dlg.exec();*/}/** * 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) emit lineRequested(pEdge->getFile(), pEdge->getLine());}#include "graphwidget.moc"
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?