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 + -
显示快捷键?