mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-310 - Graphing - Updated mouse handling to be consistent with other graph widgets.
This commit is contained in:
parent
956e8ef342
commit
d9a1c8906f
43 changed files with 1468 additions and 474 deletions
|
@ -443,6 +443,8 @@ src/main/help/help/topics/GhidraServer/GhidraServer.htm||GHIDRA||||END|
|
||||||
src/main/help/help/topics/Glossary/glossary.htm||GHIDRA||||END|
|
src/main/help/help/topics/Glossary/glossary.htm||GHIDRA||||END|
|
||||||
src/main/help/help/topics/Glossary/images/BigEndian.png||GHIDRA||reviewed||END|
|
src/main/help/help/topics/Glossary/images/BigEndian.png||GHIDRA||reviewed||END|
|
||||||
src/main/help/help/topics/Glossary/images/LittleEndian.png||GHIDRA||reviewed||END|
|
src/main/help/help/topics/Glossary/images/LittleEndian.png||GHIDRA||reviewed||END|
|
||||||
|
src/main/help/help/topics/Graph/GraphIntro.html||GHIDRA||||END|
|
||||||
|
src/main/help/help/topics/Graph/GraphServicesIntro.html||GHIDRA||||END|
|
||||||
src/main/help/help/topics/HeadlessAnalyzer/HeadlessAnalyzer.htm||GHIDRA||||END|
|
src/main/help/help/topics/HeadlessAnalyzer/HeadlessAnalyzer.htm||GHIDRA||||END|
|
||||||
src/main/help/help/topics/ImporterPlugin/images/About_pdb.png||GHIDRA||reviewed||END|
|
src/main/help/help/topics/ImporterPlugin/images/About_pdb.png||GHIDRA||reviewed||END|
|
||||||
src/main/help/help/topics/ImporterPlugin/images/BatchImportDialog.png||GHIDRA||||END|
|
src/main/help/help/topics/ImporterPlugin/images/BatchImportDialog.png||GHIDRA||||END|
|
||||||
|
|
|
@ -150,7 +150,9 @@
|
||||||
|
|
||||||
<tocdef id="FileSystem Browser" text="FileSystem Browser" target="help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html" />
|
<tocdef id="FileSystem Browser" text="FileSystem Browser" target="help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html" />
|
||||||
|
|
||||||
<tocdef id="Graphing" text="Graphing" />
|
<tocdef id="Graphing" text="Graphing" target="help/topics/Graph/GraphIntro.html">
|
||||||
|
<tocdef id="Graph Services" text="Graph Services" target="help/topics/Graph/GraphServicesIntro.html"/>
|
||||||
|
</tocdef>
|
||||||
|
|
||||||
<tocdef id="Program Tree" text="Program Tree" target="help/topics/ProgramTreePlugin/program_tree.htm" >
|
<tocdef id="Program Tree" text="Program Tree" target="help/topics/ProgramTreePlugin/program_tree.htm" >
|
||||||
<tocdef id="Folders and Fragments" sortgroup="a" text="Folders and Fragments" target="help/topics/ProgramTreePlugin/program_tree.htm#FoldersAndFragments" />
|
<tocdef id="Folders and Fragments" sortgroup="a" text="Folders and Fragments" target="help/topics/ProgramTreePlugin/program_tree.htm#FoldersAndFragments" />
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||||
|
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE>Graphing</TITLE>
|
||||||
|
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||||
|
</HEAD>
|
||||||
|
|
||||||
|
<BODY lang="EN-US">
|
||||||
|
|
||||||
|
|
||||||
|
<H1>Graphing</H1>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
This section contains all help related to the creation and display of Graphs. Content will
|
||||||
|
appear inside of this section as plugins are added. To see the available graph features,
|
||||||
|
see the <B>Graph</b> menu on the toolbar.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||||
|
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE>Graph Services</TITLE>
|
||||||
|
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||||
|
</HEAD>
|
||||||
|
|
||||||
|
<BODY lang="EN-US">
|
||||||
|
|
||||||
|
|
||||||
|
<H1>Graph Services</H1>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
This section contains all help related to the graph services that provide capabilities for
|
||||||
|
generated graphs, such as displaying and exporting. Content will appear inside of this '
|
||||||
|
section as plugins are added. To see the available graph features,
|
||||||
|
see the <B>Graph</b> menu on the toolbar.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -50,11 +50,9 @@
|
||||||
|
|
||||||
<tocroot>
|
<tocroot>
|
||||||
|
|
||||||
<tocref id="Graphing">
|
<tocref id="Graph Services">
|
||||||
<tocdef id="Graph Services" text="Graph Services">
|
|
||||||
<tocdef id="Default Graph Display" text="Default Graph Display" target="help/topics/GraphServices/GraphDisplay.htm" />
|
<tocdef id="Default Graph Display" text="Default Graph Display" target="help/topics/GraphServices/GraphDisplay.htm" />
|
||||||
<tocdef id="Exporting a Graph" text="Exporting a Graph" target="help/topics/GraphServices/GraphExport.htm" />
|
<tocdef id="Exporting a Graph" text="Exporting a Graph" target="help/topics/GraphServices/GraphExport.htm" />
|
||||||
</tocdef>
|
|
||||||
</tocref>
|
</tocref>
|
||||||
|
|
||||||
</tocroot>
|
</tocroot>
|
||||||
|
|
|
@ -5,103 +5,245 @@
|
||||||
<META name="generator" content=
|
<META name="generator" content=
|
||||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||||
|
|
||||||
<TITLE>Graphing</TITLE>
|
<TITLE>Graph Display</TITLE>
|
||||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||||
</HEAD>
|
</HEAD>
|
||||||
|
|
||||||
<BODY lang="EN-US">
|
<BODY lang="EN-US">
|
||||||
<A name="Default_Graph_Display"/>
|
<A name="Default_Graph_Display">
|
||||||
|
|
||||||
|
|
||||||
<H1>Default Graph Display</H1>
|
<H1>Default Graph Display</H1>
|
||||||
<H2>Visualization of a Graph</H2>
|
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The visualization display will show the graph in a new window or in a new tab of a previously created graph window.</P>
|
<P>The visualization display will show the graph in a new window or in a new tab of a
|
||||||
<BLOCKQUOTE>
|
previously created graph window.</P>
|
||||||
<BLOCKQUOTE>
|
|
||||||
<P align="left"><IMG src="images/DefaultGraphDisplay.png" border="1"></P>
|
<CENTER>
|
||||||
|
<TABLE border="0" width="100%">
|
||||||
|
<TR>
|
||||||
|
<TD width="100%" align="center"><IMG alt="" border="1" src=
|
||||||
|
"images/DefaultGraphDisplay.png"></TD>
|
||||||
|
</TR>
|
||||||
|
</TABLE>
|
||||||
|
</CENTER>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
|
||||||
</BLOCKQUOTE>
|
<H2>Manipulating the Graph</H2>
|
||||||
<H2>Manipulating the Graph:</H2>
|
|
||||||
<ul>
|
<UL>
|
||||||
<li>MouseButton1+drag will translate the display in the x and y axis</li>
|
<LI>Dragging in the graph or on any unselected vertices will pan the graph (translate the
|
||||||
<li>Mouse Wheel will zoom in and out</li>
|
display in the x and y axis)</LI>
|
||||||
<li>CTRL+Mouse Wheel will zoom in and out in the X-Axis only</li>
|
|
||||||
<li>ALT+Mouse Wheel will zoom in and out in the Y-Axis only</li>
|
<LI>Dragging a selected vertex will reposition all selected vertices</LI>
|
||||||
<li>Ctrl+MouseButton1 will select a vertex or edge</li>
|
|
||||||
<ul>
|
<LI>Using the <CODE>Mouse Wheel</CODE> will zoom the graph in and out</LI>
|
||||||
<li>Shift+Ctrl+MouseButton1 over an unselected vertex will add that vertex to the selection</li>
|
|
||||||
<li>Shift+Ctrl+MouseButton1 over a previously selected vertex will remove that vertex from the selection</li>
|
<LI><CODE>Control+Mouse Wheel</CODE> will zoom the graph in and out on the X-Axis only</LI>
|
||||||
</ul>
|
|
||||||
<li>Ctrl+MouseButton1+drag on an empty area will create a rectangular area and select enclosed vertices</li>
|
<LI><CODE>ALT+Mouse Wheel</CODE> will zoom the graph in and out in the Y-Axis only</LI>
|
||||||
<li>Ctrl+MouseButton1+drag over a vertex will reposition all selected vertices</li>
|
|
||||||
</ul>
|
<LI><CODE>Ctrl+Click</CODE> will select a vertex
|
||||||
|
<UL>
|
||||||
|
<LI><CODE>Ctrl+Click</CODE> over an unselected vertex will add that vertex to the
|
||||||
|
selection</LI>
|
||||||
|
|
||||||
|
<LI><CODE>Ctrl+Click</CODE> over a previously selected vertex will remove that vertex
|
||||||
|
from the selection</LI>
|
||||||
|
</UL>
|
||||||
|
</LI>
|
||||||
|
|
||||||
|
<LI><CODE>Ctrl+drag</CODE> on an empty area will create a rectangular area and select
|
||||||
|
enclosed vertices</LI>
|
||||||
|
|
||||||
|
|
||||||
|
</UL>
|
||||||
|
|
||||||
<H2>Toolbar Buttons</H2>
|
<H2>Toolbar Buttons</H2>
|
||||||
<P><A name="Scroll_To_Selection"/> The <IMG src="images/locationIn.gif"> toggle button, when 'set' will cause a focused vertex (red arrow) to be scrolled to the center of the view</P>
|
|
||||||
<P><A name="Free_Form_Selection"/>The <IMG src="images/Lasso.png" width="16" height="16"> toggle button, when 'set' will allow the user to draw a free-form shape that encloses the vertices they wish to select.</P>
|
|
||||||
<P><A name="SatelliteView"/>The <IMG src="images/sat2.png" width="16" height="16"> toggle button, when 'set' will open a satellite mini view of the graph in the lower right corner. The mini-view can be manipulated with the mouse to affect the main view</P>
|
|
||||||
<P><A name="Reset_View"/>The <IMG src="images/reload3.png"> button will reset any visual transformations on the graph and center it at a best-effort size</P>
|
|
||||||
<P><A name="View_Magnifier"/>The <IMG src="images/magnifier.png"> toggle button, when 'set' will open a rectangular magnification lens in the graph view</P>
|
|
||||||
<BLOCKQUOTE><BLOCKQUOTE>
|
|
||||||
<ul>
|
|
||||||
<li>MouseButton1 click-drag on the lens center circle to move the magnifier lens</li>
|
|
||||||
<li>MouseButton1 click-draw on a lens edge diamond to resize the magnifier lens </li>
|
|
||||||
<li>MouseButton1 click on the upper-right circle-cross to dispose of the magnifier lens</li>
|
|
||||||
<li>MouseWheel will change the magnification of the lens</li>
|
|
||||||
</ul>
|
|
||||||
</BLOCKQUOTE></BLOCKQUOTE>
|
|
||||||
|
|
||||||
<P><A name="Show_Filters"/>The <IMG src="images/filter_on.png"> button will open a Filter dialog. Select buttons in the dialog to hide specific vertices or edges in the display.
|
<P><A name="Scroll_To_Selection">
|
||||||
The Filter dialog buttons are created by examining the graph vertex/edge properties to discover candidates for filtering.</P></BLOCKQUOTE></BLOCKQUOTE>
|
The <IMG alt="" src="images/locationIn.gif"> toggle button, when 'set' will cause a focused
|
||||||
|
vertex (the vertex with the red arrow) to be moved to the center of the view</P>
|
||||||
|
|
||||||
<P><A name="Arrangement"/>The <IMG src="images/katomic.png" width="16" height="16"> Arrangement menu is used to select one of several graph layout algorithms.</P>
|
<P><A name="Free_Form_Selection">
|
||||||
<BLOCKQUOTE><BLOCKQUOTE>
|
The <IMG alt="" src="images/Lasso.png" width="16" height="16"> toggle button, when 'set' will
|
||||||
|
allow the user to draw a free-form shape that encloses the vertices they wish to select.</P>
|
||||||
|
|
||||||
<ul>
|
<P><A name="SatelliteView">
|
||||||
<li><A name="Compact_Hierarchical"/><B>Compact Hierarchical</B> is the <b>TidierTree Layout Algorithm</b>. It builds a tree structure and attempts to reduce horizontal space.</li>
|
The <IMG alt="" src="images/network-wireless-16.png" width="16" height="16"> toggle button,
|
||||||
<li><A name="Hierarchical"/><B>Hierarchical</B> is a basic Tree algorithm. It prioritizes 'important' edges while constructing the tree.</li>
|
when 'set' will open a satellite mini view of the graph in the lower right corner. The
|
||||||
<li><A name="Compact Radial"/><B>Compact Radial</B> is the <b>TidierTree Layout Algorithm</b> with the root(s) at the center and child vertices radiating outwards.</li>
|
mini-view can be manipulated with the mouse to affect the main view</P>
|
||||||
<li><B>Hierarchical MinCross</B> is the <b>Sugiyama Layout Algorithm</b>. It attempts to route edges around vertices in order to reduce crossing.There are four layering algorithms:</li>
|
|
||||||
<ul>
|
<P><A name="Reset_View">
|
||||||
<li><A name="Hierarchical_MinCross_Top_Down"/><B>Top Down</B> - biases the vertices to the top</li>
|
The <IMG alt="" src="images/reload3.png"> button will reset any visual transformations on the
|
||||||
<li><A name="Hierarchical_MinCross_Longest_Path"/><B>Longest Path</B> - biases the vertices to the bottom</li>
|
graph and center it at a best-effort size</P>
|
||||||
<li><A name="Hierarchical_MinCross_Network_Simplex"/><B>Network Simplex</B> - layers after finding an 'optimal tree'</li>
|
|
||||||
<li><A name="Hierarchical_MinCross_Coffman_Graham"/><B>Coffman Graham</B> - biases the vertices using a scheduling algorithm to minimize length</li>
|
<P><A name="View_Magnifier">
|
||||||
</ul>
|
The <IMG alt="" src="images/magnifier.png"> toggle button, when 'set' will open a rectangular
|
||||||
|
magnification lens in the graph view</P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<UL>
|
||||||
|
<LI>MouseButton1 click-drag on the lens center circle to move the magnifier lens</LI>
|
||||||
|
|
||||||
|
<LI>MouseButton1 click-draw on a lens edge diamond to resize the magnifier lens</LI>
|
||||||
|
|
||||||
|
<LI>MouseButton1 click on the upper-right circle-cross to dispose of the magnifier
|
||||||
|
lens</LI>
|
||||||
|
|
||||||
|
<LI>MouseWheel will change the magnification of the lens</LI>
|
||||||
|
</UL>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P><A name="Show_Filters">
|
||||||
|
The <IMG alt="" src="Icons.CONFIGURE_FILTER_ICON"> button will open a Filter dialog. Select
|
||||||
|
buttons in the dialog to hide specific vertices or edges in the display. The Filter dialog
|
||||||
|
buttons are created by examining the graph vertex/edge properties to discover candidates for
|
||||||
|
filtering.</P>
|
||||||
|
|
||||||
|
<P><A name="Arrangement">
|
||||||
|
The <IMG alt="" src="images/katomic.png" width="16" height="16"> Arrangement menu is used to
|
||||||
|
select one of several graph layout algorithms.</P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<UL>
|
||||||
|
<LI><A name="Compact_Hierarchical">
|
||||||
|
<B>Compact Hierarchical</B> is the <B>TidierTree Layout Algorithm</B>. It builds a tree
|
||||||
|
structure and attempts to reduce horizontal space.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Hierarchical">
|
||||||
|
<B>Hierarchical</B> is a basic Tree algorithm. It prioritizes 'important' edges while
|
||||||
|
constructing the tree.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Compact Radial">
|
||||||
|
<B>Compact Radial</B> is the <B>TidierTree Layout Algorithm</B> with the root(s) at the
|
||||||
|
center and child vertices radiating outwards.</LI>
|
||||||
|
|
||||||
|
<LI><B>Hierarchical MinCross</B> is the <B>Sugiyama Layout Algorithm</B>. It attempts to
|
||||||
|
route edges around vertices in order to reduce crossing.There are four layering
|
||||||
|
algorithms:</LI>
|
||||||
|
|
||||||
|
<LI style="list-style: none">
|
||||||
|
<UL>
|
||||||
|
<LI><A name="Hierarchical_MinCross_Top_Down">
|
||||||
|
<B>Top Down</B> - biases the vertices to the top</LI>
|
||||||
|
|
||||||
|
<LI><A name="Hierarchical_MinCross_Longest_Path">
|
||||||
|
<B>Longest Path</B> - biases the vertices to the bottom</LI>
|
||||||
|
|
||||||
|
<LI><A name="Hierarchical_MinCross_Network_Simplex">
|
||||||
|
<B>Network Simplex</B> - layers after finding an 'optimal tree'</LI>
|
||||||
|
|
||||||
|
<LI><A name="Hierarchical_MinCross_Coffman_Graham">
|
||||||
|
<B>Coffman Graham</B> - biases the vertices using a scheduling algorithm to minimize
|
||||||
|
length</LI>
|
||||||
|
</UL>
|
||||||
|
</LI>
|
||||||
|
|
||||||
|
<LI><A name="Circle">
|
||||||
|
<B>Circle</B> will arrange vertices in a Circle. If there are not too many edges (less
|
||||||
|
than specified in the jungrapht.circle.reduceEdgeCrossingMaxEdges property with a default
|
||||||
|
of 200), it will attempt to reduce edge crossing by rearranging the vertices.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Force_Balanced">
|
||||||
|
<B>Force Balanced</B> is a <B>Force Directed Layout Algorithm</B> using the the <B>Kamada
|
||||||
|
Kawai</B> approach. It attempts to balance the graph by considering vertices and edge
|
||||||
|
connections.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Force_Directed">
|
||||||
|
<B>Force Directed</B> is a <B>Force Directed Layout Algorithm</B> using the
|
||||||
|
<B>Fructermann Reingold</B> approach. It pushes unconnected vertices apart and draws
|
||||||
|
connected vertices together.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Radial">
|
||||||
|
<B>Radial</B> is a Tree structure with the root(s) at the center and child vertices
|
||||||
|
radiating outwards.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Balloon">
|
||||||
|
<B>Balloon</B> is a Tree structure with the root(s) at the centers of circles in a radial
|
||||||
|
pattern</LI>
|
||||||
|
|
||||||
|
<LI><A name="Gem__Graph_Embedder_">
|
||||||
|
<B>GEM</B> is a Force Directed layout with locally separated components</LI>
|
||||||
|
</UL>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<li><A name="Circle"/><B>Circle</B> will arrange vertices in a Circle. If there are not too many edges (less than specified in the jungrapht.circle.reduceEdgeCrossingMaxEdges property with a default of 200), it will attempt to reduce edge crossing by rearranging the vertices.</li>
|
|
||||||
<li><A name="Force_Balanced"/><B>Force Balanced</B> is a <b>Force Directed Layout Algorithm</b> using the the <b>Kamada Kawai</b> approach. It attempts to balance the graph by considering vertices and edge connections.</li>
|
|
||||||
<li><A name="Force_Directed"/><B>Force Directed</B> is a <b>Force Directed Layout Algorithm</b> using the <b>Fructermann Reingold</b> approach. It pushes unconnected vertices apart and draws connected vertices together.</li>
|
|
||||||
<li><A name="Radial"/><B>Radial</B> is a Tree structure with the root(s) at the center and child vertices radiating outwards.</li>
|
|
||||||
<li><A name="Balloon"/><B>Balloon</B> is a Tree structure with the root(s) at the centers of circles in a radial pattern</li>
|
|
||||||
<li><A name="Gem__Graph_Embedder_"/><B>GEM</B> is a Force Directed layout with locally separated components </li>
|
|
||||||
</ul>
|
|
||||||
</BLOCKQUOTE></BLOCKQUOTE>
|
|
||||||
<H2>Popup Actions</H2>
|
<H2>Popup Actions</H2>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<H3>Standard Popup Actions</H3>
|
<H3>Standard Popup Actions</H3>
|
||||||
<ul>
|
|
||||||
<li><A name="Hide Selected"/><B>Hide Selected</B> - Causes the display to not show selected vertices. </li>
|
<UL>
|
||||||
<li><A name="Hide Unselected"/><B>Hide Unselected</B> - Causes the display to not show unselected vertices.</li>
|
<LI><A name="Hide_Selected">
|
||||||
<li><A name="Invert Selection"/><B>Invert Selection</B> - Unselects all selected nodes and selects all unselected nodes.</li>
|
<B>Hide Selected</B> - Causes the display to not show selected vertices.</LI>
|
||||||
<li><A name="Grow Selection From Sources"/><B>Grow Selection From Sources</B> - Adds to the selection all vertices that have outgoing edges to the current selection.</li>
|
|
||||||
<li><A name="Grow Selection To Targets"/><B>Grow Selection To Targets</B> - Adds to the selection all vertices that have incoming edges from the current selection.</li>
|
<LI><A name="Hide_Unselected">
|
||||||
<li><A name="Create Subgraph"/><B>Display Selected As New Graph</B> - Creates a new graph and display from the currently selected vertices.</li>
|
<B>Hide Unselected</B> - Causes the display to not show unselected vertices.</LI>
|
||||||
</ul>
|
|
||||||
|
<LI><A name="Invert_Selection">
|
||||||
|
<B>Invert Selection</B> - Unselects all selected nodes and selects all unselected
|
||||||
|
nodes.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Grow_Selection From Sources">
|
||||||
|
<B>Grow Selection From Sources</B> - Adds to the selection all vertices that have outgoing
|
||||||
|
edges to the current selection.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Grow_Selection To Targets">
|
||||||
|
<B>Grow Selection To Targets</B> - Adds to the selection all vertices that have incoming
|
||||||
|
edges from the current selection.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Clear_Selection">
|
||||||
|
<B>Clear Selection</B> - Clears all edge and vertex selection.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Create_Subgraph">
|
||||||
|
<B>Display Selected As New Graph</B> - Creates a new graph and display from the currently
|
||||||
|
selected vertices.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Display_Popup_Windows">
|
||||||
|
<B>Display Popup Windows</B> - When toggled off no tooltip popups will be displayed.</LI>
|
||||||
|
|
||||||
|
</UL>
|
||||||
|
|
||||||
<H3>Vertex Popup Actions</H3>
|
<H3>Vertex Popup Actions</H3>
|
||||||
<ul>
|
|
||||||
<li><A name="Select Vertex"/><B>Select Vertex</B> - Selects the vertex that this action was invoked on.</li>
|
<UL>
|
||||||
<li><A name="Deselect Vertex"/><B>Deselect Vertex</B> - Deselects the vertex that this action was invoked on.</li>
|
<LI><A name="Select_Vertex">
|
||||||
</ul>
|
<B>Select Vertex</B> - Selects the vertex that this action was invoked on.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Deselect_Vertex">
|
||||||
|
<B>Deselect Vertex</B> - Deselects the vertex that this action was invoked on.</LI>
|
||||||
|
</UL>
|
||||||
|
|
||||||
<H3>Edge Popup Actions</H3>
|
<H3>Edge Popup Actions</H3>
|
||||||
<ul>
|
|
||||||
<li><A name="Edge Source"/><B>Go To Edge Source</B> - Makes this edge's source vertex be the focused vertex.</li>
|
<UL>
|
||||||
<li><A name="Edge Target"/><B>Go To Edge Target</B> - Makes this edge's destination vertex be the focused vertex.</li>
|
<LI><A name="Edge_Source">
|
||||||
<li><A name="Select Edge"/><B>Select Edge</B> - Add this edge and its associated vertices to the selection</li>
|
<B>Go To Edge Source</B> - Makes this edge's source vertex be the focused vertex.</LI>
|
||||||
<li><A name="Deselect Edge"/><B>Deselect Edge</B> - Removes this edge and its associated vertices from the selection </li>
|
|
||||||
</ul>
|
<LI><A name="Edge_Target">
|
||||||
|
<B>Go To Edge Target</B> - Makes this edge's destination vertex be the focused vertex.</LI>
|
||||||
|
|
||||||
|
<LI><A name="Select_Edge">
|
||||||
|
<B>Select Edge</B> - Add this edge and its associated vertices to the selection</LI>
|
||||||
|
|
||||||
|
<LI><A name="Deselect_Edge">
|
||||||
|
<B>Deselect Edge</B> - Removes this edge and its associated vertices from the
|
||||||
|
selection</LI>
|
||||||
|
</UL>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P class="providedbyplugin">Provided By: <I>GraphDisplayBrokerPlugin</I></P>
|
||||||
|
|
||||||
|
<P class="relatedtopic">Related Topics:</P>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI><A href="help/topics/GraphServices/GraphExport.htm">Graph Export</A></LI>
|
||||||
|
</UL><BR>
|
||||||
|
<BR>
|
||||||
</BODY>
|
</BODY>
|
||||||
</HTML>
|
</HTML>
|
|
@ -11,19 +11,22 @@
|
||||||
</HEAD>
|
</HEAD>
|
||||||
|
|
||||||
<BODY lang="EN-US">
|
<BODY lang="EN-US">
|
||||||
<A name="Default Graph Exporter"/>
|
<A NAME="Graph_Exporter"/>
|
||||||
<H1>Graph Export Service</H1>
|
<H1>Graph Export Service</H1>
|
||||||
|
|
||||||
<H2> Export Dialog </H2>
|
<H2> Export Dialog </H2>
|
||||||
<P> Whenever a graph is generated and the graph output is set to <B>Graph Export</B>, then the
|
<P> Whenever a graph is generated and the graph output is set to <B>Graph Export</B>, then the
|
||||||
following graph export dialog is displayed: </P>
|
following graph export dialog is displayed: </P>
|
||||||
<BR>
|
<BR>
|
||||||
<BLOCKQUOTE>
|
|
||||||
<BLOCKQUOTE>
|
|
||||||
|
|
||||||
<P align="left"><IMG src="images/ExportDialog.png"></P>
|
<CENTER>
|
||||||
</BLOCKQUOTE>
|
<TABLE border="0" width="100%">
|
||||||
</BLOCKQUOTE>
|
<TR>
|
||||||
|
<TD width="100%" align="center"><IMG alt="" border="1" src=
|
||||||
|
"images/ExportDialog.png"></TD>
|
||||||
|
</TR>
|
||||||
|
</TABLE>
|
||||||
|
</CENTER>
|
||||||
<BR>
|
<BR>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The Export Graph dialog offers a choice of the following graph formats:</P>
|
<P>The Export Graph dialog offers a choice of the following graph formats:</P>
|
||||||
|
@ -49,5 +52,16 @@
|
||||||
<p>The <b>Ok</b> button will marshal the graph to the selected file in the selected format and close the dialog.</p>
|
<p>The <b>Ok</b> button will marshal the graph to the selected file in the selected format and close the dialog.</p>
|
||||||
<p>The <b>Cancel</b> button will close the dialog and perform no other action.</p>
|
<p>The <b>Cancel</b> button will close the dialog and perform no other action.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<P class="providedbyplugin">Provided By: <I>GraphDisplayBrokerPlugin</I></P>
|
||||||
|
|
||||||
|
<P class="relatedtopic">Related Topics:</P>
|
||||||
|
<UL>
|
||||||
|
<LI><A href="help/topics/GraphServices/GraphDisplay.htm">Default Graph Display</A></LI>
|
||||||
|
</UL>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
|
||||||
</BODY>
|
</BODY>
|
||||||
</HTML>
|
</HTML>
|
Binary file not shown.
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 8.5 KiB |
|
@ -73,6 +73,6 @@ public class ExportAttributedGraphDisplayProvider implements GraphDisplayProvide
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HelpLocation getHelpLocation() {
|
public HelpLocation getHelpLocation() {
|
||||||
return new HelpLocation("GraphServices", "Default_Graph_Exporter");
|
return new HelpLocation("GraphServices", "Graph_Exporter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class GraphExporterDialog extends DialogComponentProvider {
|
||||||
addWorkPanel(buildWorkPanel());
|
addWorkPanel(buildWorkPanel());
|
||||||
addOKButton();
|
addOKButton();
|
||||||
addCancelButton();
|
addCancelButton();
|
||||||
setHelpLocation(new HelpLocation("ExporterPlugin", "Exporter_Dialog"));
|
setHelpLocation(new HelpLocation("GraphServices", "Graph_Exporter"));
|
||||||
validate();
|
validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,10 @@ final class DefaultDisplayGraphIcons {
|
||||||
private DefaultDisplayGraphIcons() {
|
private DefaultDisplayGraphIcons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Icon SATELLITE_VIEW_ICON = Icons.get("images/sat2.png");
|
public static final Icon SATELLITE_VIEW_ICON = Icons.get("images/network-wireless-16.png");
|
||||||
public static final Icon VIEW_MAGNIFIER_ICON = Icons.get("images/magnifier.png");
|
public static final Icon VIEW_MAGNIFIER_ICON = Icons.get("images/magnifier.png");
|
||||||
public static final Icon PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.png");
|
public static final Icon PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.png");
|
||||||
public static final Icon LAYOUT_ALGORITHM_ICON = Icons.get("images/katomic.png");
|
public static final Icon LAYOUT_ALGORITHM_ICON = Icons.get("images/katomic.png");
|
||||||
public static final Icon LASSO_ICON = Icons.get("images/Lasso.png");
|
public static final Icon LASSO_ICON = Icons.get("images/Lasso.png");
|
||||||
public static final Icon FILTER_ICON = Icons.get("images/filter_on.png");
|
public static final Icon FILTER_ICON = Icons.CONFIGURE_FILTER_ICON;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import java.awt.event.*;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -64,6 +63,8 @@ import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.graph.AttributeFilters;
|
import ghidra.graph.AttributeFilters;
|
||||||
import ghidra.graph.job.GraphJobRunner;
|
import ghidra.graph.job.GraphJobRunner;
|
||||||
import ghidra.graph.viewer.popup.*;
|
import ghidra.graph.viewer.popup.*;
|
||||||
|
import ghidra.graph.visualization.mouse.JgtPluggableGraphMouse;
|
||||||
|
import ghidra.graph.visualization.mouse.JgtUtils;
|
||||||
import ghidra.service.graph.*;
|
import ghidra.service.graph.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -76,19 +77,18 @@ import resources.Icons;
|
||||||
*/
|
*/
|
||||||
public class DefaultGraphDisplay implements GraphDisplay {
|
public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
public static final String FAVORED_EDGE = "Fall-Through";
|
private static final String ACTION_OWNER = "GraphServices";
|
||||||
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
|
|
||||||
public static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000);
|
|
||||||
public static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
|
|
||||||
|
|
||||||
Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
private static final String FAVORED_EDGE = "Fall-Through";
|
||||||
|
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
|
||||||
|
private static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000);
|
||||||
|
private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
|
||||||
|
|
||||||
|
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
||||||
|
|
||||||
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
/**
|
|
||||||
* the {@link Graph} to visualize
|
|
||||||
*/
|
|
||||||
private AttributedGraph graph;
|
private AttributedGraph graph;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,91 +97,64 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
private final int displayId;
|
private final int displayId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the delegate viewer to display the ProgramGraph
|
* The delegate viewer to display the ProgramGraph
|
||||||
*/
|
*/
|
||||||
private final VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
|
private final VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the {@link PluginTool}
|
* The {@link PluginTool}
|
||||||
*/
|
*/
|
||||||
private final PluginTool pluginTool;
|
private final PluginTool pluginTool;
|
||||||
|
|
||||||
/**
|
|
||||||
* the "owner name" for action - mainly affects default help location
|
|
||||||
*/
|
|
||||||
private final String actionOwnerName = "GraphServices";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* provides the component for the {@link GraphDisplay}
|
|
||||||
*/
|
|
||||||
private final DefaultGraphDisplayComponentProvider componentProvider;
|
private final DefaultGraphDisplayComponentProvider componentProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* whether to ensure the focused vertex is visible, scrolling if necessary
|
* Whether to ensure the focused vertex is visible, scrolling if necessary
|
||||||
* the visualization in order to center the selected vertex
|
* the visualization in order to center the selected vertex
|
||||||
* or the center of the set of selected vertices
|
* or the center of the set of selected vertices
|
||||||
*/
|
*/
|
||||||
private boolean ensureVertexIsVisible = false;
|
private boolean ensureVertexIsVisible = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* allows selection of various {@link LayoutAlgorithm} ('arrangements')
|
* Allows selection of various {@link LayoutAlgorithm} ('arrangements')
|
||||||
*/
|
*/
|
||||||
private final LayoutTransitionManager layoutTransitionManager;
|
private final LayoutTransitionManager layoutTransitionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provides graph displays for supplied graphs
|
* Provides graph displays for supplied graphs
|
||||||
*/
|
*/
|
||||||
private final DefaultGraphDisplayProvider graphDisplayProvider;
|
private final DefaultGraphDisplayProvider graphDisplayProvider;
|
||||||
/**
|
/**
|
||||||
* the vertex that has been nominated to be 'focused' in the graph display and listing
|
* the vertex that has been nominated to be 'focused' in the graph display and listing
|
||||||
*/
|
*/
|
||||||
private AttributedVertex focusedVertex;
|
private AttributedVertex focusedVertex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs animation jobs for updating the display
|
||||||
|
*/
|
||||||
private final GraphJobRunner jobRunner = new GraphJobRunner();
|
private final GraphJobRunner jobRunner = new GraphJobRunner();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a satellite view that shows in the lower left corner as a birds-eye view of the graph display
|
* a satellite view that shows in the lower left corner as a birds-eye view of the graph display
|
||||||
*/
|
*/
|
||||||
private final SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> satelliteViewer;
|
private final SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> satelliteViewer;
|
||||||
/**
|
|
||||||
* generated filters on edges
|
|
||||||
*/
|
|
||||||
private AttributeFilters edgeFilters;
|
|
||||||
/**
|
|
||||||
* generated filters on vertices
|
|
||||||
*/
|
|
||||||
private AttributeFilters vertexFilters;
|
|
||||||
/**
|
|
||||||
* a dialog populated with generated vertex/edge filters
|
|
||||||
*/
|
|
||||||
private FilterDialog filterDialog;
|
private FilterDialog filterDialog;
|
||||||
/**
|
private AttributeFilters edgeFilters;
|
||||||
* holds the vertex icons (instead of recomputing them)
|
private AttributeFilters vertexFilters;
|
||||||
*/
|
|
||||||
private GhidraIconCache iconCache;
|
private GhidraIconCache iconCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* multi-selection is done in a free-form traced shape instead of a rectangle
|
* Multi-selection is done in a free-form traced shape instead of a rectangle
|
||||||
*/
|
*/
|
||||||
private boolean freeFormSelection;
|
private boolean freeFormSelection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the popup
|
* Handles all mouse interaction
|
||||||
*/
|
*/
|
||||||
private GhidraGraphMouse graphMouse;
|
private JgtPluggableGraphMouse graphMouse;
|
||||||
|
|
||||||
/**
|
|
||||||
* Will accept a {@link Graph} and use it to create a new graph display in
|
|
||||||
* a new tab or new window
|
|
||||||
*/
|
|
||||||
Consumer<Graph<AttributedVertex, AttributedEdge>> subgraphConsumer = g -> {
|
|
||||||
|
|
||||||
AttributedGraph attributedGraph = new AttributedGraph();
|
|
||||||
g.vertexSet().forEach(attributedGraph::addVertex);
|
|
||||||
g.edgeSet().forEach(e -> {
|
|
||||||
AttributedVertex source = g.getEdgeSource(e);
|
|
||||||
AttributedVertex target = g.getEdgeTarget(e);
|
|
||||||
attributedGraph.addEdge(source, target, e);
|
|
||||||
});
|
|
||||||
displaySubGraph(attributedGraph);
|
|
||||||
};
|
|
||||||
private ToggleDockingAction hideSelectedAction;
|
private ToggleDockingAction hideSelectedAction;
|
||||||
private ToggleDockingAction hideUnselectedAction;
|
private ToggleDockingAction hideUnselectedAction;
|
||||||
private SwitchableSelectionItemListener switchableSelectionListener;
|
private SwitchableSelectionItemListener switchableSelectionListener;
|
||||||
|
@ -226,7 +199,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
.builder(viewer.getRenderContext().getVertexBoundsFunction())
|
.builder(viewer.getRenderContext().getVertexBoundsFunction())
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
graphMouse = new GhidraGraphMouse(componentProvider, viewer);
|
graphMouse = new JgtPluggableGraphMouse(this);
|
||||||
|
|
||||||
createToolbarActions();
|
createToolbarActions();
|
||||||
createPopupActions();
|
createPopupActions();
|
||||||
|
@ -302,7 +275,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
private void createToolbarActions() {
|
private void createToolbarActions() {
|
||||||
|
|
||||||
// create a toggle for 'scroll to selected vertex'
|
// create a toggle for 'scroll to selected vertex'
|
||||||
new ToggleActionBuilder("Scroll To Selection", actionOwnerName)
|
new ToggleActionBuilder("Scroll To Selection", ACTION_OWNER)
|
||||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
||||||
.description("Ensure that the 'focused' vertex is visible")
|
.description("Ensure that the 'focused' vertex is visible")
|
||||||
.selected(true)
|
.selected(true)
|
||||||
|
@ -314,7 +287,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
// create a toggle for enabling 'free-form' selection: selection is
|
// create a toggle for enabling 'free-form' selection: selection is
|
||||||
// inside of a traced shape instead of a rectangle
|
// inside of a traced shape instead of a rectangle
|
||||||
new ToggleActionBuilder("Free-Form Selection", actionOwnerName)
|
new ToggleActionBuilder("Free-Form Selection", ACTION_OWNER)
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.LASSO_ICON)
|
.toolBarIcon(DefaultDisplayGraphIcons.LASSO_ICON)
|
||||||
.description("Trace Free-Form Shape to select multiple vertices (CTRL-click-drag)")
|
.description("Trace Free-Form Shape to select multiple vertices (CTRL-click-drag)")
|
||||||
.selected(false)
|
.selected(false)
|
||||||
|
@ -323,14 +296,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
// create an icon button to display the satellite view
|
// create an icon button to display the satellite view
|
||||||
new ToggleActionBuilder("SatelliteView", actionOwnerName).description("Show Satellite View")
|
new ToggleActionBuilder("SatelliteView", ACTION_OWNER).description("Show Satellite View")
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.SATELLITE_VIEW_ICON)
|
.toolBarIcon(DefaultDisplayGraphIcons.SATELLITE_VIEW_ICON)
|
||||||
.onAction(this::toggleSatellite)
|
.onAction(this::toggleSatellite)
|
||||||
.selected(graphDisplayProvider.getDefaultSatelliteState())
|
.selected(graphDisplayProvider.getDefaultSatelliteState())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
// create an icon button to reset the view transformations to identity (scaled to layout)
|
// create an icon button to reset the view transformations to identity (scaled to layout)
|
||||||
new ActionBuilder("Reset View", actionOwnerName)
|
new ActionBuilder("Reset View", ACTION_OWNER)
|
||||||
.description("Reset all view transforms to center graph in display")
|
.description("Reset all view transforms to center graph in display")
|
||||||
.toolBarIcon(Icons.REFRESH_ICON)
|
.toolBarIcon(Icons.REFRESH_ICON)
|
||||||
.onAction(context -> viewer.scaleToLayout())
|
.onAction(context -> viewer.scaleToLayout())
|
||||||
|
@ -338,7 +311,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
// create a button to show the view magnify lens
|
// create a button to show the view magnify lens
|
||||||
LensSupport<LensGraphMouse> magnifyViewSupport = createMagnifier();
|
LensSupport<LensGraphMouse> magnifyViewSupport = createMagnifier();
|
||||||
ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", actionOwnerName)
|
ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", ACTION_OWNER)
|
||||||
.description("Show View Magnifier")
|
.description("Show View Magnifier")
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.VIEW_MAGNIFIER_ICON)
|
.toolBarIcon(DefaultDisplayGraphIcons.VIEW_MAGNIFIER_ICON)
|
||||||
.onAction(context -> magnifyViewSupport.activate(
|
.onAction(context -> magnifyViewSupport.activate(
|
||||||
|
@ -349,90 +322,91 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
componentProvider.addLocalAction(lensToggle);
|
componentProvider.addLocalAction(lensToggle);
|
||||||
|
|
||||||
// create an action button to show a dialog with generated filters
|
// create an action button to show a dialog with generated filters
|
||||||
new ActionBuilder("Show Filters", actionOwnerName).description("Show Graph Filters")
|
new ActionBuilder("Show Filters", ACTION_OWNER).description("Show Graph Filters")
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.FILTER_ICON)
|
.toolBarIcon(DefaultDisplayGraphIcons.FILTER_ICON)
|
||||||
.onAction(context -> showFilterDialog())
|
.onAction(context -> showFilterDialog())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
// create a menu with graph layout algorithm selections
|
// create a menu with graph layout algorithm selections
|
||||||
new MultiStateActionBuilder<String>("Arrangement", actionOwnerName)
|
List<ActionState<String>> layoutActionStates = getLayoutActionStates();
|
||||||
.description("Select Layout Arrangement Algorithm")
|
new MultiStateActionBuilder<String>("Arrangement", ACTION_OWNER)
|
||||||
|
.description("Arrangement: " + layoutActionStates.get(0).getName())
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON)
|
.toolBarIcon(DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON)
|
||||||
.fireFirstAction(false)
|
.fireFirstAction(false)
|
||||||
.onActionStateChanged((s, t) -> layoutChanged(s.getName()))
|
.onActionStateChanged((s, t) -> layoutChanged(s.getName()))
|
||||||
.addStates(getLayoutActionStates())
|
.addStates(layoutActionStates)
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPopupActions() {
|
private void createPopupActions() {
|
||||||
new ActionBuilder("Select Vertex", actionOwnerName)
|
new ActionBuilder("Select Vertex", ACTION_OWNER)
|
||||||
.popupMenuPath("Select Vertex")
|
.popupMenuPath("Select Vertex")
|
||||||
.popupMenuGroup("selection", "1")
|
.popupMenuGroup("selection", "1")
|
||||||
.withContext(VertexGraphActionContext.class)
|
.withContext(VertexGraphActionContext.class)
|
||||||
.enabledWhen(c -> !viewer.getSelectedVertexState().isSelected(c.getClickedVertex()))
|
.enabledWhen(c -> !isSelected(c.getClickedVertex()))
|
||||||
.onAction(c -> viewer.getSelectedVertexState().select(c.getClickedVertex()))
|
.onAction(c -> viewer.getSelectedVertexState().select(c.getClickedVertex()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Deselect Vertex", actionOwnerName)
|
new ActionBuilder("Deselect Vertex", ACTION_OWNER)
|
||||||
.popupMenuPath("Deselect Vertex")
|
.popupMenuPath("Deselect Vertex")
|
||||||
.popupMenuGroup("selection", "2")
|
.popupMenuGroup("selection", "2")
|
||||||
.withContext(VertexGraphActionContext.class)
|
.withContext(VertexGraphActionContext.class)
|
||||||
.enabledWhen(c -> viewer.getSelectedVertexState().isSelected(c.getClickedVertex()))
|
.enabledWhen(c -> isSelected(c.getClickedVertex()))
|
||||||
.onAction(c -> viewer.getSelectedVertexState().deselect(c.getClickedVertex()))
|
.onAction(c -> viewer.getSelectedVertexState().deselect(c.getClickedVertex()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Select Edge", actionOwnerName)
|
new ActionBuilder("Select Edge", ACTION_OWNER)
|
||||||
.popupMenuPath("Select Edge")
|
.popupMenuPath("Select Edge")
|
||||||
.popupMenuGroup("selection", "1")
|
.popupMenuGroup("selection", "1")
|
||||||
.withContext(EdgeGraphActionContext.class)
|
.withContext(EdgeGraphActionContext.class)
|
||||||
.enabledWhen(c -> !viewer.getSelectedEdgeState().isSelected(c.getClickedEdge()))
|
.enabledWhen(c -> !isSelected(c.getClickedEdge()))
|
||||||
.onAction(c -> selectEdge(c.getClickedEdge()))
|
.onAction(c -> selectEdge(c.getClickedEdge()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Deselect Edge", actionOwnerName)
|
new ActionBuilder("Deselect Edge", ACTION_OWNER)
|
||||||
.popupMenuPath("Deselect Edge")
|
.popupMenuPath("Deselect Edge")
|
||||||
.popupMenuGroup("selection", "2")
|
.popupMenuGroup("selection", "2")
|
||||||
.withContext(EdgeGraphActionContext.class)
|
.withContext(EdgeGraphActionContext.class)
|
||||||
.enabledWhen(c -> viewer.getSelectedEdgeState().isSelected(c.getClickedEdge()))
|
.enabledWhen(c -> isSelected(c.getClickedEdge()))
|
||||||
.onAction(c -> deselectEdge(c.getClickedEdge()))
|
.onAction(c -> deselectEdge(c.getClickedEdge()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Edge Source", actionOwnerName)
|
new ActionBuilder("Edge Source", ACTION_OWNER)
|
||||||
.popupMenuPath("Go To Edge Source")
|
.popupMenuPath("Go To Edge Source")
|
||||||
.popupMenuGroup("Go To")
|
.popupMenuGroup("Go To")
|
||||||
.withContext(EdgeGraphActionContext.class)
|
.withContext(EdgeGraphActionContext.class)
|
||||||
.onAction(c -> setFocusedVertex(graph.getEdgeSource(c.getClickedEdge())))
|
.onAction(c -> setFocusedVertex(graph.getEdgeSource(c.getClickedEdge())))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Edge Target", actionOwnerName)
|
new ActionBuilder("Edge Target", ACTION_OWNER)
|
||||||
.popupMenuPath("Go To Edge Target")
|
.popupMenuPath("Go To Edge Target")
|
||||||
.popupMenuGroup("Go To")
|
.popupMenuGroup("Go To")
|
||||||
.withContext(EdgeGraphActionContext.class)
|
.withContext(EdgeGraphActionContext.class)
|
||||||
.onAction(c -> setFocusedVertex(graph.getEdgeTarget(c.getClickedEdge())))
|
.onAction(c -> setFocusedVertex(graph.getEdgeTarget(c.getClickedEdge())))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
hideSelectedAction = new ToggleActionBuilder("Hide Selected", actionOwnerName)
|
hideSelectedAction = new ToggleActionBuilder("Hide Selected", ACTION_OWNER)
|
||||||
.popupMenuPath("Hide Selected")
|
.popupMenuPath("Hide Selected")
|
||||||
.popupMenuGroup("z", "1")
|
.popupMenuGroup("z", "1")
|
||||||
.description("Toggles whether or not to show selected vertices and edges")
|
.description("Toggles whether or not to show selected vertices and edges")
|
||||||
.onAction(c -> manageVertexDisplay())
|
.onAction(c -> manageVertexDisplay())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", actionOwnerName)
|
hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", ACTION_OWNER)
|
||||||
.popupMenuPath("Hide Unselected")
|
.popupMenuPath("Hide Unselected")
|
||||||
.popupMenuGroup("z", "2")
|
.popupMenuGroup("z", "2")
|
||||||
.description("Toggles whether or not to show selected vertices and edges")
|
.description("Toggles whether or not to show selected vertices and edges")
|
||||||
.onAction(c -> manageVertexDisplay())
|
.onAction(c -> manageVertexDisplay())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Invert Selection", actionOwnerName)
|
new ActionBuilder("Invert Selection", ACTION_OWNER)
|
||||||
.popupMenuPath("Invert Selection")
|
.popupMenuPath("Invert Selection")
|
||||||
.popupMenuGroup("z", "3")
|
.popupMenuGroup("z", "3")
|
||||||
.description("Inverts the current selection")
|
.description("Inverts the current selection")
|
||||||
.onAction(c -> invertSelection())
|
.onAction(c -> invertSelection())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Grow Selection To Targets", actionOwnerName)
|
new ActionBuilder("Grow Selection To Targets", ACTION_OWNER)
|
||||||
.popupMenuPath("Grow Selection To Targets")
|
.popupMenuPath("Grow Selection To Targets")
|
||||||
.popupMenuGroup("z", "4")
|
.popupMenuGroup("z", "4")
|
||||||
.description("Extends the current selection by including the target vertex " +
|
.description("Extends the current selection by including the target vertex " +
|
||||||
|
@ -442,7 +416,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
.onAction(c -> growSelection(getTargetVerticesFromSelected()))
|
.onAction(c -> growSelection(getTargetVerticesFromSelected()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Grow Selection From Sources", actionOwnerName)
|
new ActionBuilder("Grow Selection From Sources", ACTION_OWNER)
|
||||||
.popupMenuPath("Grow Selection From Sources")
|
.popupMenuPath("Grow Selection From Sources")
|
||||||
.popupMenuGroup("z", "4")
|
.popupMenuGroup("z", "4")
|
||||||
.description("Extends the current selection by including the target vertex " +
|
.description("Extends the current selection by including the target vertex " +
|
||||||
|
@ -452,15 +426,23 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
.onAction(c -> growSelection(getSourceVerticesFromSelected()))
|
.onAction(c -> growSelection(getSourceVerticesFromSelected()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
new ActionBuilder("Create Subgraph", actionOwnerName)
|
new ActionBuilder("Clear Selection", ACTION_OWNER)
|
||||||
.popupMenuPath("Display Selected as New Graph")
|
.popupMenuPath("Clear Selection")
|
||||||
.popupMenuGroup("z", "5")
|
.popupMenuGroup("z", "5")
|
||||||
|
.keyBinding("escape")
|
||||||
|
.enabledWhen(c -> hasSelection())
|
||||||
|
.onAction(c -> clearSelection())
|
||||||
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
|
new ActionBuilder("Create Subgraph", ACTION_OWNER)
|
||||||
|
.popupMenuPath("Display Selected as New Graph")
|
||||||
|
.popupMenuGroup("zz", "5")
|
||||||
.description("Creates a subgraph from the selected nodes")
|
.description("Creates a subgraph from the selected nodes")
|
||||||
.enabledWhen(c -> !viewer.getSelectedVertexState().getSelected().isEmpty())
|
.enabledWhen(c -> !viewer.getSelectedVertexState().getSelected().isEmpty())
|
||||||
.onAction(c -> createAndDisplaySubGraph())
|
.onAction(c -> createAndDisplaySubGraph())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
togglePopupsAction = new ToggleActionBuilder("Display Popup Windows", actionOwnerName)
|
togglePopupsAction = new ToggleActionBuilder("Display Popup Windows", ACTION_OWNER)
|
||||||
.popupMenuPath("Display Popup Windows")
|
.popupMenuPath("Display Popup Windows")
|
||||||
.popupMenuGroup("zz", "1")
|
.popupMenuGroup("zz", "1")
|
||||||
.description("Toggles whether or not to show popup windows, such as tool tips")
|
.description("Toggles whether or not to show popup windows, such as tool tips")
|
||||||
|
@ -471,6 +453,24 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearSelection() {
|
||||||
|
viewer.getSelectedVertexState().clear();
|
||||||
|
viewer.getSelectedEdgeState().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasSelection() {
|
||||||
|
return !(viewer.getSelectedVertexState().getSelected().isEmpty() &&
|
||||||
|
viewer.getSelectedEdgeState().getSelected().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelected(AttributedVertex v) {
|
||||||
|
return viewer.getSelectedVertexState().isSelected(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelected(AttributedEdge e) {
|
||||||
|
return viewer.getSelectedEdgeState().isSelected(e);
|
||||||
|
}
|
||||||
|
|
||||||
private void createAndDisplaySubGraph() {
|
private void createAndDisplaySubGraph() {
|
||||||
GraphDisplay display = graphDisplayProvider.getGraphDisplay(false, TaskMonitor.DUMMY);
|
GraphDisplay display = graphDisplayProvider.getGraphDisplay(false, TaskMonitor.DUMMY);
|
||||||
try {
|
try {
|
||||||
|
@ -556,7 +556,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
for (String layoutName : names) {
|
for (String layoutName : names) {
|
||||||
ActionState<String> state = new ActionState<>(layoutName,
|
ActionState<String> state = new ActionState<>(layoutName,
|
||||||
DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON, layoutName);
|
DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON, layoutName);
|
||||||
state.setHelpLocation(new HelpLocation(actionOwnerName, layoutName));
|
state.setHelpLocation(new HelpLocation(ACTION_OWNER, layoutName));
|
||||||
actionStates.add(state);
|
actionStates.add(state);
|
||||||
}
|
}
|
||||||
return actionStates;
|
return actionStates;
|
||||||
|
@ -603,24 +603,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
viewer.repaint();
|
viewer.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displaySubGraph(Graph<AttributedVertex, AttributedEdge> subGraph) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
GraphDisplay graphDisplay =
|
|
||||||
graphDisplayProvider.getGraphDisplay(false, TaskMonitor.DUMMY);
|
|
||||||
graphDisplay.setGraph((AttributedGraph) subGraph, "SubGraph", false, TaskMonitor.DUMMY);
|
|
||||||
graphDisplay.setGraphDisplayListener(listener);
|
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
// can't happen while using a dummy monitor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a SatelliteViewer for the Visualization
|
|
||||||
* @param parentViewer the main visualization 'parent' of the satellite view
|
|
||||||
* @return a new SatelliteVisualizationViewer
|
|
||||||
*/
|
|
||||||
private SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> createSatelliteViewer(
|
private SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> createSatelliteViewer(
|
||||||
VisualizationViewer<AttributedVertex, AttributedEdge> parentViewer) {
|
VisualizationViewer<AttributedVertex, AttributedEdge> parentViewer) {
|
||||||
Dimension viewerSize = parentViewer.getSize();
|
Dimension viewerSize = parentViewer.getSize();
|
||||||
|
@ -649,9 +631,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
return satellite;
|
return satellite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* close this graph display
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
graphDisplayProvider.remove(this);
|
graphDisplayProvider.remove(this);
|
||||||
|
@ -662,10 +641,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
componentProvider.closeComponent();
|
componentProvider.closeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* accept a {@code GraphDisplayListener}
|
|
||||||
* @param listener the listener to be notified
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void setGraphDisplayListener(GraphDisplayListener listener) {
|
public void setGraphDisplayListener(GraphDisplayListener listener) {
|
||||||
if (this.listener != null) {
|
if (this.listener != null) {
|
||||||
|
@ -697,7 +672,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
viewer.getSelectedVertexState().addItemListener(switchableSelectionListener);
|
viewer.getSelectedVertexState().addItemListener(switchableSelectionListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setFocusedVertex(AttributedVertex vertex) {
|
public void setFocusedVertex(AttributedVertex vertex) {
|
||||||
setFocusedVertex(vertex, EventTrigger.API_CALL);
|
setFocusedVertex(vertex, EventTrigger.API_CALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,8 +983,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
return new Point2D.Double(p.x, p.y);
|
return new Point2D.Double(p.x, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// they did not pick a vertex to center, so
|
// they did not pick a vertex to center, so just center the graph
|
||||||
// just center the graph
|
|
||||||
Point2D center = viewer.getCenter();
|
Point2D center = viewer.getCenter();
|
||||||
Point p = Point.of(center.getX(), center.getY());
|
Point p = Point.of(center.getX(), center.getY());
|
||||||
return new Point2D.Double(p.x, p.y);
|
return new Point2D.Double(p.x, p.y);
|
||||||
|
@ -1211,13 +1185,13 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
|
|
||||||
public ActionContext getActionContext(MouseEvent e) {
|
public ActionContext getActionContext(MouseEvent e) {
|
||||||
|
|
||||||
AttributedVertex pickedVertex = graphMouse.getPickedVertex(e);
|
AttributedVertex pickedVertex = JgtUtils.getVertex(e, viewer);
|
||||||
if (pickedVertex != null) {
|
if (pickedVertex != null) {
|
||||||
return new VertexGraphActionContext(componentProvider, graph, getSelectedVertices(),
|
return new VertexGraphActionContext(componentProvider, graph, getSelectedVertices(),
|
||||||
focusedVertex, pickedVertex);
|
focusedVertex, pickedVertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributedEdge pickedEdge = graphMouse.getPickedEdge(e);
|
AttributedEdge pickedEdge = JgtUtils.getEdge(e, viewer);
|
||||||
if (pickedEdge != null) {
|
if (pickedEdge != null) {
|
||||||
return new EdgeGraphActionContext(componentProvider, graph, getSelectedVertices(),
|
return new EdgeGraphActionContext(componentProvider, graph, getSelectedVertices(),
|
||||||
focusedVertex, pickedEdge);
|
focusedVertex, pickedEdge);
|
||||||
|
|
|
@ -0,0 +1,311 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.event.*;
|
||||||
|
|
||||||
|
import org.jungrapht.visualization.SatelliteVisualizationViewer;
|
||||||
|
import org.jungrapht.visualization.VisualizationViewer;
|
||||||
|
import org.jungrapht.visualization.control.AbstractGraphMousePlugin;
|
||||||
|
import org.jungrapht.visualization.selection.MutableSelectedState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Graph mouse plugin base class.
|
||||||
|
*
|
||||||
|
* Usage Notes:
|
||||||
|
* <ul>
|
||||||
|
* <li>We clear state on mouseReleased() and mouseExited(), since we will get
|
||||||
|
* at least one of those calls</li>
|
||||||
|
* </ul>
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
*/
|
||||||
|
//@formatter:off
|
||||||
|
public abstract class AbstractJgtGraphMousePlugin<V, E>
|
||||||
|
extends AbstractGraphMousePlugin
|
||||||
|
implements MouseListener, MouseMotionListener {
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
protected boolean isHandlingMouseEvents;
|
||||||
|
|
||||||
|
protected V selectedVertex;
|
||||||
|
protected E selectedEdge;
|
||||||
|
|
||||||
|
public AbstractJgtGraphMousePlugin() {
|
||||||
|
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractJgtGraphMousePlugin(int selectionModifiers) {
|
||||||
|
super(selectionModifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VisualizationViewer<V, E> getViewer(MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = getGraphViewer(e);
|
||||||
|
return viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <b>primary/master</b> graph viewer.
|
||||||
|
*
|
||||||
|
* @param e the mouse event from which to get the viewer
|
||||||
|
* @return the viewer
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public VisualizationViewer<V, E> getGraphViewer(MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = (VisualizationViewer<V, E>) e.getSource();
|
||||||
|
|
||||||
|
// is this the satellite viewer?
|
||||||
|
if (viewer instanceof SatelliteVisualizationViewer) {
|
||||||
|
return ((SatelliteVisualizationViewer<V, E>) viewer).getMaster();
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the satellite graph viewer. This assumes that the mouse event originated from
|
||||||
|
* the satellite viewer.
|
||||||
|
*
|
||||||
|
* @param e the mouse event from which to get the viewer
|
||||||
|
* @return the viewer
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public SatelliteVisualizationViewer<V, E> getSatelliteGraphViewer(MouseEvent e) {
|
||||||
|
|
||||||
|
VisualizationViewer<V, E> viewer = (VisualizationViewer<V, E>) e.getSource();
|
||||||
|
|
||||||
|
// is this the satellite viewer?
|
||||||
|
if (viewer instanceof SatelliteVisualizationViewer) {
|
||||||
|
return (SatelliteVisualizationViewer<V, E>) viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Do not have a satellite GraphViewer");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals to perform any cleanup when this plugin is going away
|
||||||
|
*/
|
||||||
|
public void dispose() {
|
||||||
|
// stub
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the given mouse event to see if it is a valid event for selecting a vertex at the
|
||||||
|
* mouse location. If so, then the vertex is selected in this mouse handler and the event
|
||||||
|
* is consumed.
|
||||||
|
* @param e the event
|
||||||
|
* @return true if a vertex was selected
|
||||||
|
*/
|
||||||
|
protected boolean checkForVertex(MouseEvent e) {
|
||||||
|
if (!checkModifiers(e)) {
|
||||||
|
selectedVertex = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualizationViewer<V, E> vv = getViewer(e);
|
||||||
|
selectedVertex = JgtUtils.getVertex(e, vv);
|
||||||
|
if (selectedVertex == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.consume();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the given mouse event to see if it is a valid event for selecting an edge at the
|
||||||
|
* mouse location. If so, then the edge is selected in this mouse handler and the event
|
||||||
|
* is consumed.
|
||||||
|
* @param e the event
|
||||||
|
* @return true if an edge was selected
|
||||||
|
*/
|
||||||
|
protected boolean checkForEdge(MouseEvent e) {
|
||||||
|
if (!checkModifiers(e) || isOverVertex(e)) {
|
||||||
|
selectedEdge = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualizationViewer<V, E> vv = getViewer(e);
|
||||||
|
selectedEdge = JgtUtils.getEdge(e, vv);
|
||||||
|
if (selectedEdge == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.consume();
|
||||||
|
isHandlingMouseEvents = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the given vertex
|
||||||
|
* @param vertex the vertex
|
||||||
|
* @param viewer the graph viewer
|
||||||
|
* @return true if the vertex is selected
|
||||||
|
*/
|
||||||
|
protected boolean selectVertex(V vertex, VisualizationViewer<V, E> viewer) {
|
||||||
|
MutableSelectedState<V> selectedVertexState = viewer.getSelectedVertexState();
|
||||||
|
if (selectedVertexState == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedVertexState.isSelected(vertex);
|
||||||
|
|
||||||
|
if (selectedVertexState.isSelected(vertex) == false) {
|
||||||
|
selectedVertexState.clear();
|
||||||
|
selectedVertexState.select(vertex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the given edge
|
||||||
|
* @param edge the edge
|
||||||
|
* @param viewer the graph viewer
|
||||||
|
* @return true if the edge is selected
|
||||||
|
*/
|
||||||
|
protected boolean selectEdge(E edge, VisualizationViewer<V, E> viewer) {
|
||||||
|
|
||||||
|
MutableSelectedState<E> selectedVertexState = viewer.getSelectedEdgeState();
|
||||||
|
if (selectedVertexState == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedVertexState.isSelected(edge);
|
||||||
|
|
||||||
|
if (selectedVertexState.isSelected(edge) == false) {
|
||||||
|
selectedVertexState.clear();
|
||||||
|
selectedVertexState.select(edge, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the location of the mouse event is over a vertex
|
||||||
|
* @param e the event
|
||||||
|
* @return true if the location of the mouse event is over a vertex
|
||||||
|
*/
|
||||||
|
protected boolean isOverVertex(MouseEvent e) {
|
||||||
|
return getVertex(e) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the vertex if the mouse event is over a vertex
|
||||||
|
* @param e the event
|
||||||
|
* @return a vertex or null
|
||||||
|
*/
|
||||||
|
protected V getVertex(MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||||
|
return JgtUtils.getVertex(e, viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the location of the mouse event is over a edge
|
||||||
|
* @param e the event
|
||||||
|
* @return true if the location of the mouse event is over a edge
|
||||||
|
*/
|
||||||
|
protected boolean isOverEdge(MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||||
|
E edge = JgtUtils.getEdge(e, viewer);
|
||||||
|
if (edge == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isOverVertex(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void installCursor(Cursor newCursor, MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||||
|
viewer.setCursor(newCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldShowCursor(MouseEvent e) {
|
||||||
|
return isOverVertex(e); // to showing cursor over vertices
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
if (!checkModifiers(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// override this method to do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (!isHandlingMouseEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.consume();
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetState() {
|
||||||
|
isHandlingMouseEvents = false;
|
||||||
|
selectedVertex = null;
|
||||||
|
selectedEdge = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
if (!isHandlingMouseEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.consume();
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(MouseEvent e) {
|
||||||
|
if (isHandlingMouseEvents) {
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// only "turn on" the cursor; resetting is handled elsewhere (in the mouse driver)
|
||||||
|
if (shouldShowCursor(e)) {
|
||||||
|
installCursor(cursor, e);
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
if (isHandlingMouseEvents) {
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldShowCursor(e)) {
|
||||||
|
installCursor(cursor, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEntered(MouseEvent e) {
|
||||||
|
if (shouldShowCursor(e)) {
|
||||||
|
installCursor(cursor, e);
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(MouseEvent e) {
|
||||||
|
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseMotionListener;
|
||||||
|
|
||||||
|
import org.jungrapht.visualization.VisualizationViewer;
|
||||||
|
import org.jungrapht.visualization.control.AbstractGraphMousePlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the cursor after other graph mouse operations.
|
||||||
|
*
|
||||||
|
* Future: this is copied from the Visual Graph counterpart--consolidate these
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
*/
|
||||||
|
public class JgtCursorRestoringPlugin<V, E> extends AbstractGraphMousePlugin
|
||||||
|
implements MouseMotionListener {
|
||||||
|
|
||||||
|
public JgtCursorRestoringPlugin() {
|
||||||
|
super(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
// don't care
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(MouseEvent e) {
|
||||||
|
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void installCursor(Cursor newCursor, MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = (VisualizationViewer<V, E>) e.getSource();
|
||||||
|
viewer.setCursor(newCursor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jungrapht.visualization.VisualizationViewer;
|
||||||
|
import org.jungrapht.visualization.layout.model.Point;
|
||||||
|
import org.jungrapht.visualization.selection.MutableSelectedState;
|
||||||
|
|
||||||
|
import ghidra.graph.visualization.CenterAnimationJob;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mouse plugin to allow for edge navigation
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
*/
|
||||||
|
public class JgtEdgeNavigationPlugin<V, E> extends AbstractJgtGraphMousePlugin<V, E> {
|
||||||
|
|
||||||
|
public JgtEdgeNavigationPlugin() {
|
||||||
|
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
if (!checkModifiers(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.getClickCount() != 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForEdge(e); // this will select an edge if we can and store off the edge
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (!isHandlingMouseEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
E edge = selectedEdge; // save off before we reset
|
||||||
|
e.consume();
|
||||||
|
resetState();
|
||||||
|
|
||||||
|
// on double-clicks we go to the vertex in the current edge direction unless that vertex
|
||||||
|
// is already selected, then we go to the other vertex
|
||||||
|
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||||
|
MutableSelectedState<V> selectedState = viewer.getSelectedVertexState();
|
||||||
|
|
||||||
|
Graph<V, E> graph = viewer.getVisualizationModel().getGraph();
|
||||||
|
V end = graph.getEdgeTarget(edge);
|
||||||
|
if (!selectedState.isSelected(end)) {
|
||||||
|
pickAndShowVertex(end, selectedState, viewer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the destination was picked, go the other direction
|
||||||
|
V source = graph.getEdgeSource(edge);
|
||||||
|
pickAndShowVertex(source, selectedState, viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pickAndShowVertex(V vertex, MutableSelectedState<V> selectedVertexState,
|
||||||
|
VisualizationViewer<V, E> viewer) {
|
||||||
|
|
||||||
|
// TODO animate; this requires a single view updater
|
||||||
|
Point2D existingCenter = viewer.getRenderContext()
|
||||||
|
.getMultiLayerTransformer()
|
||||||
|
.inverseTransform(viewer.getCenter());
|
||||||
|
Point vp = viewer.getVisualizationModel().getLayoutModel().get(vertex);
|
||||||
|
Point2D newCenter = new Point2D.Double(vp.x, vp.y);
|
||||||
|
CenterAnimationJob job = new CenterAnimationJob(viewer, existingCenter, newCenter);
|
||||||
|
job.finished();
|
||||||
|
|
||||||
|
selectedVertexState.clear();
|
||||||
|
selectedVertexState.select(vertex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
VisualGraphViewUpdater<V, E> updater = viewer.getViewUpdater();
|
||||||
|
updater.moveVertexToCenterWithAnimation(vertex, isBusy -> {
|
||||||
|
|
||||||
|
// pick the vertex after the animation has run
|
||||||
|
if (!isBusy) {
|
||||||
|
GPickedState<V> pickedStateWrapper = (GPickedState<V>) selectedVertexState;
|
||||||
|
pickedStateWrapper.pickToActivate(vertex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldShowCursor(MouseEvent e) {
|
||||||
|
return isOverEdge(e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
|
||||||
|
import org.jungrapht.visualization.control.*;
|
||||||
|
|
||||||
|
import docking.DockingUtils;
|
||||||
|
import ghidra.graph.visualization.DefaultGraphDisplay;
|
||||||
|
import ghidra.service.graph.AttributedEdge;
|
||||||
|
import ghidra.service.graph.AttributedVertex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pluggable graph mouse for jungrapht
|
||||||
|
*/
|
||||||
|
public class JgtPluggableGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
||||||
|
|
||||||
|
private DefaultGraphDisplay graphDisplay;
|
||||||
|
|
||||||
|
// TODO we should not need the graph display for any mouse plugins, but the API is net yet
|
||||||
|
// robust enough to communicate fully without it
|
||||||
|
public JgtPluggableGraphMouse(DefaultGraphDisplay graphDisplay) {
|
||||||
|
super(DefaultGraphMouse.<AttributedVertex, AttributedEdge> builder());
|
||||||
|
this.graphDisplay = graphDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadPlugins() {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Note: the order of these additions matters, as an event will flow to each plugin until
|
||||||
|
// it is handled.
|
||||||
|
//
|
||||||
|
|
||||||
|
// edge
|
||||||
|
add(new JgtEdgeNavigationPlugin<AttributedVertex, AttributedEdge>());
|
||||||
|
|
||||||
|
add(new JgtVertexFocusingPlugin<AttributedVertex, AttributedEdge>(graphDisplay));
|
||||||
|
|
||||||
|
// scaling
|
||||||
|
add(new ScalingGraphMousePlugin(new CrossoverScalingControl(), 0, in, out));
|
||||||
|
|
||||||
|
// the grab/pan feature
|
||||||
|
add(new JgtTranslatingPlugin<AttributedVertex, AttributedEdge>());
|
||||||
|
|
||||||
|
add(new SelectingGraphMousePlugin<AttributedVertex, AttributedEdge>(
|
||||||
|
InputEvent.BUTTON1_DOWN_MASK,
|
||||||
|
0,
|
||||||
|
DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
||||||
|
|
||||||
|
// cursor cleanup
|
||||||
|
add(new JgtCursorRestoringPlugin<AttributedVertex, AttributedEdge>());
|
||||||
|
|
||||||
|
setPluginsLoaded();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
|
import org.jungrapht.visualization.*;
|
||||||
|
import org.jungrapht.visualization.MultiLayerTransformer.Layer;
|
||||||
|
import org.jungrapht.visualization.control.TranslatingGraphMousePlugin;
|
||||||
|
import org.jungrapht.visualization.transform.MutableTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: this class is based on {@link TranslatingGraphMousePlugin}.
|
||||||
|
* <p>
|
||||||
|
* TranslatingGraphMousePlugin uses a MouseButtonOne press and drag gesture to translate
|
||||||
|
* the graph display in the x and y direction. The default MouseButtonOne modifier can be overridden
|
||||||
|
* to cause a different mouse gesture to translate the display.
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
*/
|
||||||
|
public class JgtTranslatingPlugin<V, E>
|
||||||
|
extends AbstractJgtGraphMousePlugin<V, E> {
|
||||||
|
|
||||||
|
private boolean panning;
|
||||||
|
private boolean isHandlingEvent;
|
||||||
|
|
||||||
|
public JgtTranslatingPlugin() {
|
||||||
|
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JgtTranslatingPlugin(int modifiers) {
|
||||||
|
super(modifiers);
|
||||||
|
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
boolean accepted = checkModifiers(e) && isInDraggingArea(e);
|
||||||
|
if (!accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
down = e.getPoint();
|
||||||
|
VisualizationViewer<V, E> viewer = getGraphViewer(e);
|
||||||
|
viewer.setCursor(cursor);
|
||||||
|
isHandlingEvent = true;
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
boolean wasHandlingEvent = isHandlingEvent;
|
||||||
|
isHandlingEvent = false;
|
||||||
|
down = null;
|
||||||
|
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||||
|
|
||||||
|
// NOTE: we are only consuming the event here if we actually did pan...this allows follow-on
|
||||||
|
// mouse handlers to process the mouseReleased() event. This is a bit odd and not the
|
||||||
|
// normal event processing (which is to consume all related events).
|
||||||
|
if (wasHandlingEvent && panning) {
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
panning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
boolean accepted = checkModifiers(e);
|
||||||
|
if (!accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHandlingEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
panning = true;
|
||||||
|
|
||||||
|
VisualizationViewer<V, E> viewer = getGraphViewer(e);
|
||||||
|
RenderContext<V, E> context = viewer.getRenderContext();
|
||||||
|
MultiLayerTransformer multiLayerTransformer = context.getMultiLayerTransformer();
|
||||||
|
MutableTransformer layoutTransformer = multiLayerTransformer.getTransformer(Layer.LAYOUT);
|
||||||
|
viewer.setCursor(cursor);
|
||||||
|
Point2D downPoint = multiLayerTransformer.inverseTransform(down);
|
||||||
|
Point2D p = multiLayerTransformer.inverseTransform(e.getPoint());
|
||||||
|
float dx = (float) (p.getX() - downPoint.getX());
|
||||||
|
float dy = (float) (p.getY() - downPoint.getY());
|
||||||
|
|
||||||
|
layoutTransformer.translate(dx, dy);
|
||||||
|
down.x = e.getX();
|
||||||
|
down.y = e.getY();
|
||||||
|
e.consume();
|
||||||
|
viewer.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
// don't care
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEntered(MouseEvent e) {
|
||||||
|
if (isHandlingEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isInDraggingArea(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkModifiersForCursor(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
installCursor(cursor, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(MouseEvent e) {
|
||||||
|
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(MouseEvent e) {
|
||||||
|
if (!checkModifiersForCursor(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHandlingEvent) {
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInDraggingArea(e)) {
|
||||||
|
installCursor(cursor, e);
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkModifiersForCursor(MouseEvent e) {
|
||||||
|
if (e.getModifiersEx() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
// Private methods
|
||||||
|
//==================================================================================================
|
||||||
|
|
||||||
|
private boolean isInDraggingArea(MouseEvent e) {
|
||||||
|
return !(isOverVertex(e) || isOverEdge(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void installCursor(Cursor newCursor, MouseEvent e) {
|
||||||
|
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||||
|
viewer.setCursor(newCursor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.graph.visualization;
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
import static org.jungrapht.visualization.VisualizationServer.*;
|
import static org.jungrapht.visualization.VisualizationServer.*;
|
||||||
|
|
||||||
|
@ -22,42 +22,86 @@ import java.awt.geom.Point2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
|
||||||
import org.jungrapht.visualization.VisualizationViewer;
|
import org.jungrapht.visualization.VisualizationViewer;
|
||||||
import org.jungrapht.visualization.control.*;
|
import org.jungrapht.visualization.control.GraphElementAccessor;
|
||||||
|
import org.jungrapht.visualization.control.TransformSupport;
|
||||||
import org.jungrapht.visualization.layout.model.LayoutModel;
|
import org.jungrapht.visualization.layout.model.LayoutModel;
|
||||||
import org.jungrapht.visualization.selection.ShapePickSupport;
|
import org.jungrapht.visualization.selection.ShapePickSupport;
|
||||||
|
|
||||||
import docking.ComponentProvider;
|
|
||||||
import ghidra.service.graph.AttributedEdge;
|
|
||||||
import ghidra.service.graph.AttributedVertex;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An extension of the jungrapht DefaultGraphMouse. This class has references to
|
* Keeper of shared logic for jungrapht handling
|
||||||
* <ul>
|
|
||||||
* <li>a {@link VisualizationViewer} (to access the Graph and LayoutModel)
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class GhidraGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
public class JgtUtils {
|
||||||
|
|
||||||
private static final String PICK_AREA_SIZE_PROPERTY = PREFIX + "pickAreaSize";
|
private static final String PICK_AREA_SIZE_PROPERTY = PREFIX + "pickAreaSize";
|
||||||
|
|
||||||
private VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
|
|
||||||
|
|
||||||
private int pickSize;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create an instance with default values
|
* Returns the edge under the given mouse event
|
||||||
* @param componentProvider the graph component provider
|
*
|
||||||
* @param viewer the graph viewer component
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
* @param e the event
|
||||||
|
* @param viewer the graph viewer
|
||||||
|
* @return the edge
|
||||||
*/
|
*/
|
||||||
GhidraGraphMouse(ComponentProvider componentProvider,
|
public static <V, E> E getEdge(MouseEvent e, VisualizationViewer<V, E> viewer) {
|
||||||
VisualizationViewer<AttributedVertex, AttributedEdge> viewer) {
|
if (e == null) {
|
||||||
|
return null;
|
||||||
super(DefaultGraphMouse.<AttributedVertex, AttributedEdge> builder());
|
|
||||||
this.viewer = viewer;
|
|
||||||
pickSize = Integer.getInteger(GhidraGraphMouse.PICK_AREA_SIZE_PROPERTY, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rectangle2D getFootprint(MouseEvent e) {
|
Rectangle2D footprintRectangle = getFootprint(e);
|
||||||
|
LayoutModel<V> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
||||||
|
GraphElementAccessor<V, E> pickSupport = viewer.getPickSupport();
|
||||||
|
if (pickSupport == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pickSupport instanceof ShapePickSupport) {
|
||||||
|
ShapePickSupport<V, E> shapePickSupport =
|
||||||
|
(ShapePickSupport<V, E>) pickSupport;
|
||||||
|
return shapePickSupport.getEdge(layoutModel, footprintRectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformSupport<V, E> transformSupport =
|
||||||
|
viewer.getTransformSupport();
|
||||||
|
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
||||||
|
return pickSupport.getEdge(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the vertex under the given mouse event
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
* @param e the event
|
||||||
|
* @param viewer the graph viewer
|
||||||
|
* @return the vertex
|
||||||
|
*/
|
||||||
|
public static <V, E> V getVertex(MouseEvent e, VisualizationViewer<V, E> viewer) {
|
||||||
|
if (e == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle2D footprintRectangle = getFootprint(e);
|
||||||
|
LayoutModel<V> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
||||||
|
GraphElementAccessor<V, E> pickSupport = viewer.getPickSupport();
|
||||||
|
if (pickSupport == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pickSupport instanceof ShapePickSupport) {
|
||||||
|
ShapePickSupport<V, E> shapePickSupport =
|
||||||
|
(ShapePickSupport<V, E>) pickSupport;
|
||||||
|
return shapePickSupport.getVertex(layoutModel, footprintRectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformSupport<V, E> transformSupport =
|
||||||
|
viewer.getTransformSupport();
|
||||||
|
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
||||||
|
return pickSupport.getVertex(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rectangle2D getFootprint(MouseEvent e) {
|
||||||
|
int pickSize = Integer.getInteger(PICK_AREA_SIZE_PROPERTY, 4);
|
||||||
return new Rectangle2D.Float(
|
return new Rectangle2D.Float(
|
||||||
e.getPoint().x - pickSize / 2f,
|
e.getPoint().x - pickSize / 2f,
|
||||||
e.getPoint().y - pickSize / 2f,
|
e.getPoint().y - pickSize / 2f,
|
||||||
|
@ -65,44 +109,4 @@ public class GhidraGraphMouse extends DefaultGraphMouse<AttributedVertex, Attrib
|
||||||
pickSize);
|
pickSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributedEdge getPickedEdge(MouseEvent e) {
|
|
||||||
if (e == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Rectangle2D footprintRectangle = getFootprint(e);
|
|
||||||
LayoutModel<AttributedVertex> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
|
||||||
GraphElementAccessor<AttributedVertex, AttributedEdge> pickSupport =
|
|
||||||
viewer.getPickSupport();
|
|
||||||
if (pickSupport instanceof ShapePickSupport) {
|
|
||||||
ShapePickSupport<AttributedVertex, AttributedEdge> shapePickSupport =
|
|
||||||
(ShapePickSupport<AttributedVertex, AttributedEdge>) pickSupport;
|
|
||||||
return shapePickSupport.getEdge(layoutModel, footprintRectangle);
|
|
||||||
}
|
|
||||||
|
|
||||||
TransformSupport<AttributedVertex, AttributedEdge> transformSupport =
|
|
||||||
viewer.getTransformSupport();
|
|
||||||
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
|
||||||
return pickSupport.getEdge(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
AttributedVertex getPickedVertex(MouseEvent e) {
|
|
||||||
if (e == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Rectangle2D footprintRectangle = getFootprint(e);
|
|
||||||
LayoutModel<AttributedVertex> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
|
||||||
GraphElementAccessor<AttributedVertex, AttributedEdge> pickSupport =
|
|
||||||
viewer.getPickSupport();
|
|
||||||
if (pickSupport instanceof ShapePickSupport) {
|
|
||||||
ShapePickSupport<AttributedVertex, AttributedEdge> shapePickSupport =
|
|
||||||
(ShapePickSupport<AttributedVertex, AttributedEdge>) pickSupport;
|
|
||||||
return shapePickSupport.getVertex(layoutModel, footprintRectangle);
|
|
||||||
}
|
|
||||||
|
|
||||||
TransformSupport<AttributedVertex, AttributedEdge> transformSupport =
|
|
||||||
viewer.getTransformSupport();
|
|
||||||
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
|
||||||
return pickSupport.getVertex(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.graph.visualization.mouse;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
import ghidra.graph.visualization.DefaultGraphDisplay;
|
||||||
|
import ghidra.service.graph.AttributedVertex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mouse plugin to focus a vertex when clicked
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
|
*/
|
||||||
|
public class JgtVertexFocusingPlugin<V, E> extends AbstractJgtGraphMousePlugin<V, E> {
|
||||||
|
|
||||||
|
private DefaultGraphDisplay graphDisplay;
|
||||||
|
|
||||||
|
public JgtVertexFocusingPlugin(DefaultGraphDisplay graphDisplay) {
|
||||||
|
this.graphDisplay = graphDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
if (!checkModifiers(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedVertex = getVertex(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (selectedVertex == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphDisplay.setFocusedVertex((AttributedVertex) selectedVertex);
|
||||||
|
|
||||||
|
// Note: do not consume the event. We will just focus our vertex, regardless of further
|
||||||
|
// mouse event processing.
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,3 +62,10 @@ jungrapht.initialDimensionVertexDensity=0.3f
|
||||||
|
|
||||||
jungrapht.minScale=0.001
|
jungrapht.minScale=0.001
|
||||||
jungrapht.maxScale=1.0
|
jungrapht.maxScale=1.0
|
||||||
|
|
||||||
|
|
||||||
|
11:45 AM
|
||||||
|
|
||||||
|
# not using spatial data structures for edges (fixed in versions after 1.0)
|
||||||
|
jungrapht.edgeSpatialSupport=NONE
|
||||||
|
jungrapht.vertexSpatialSupport=NONE
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<BODY lang="EN-US">
|
<BODY lang="EN-US">
|
||||||
<H1>Graphing the Program</H1>
|
<H1>Graphing the Program</H1>
|
||||||
|
|
||||||
<H3>Graph Output</H3>
|
<H2>Graph Output</H2>
|
||||||
|
|
||||||
<P>To display or export a graph, Ghidra supports multiple graph services. Ghidra has two
|
<P>To display or export a graph, Ghidra supports multiple graph services. Ghidra has two
|
||||||
built-in graph services; one to display a graph and one to export a graph. Before invoking
|
built-in graph services; one to display a graph and one to export a graph. Before invoking
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
will direct the output of the graph function to the active graph service. To select a graph
|
will direct the output of the graph function to the active graph service. To select a graph
|
||||||
service, use the <B>Graph<IMG src="../../shared/arrow.gif">Graph Output</B></LI> menu.
|
service, use the <B>Graph<IMG src="../../shared/arrow.gif">Graph Output</B></LI> menu.
|
||||||
|
|
||||||
<H3>Graph types</H3>
|
<H2>Graph types</H2>
|
||||||
<P>Program control flow Graphs can be created and then shown using an appropriate graph service.
|
<P>Program control flow Graphs can be created and then shown using an appropriate graph service.
|
||||||
A control flow graph is a representation of the flow from one portion of the code to
|
A control flow graph is a representation of the flow from one portion of the code to
|
||||||
another. The nodes of the graph represent blocks of code and the edges represent flow between
|
another. The nodes of the graph represent blocks of code and the edges represent flow between
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
<P>Selection and Location events are synchronized between each
|
<P>Selection and Location events are synchronized between each
|
||||||
graph and the other windows in the tool.
|
graph and the other windows in the tool.
|
||||||
|
|
||||||
<H3>Selection</H3>
|
<H2>Selection</H2>
|
||||||
|
|
||||||
<P>The current selection within the graph display is represented by a red box around selected
|
<P>The current selection within the graph display is represented by a red box around selected
|
||||||
nodes as shown below on the node labeled "00408133". A node is selected if any addresses it represents are contained within the
|
nodes as shown below on the node labeled "00408133". A node is selected if any addresses it represents are contained within the
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
from the basic blocks found within the selected subroutine.</P>
|
from the basic blocks found within the selected subroutine.</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Location</H3>
|
<H2>Location</H2>
|
||||||
|
|
||||||
<P>The node containing the current address location is marked with a large red arrow as shown
|
<P>The node containing the current address location is marked with a large red arrow as shown
|
||||||
below on the graph node labeled "00408133".</P>
|
below on the graph node labeled "00408133".</P>
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
current address location within Ghidra to change to the minimum address represented by the
|
current address location within Ghidra to change to the minimum address represented by the
|
||||||
graph node.</P>
|
graph node.</P>
|
||||||
|
|
||||||
<H3>Graph Representation</H3>
|
<H2>Graph Representation</H2>
|
||||||
|
|
||||||
<P>By Default, the graphs use the following icons and colors to represent the nodes and edges.</P>
|
<P>By Default, the graphs use the following icons and colors to represent the nodes and edges.</P>
|
||||||
|
|
||||||
|
@ -220,98 +220,6 @@
|
||||||
</DIV>
|
</DIV>
|
||||||
</CENTER>
|
</CENTER>
|
||||||
|
|
||||||
<H2><A name="Graph_Block_Flow"></A>Block Flow Graph</H2>
|
|
||||||
|
|
||||||
<P>A Block Flow Graph consists of nodes that represent Basic blocks of contiguous instructions.
|
|
||||||
Basic blocks are broken up by any instruction that causes a change in execution flow. All Jump,
|
|
||||||
Call, Branch, and Return instructions can cause the execution flow to change. Arithmetic and
|
|
||||||
store/load instructions do not break a Basic block because they do not change the execution
|
|
||||||
flow. A labeled instruction will always start a block regardless of the instruction type.</P>
|
|
||||||
|
|
||||||
<P>For example:</P>
|
|
||||||
|
|
||||||
<P align="center"><IMG src="images/BasicBlockExampleCode.png"></P>
|
|
||||||
|
|
||||||
<P>Would generate the following graph:</P>
|
|
||||||
|
|
||||||
<P align="center"><IMG src="images/BasicBlockGraph.png">
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
|
||||||
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
|
||||||
will be restricted to blocks of code that fall within the selection.</P>
|
|
||||||
</BLOCKQUOTE>
|
|
||||||
|
|
||||||
<P>To Graph Block Flow Using the default model,</P>
|
|
||||||
|
|
||||||
<OL>
|
|
||||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Block Flow</B></LI>
|
|
||||||
|
|
||||||
<LI>A new graph window is created</LI>
|
|
||||||
</OL>
|
|
||||||
|
|
||||||
<H2><A name="Graph_Code_Flow"></A>Graph Code Flow</H2>
|
|
||||||
|
|
||||||
<P align="left">A Code Flow Graph is an extension of a <A href="#Graph_Block_Flow">Block Flow
|
|
||||||
Graph</A> in which each graph node (i.e., vertex) contains the list of instructions contained
|
|
||||||
within the associated block. The list of instructions are passed to the graph as the vertex
|
|
||||||
label.</P>
|
|
||||||
|
|
||||||
<P align="center"><BR>
|
|
||||||
<BR>
|
|
||||||
<IMG src="images/CodeBlockGraph.png"></P>
|
|
||||||
|
|
||||||
<H2><A name="Graph_Calls_Using_Default_Model"></A>Graph Calls</H2>
|
|
||||||
|
|
||||||
<P>A graph of the call instruction flow from one subroutine to another can be created with
|
|
||||||
<B>Graph<IMG src="../../shared/arrow.gif"> Calls</B>. The graph is created using the default
|
|
||||||
Call Model. Several Subroutine Models are available. Each model provides a slightly
|
|
||||||
different perspective on what constitutes a subroutine.</P>
|
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
|
||||||
<BLOCKQUOTE>
|
|
||||||
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
|
||||||
will be restricted to blocks of code that fall within the selection.</P>
|
|
||||||
</BLOCKQUOTE>
|
|
||||||
|
|
||||||
<P>To Graph Calls Using the default model,</P>
|
|
||||||
|
|
||||||
<OL>
|
|
||||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls</B></LI>
|
|
||||||
|
|
||||||
<LI>A new graph window is created</LI>
|
|
||||||
</OL>
|
|
||||||
|
|
||||||
<P><A name="Graph_Calls_Using_Model"></A>To Graph Calls Using a specific model*,</P>
|
|
||||||
|
|
||||||
<OL>
|
|
||||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls Using Model<IMG src=
|
|
||||||
"../../shared/arrow.gif"></B> <<I><B>a Call Model</B></I>></LI>
|
|
||||||
|
|
||||||
<LI>
|
|
||||||
Select one of
|
|
||||||
|
|
||||||
<UL>
|
|
||||||
<LI>Isolated Entry Model</LI>
|
|
||||||
|
|
||||||
<LI>Multiple Entry Model</LI>
|
|
||||||
|
|
||||||
<LI>Overlapped Code Model</LI>
|
|
||||||
|
|
||||||
<LI>Partitioned Code Model</LI>
|
|
||||||
</UL>
|
|
||||||
</LI>
|
|
||||||
|
|
||||||
<LI>A new graph window is created</LI>
|
|
||||||
</OL>
|
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
|
||||||
<P><IMG src="../../shared/note.png"> *For a more thorough description of each Call Block
|
|
||||||
Model (i.e., Subroutine Model), see <A href="help/topics/BlockModel/Block_Model.htm">Block
|
|
||||||
Models</A>. The specific list of models presented to the user may vary depending upon the
|
|
||||||
set of block models configured into the tool.</P>
|
|
||||||
</BLOCKQUOTE>
|
|
||||||
</BLOCKQUOTE>
|
|
||||||
|
|
||||||
<H2><A name="Reuse_Graph"></A>Reuse Graph</H2>
|
<H2><A name="Reuse_Graph"></A>Reuse Graph</H2>
|
||||||
|
|
||||||
|
@ -380,6 +288,123 @@
|
||||||
current address location changes.</P>
|
current address location changes.</P>
|
||||||
|
|
||||||
|
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
<HR WIDTH="90%">
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
|
||||||
|
<H2><A name="Graph_Block_Flow"></A>Block Flow Graph</H2>
|
||||||
|
|
||||||
|
<P>A Block Flow Graph consists of nodes that represent Basic blocks of contiguous instructions.
|
||||||
|
Basic blocks are broken up by any instruction that causes a change in execution flow. All Jump,
|
||||||
|
Call, Branch, and Return instructions can cause the execution flow to change. Arithmetic and
|
||||||
|
store/load instructions do not break a Basic block because they do not change the execution
|
||||||
|
flow. A labeled instruction will always start a block regardless of the instruction type.</P>
|
||||||
|
|
||||||
|
<P>For example:</P>
|
||||||
|
|
||||||
|
<P align="center"><IMG src="images/BasicBlockExampleCode.png"></P>
|
||||||
|
|
||||||
|
<P>Would generate the following graph:</P>
|
||||||
|
|
||||||
|
<P align="center"><IMG src="images/BasicBlockGraph.png">
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
||||||
|
will be restricted to blocks of code that fall within the selection.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P>To Graph Block Flow Using the default model,</P>
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Block Flow</B></LI>
|
||||||
|
|
||||||
|
<LI>A new graph window is created</LI>
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3><A NAME="Rename_Vertex"></A>Rename Vertex</H3>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>Allows the user to rename the symbol represented by the given vertex.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
<H2><A name="Graph_Code_Flow"></A>Graph Code Flow</H2>
|
||||||
|
|
||||||
|
<P align="left">A Code Flow Graph is an extension of a <A href="#Graph_Block_Flow">Block Flow
|
||||||
|
Graph</A> in which each graph node (i.e., vertex) contains the list of instructions contained
|
||||||
|
within the associated block. The list of instructions are passed to the graph as the vertex
|
||||||
|
label.</P>
|
||||||
|
|
||||||
|
<P align="center"><BR>
|
||||||
|
<BR>
|
||||||
|
<IMG src="images/CodeBlockGraph.png"></P>
|
||||||
|
|
||||||
|
<H2><A name="Graph_Calls_Using_Default_Model"></A>Graph Calls</H2>
|
||||||
|
|
||||||
|
<P>A graph of the call instruction flow from one subroutine to another can be created with
|
||||||
|
<B>Graph<IMG src="../../shared/arrow.gif"> Calls</B>. The graph is created using the default
|
||||||
|
Call Model. Several Subroutine Models are available. Each model provides a slightly
|
||||||
|
different perspective on what constitutes a subroutine.</P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
||||||
|
will be restricted to blocks of code that fall within the selection.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P>To Graph Calls Using the default model,</P>
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls</B></LI>
|
||||||
|
|
||||||
|
<LI>A new graph window is created</LI>
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
<P><A name="Graph_Calls_Using_Model"></A>To Graph Calls Using a specific model*,</P>
|
||||||
|
|
||||||
|
<OL>
|
||||||
|
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls Using Model<IMG src=
|
||||||
|
"../../shared/arrow.gif"></B> <<I><B>a Call Model</B></I>></LI>
|
||||||
|
|
||||||
|
<LI>
|
||||||
|
Select one of
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI>Isolated Entry Model</LI>
|
||||||
|
|
||||||
|
<LI>Multiple Entry Model</LI>
|
||||||
|
|
||||||
|
<LI>Overlapped Code Model</LI>
|
||||||
|
|
||||||
|
<LI>Partitioned Code Model</LI>
|
||||||
|
</UL>
|
||||||
|
</LI>
|
||||||
|
|
||||||
|
<LI>A new graph window is created</LI>
|
||||||
|
</OL>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><IMG src="../../shared/note.png"> *For a more thorough description of each Call Block
|
||||||
|
Model (i.e., Subroutine Model), see <A href="help/topics/BlockModel/Block_Model.htm">Block
|
||||||
|
Models</A>. The specific list of models presented to the user may vary depending upon the
|
||||||
|
set of block models configured into the tool.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
<BR>
|
<BR>
|
||||||
<BR>
|
<BR>
|
||||||
<BR>
|
<BR>
|
||||||
|
|
|
@ -26,6 +26,7 @@ import ghidra.program.model.block.*;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
import ghidra.program.model.symbol.SymbolTable;
|
||||||
import ghidra.service.graph.*;
|
import ghidra.service.graph.*;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
|
||||||
display.addAction(new ActionBuilder("Rename Vertex", "Block Graph")
|
display.addAction(new ActionBuilder("Rename Vertex", "Block Graph")
|
||||||
.popupMenuPath("Rename Vertex")
|
.popupMenuPath("Rename Vertex")
|
||||||
.withContext(VertexGraphActionContext.class)
|
.withContext(VertexGraphActionContext.class)
|
||||||
|
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename Vertex"))
|
||||||
// only enable action when vertex corresponds to an address
|
// only enable action when vertex corresponds to an address
|
||||||
.enabledWhen(c -> getAddress(c.getClickedVertex().getId()) != null)
|
.enabledWhen(c -> getAddress(c.getClickedVertex().getId()) != null)
|
||||||
.onAction(this::updateVertexName)
|
.onAction(this::updateVertexName)
|
||||||
|
|
|
@ -1128,9 +1128,13 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
|
|
||||||
private V selectedVertex;
|
private V selectedVertex;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // deprecated until we fix the checkModifiers() code
|
|
||||||
public VertexClickMousePlugin() {
|
public VertexClickMousePlugin() {
|
||||||
super(InputEvent.BUTTON1_MASK);
|
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1203,6 +1207,5 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
||||||
public void mouseExited(MouseEvent e) {
|
public void mouseExited(MouseEvent e) {
|
||||||
// stub
|
// stub
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ import ghidra.graph.viewer.*;
|
||||||
* <li>We clear state on mouseReleased() and mouseExited(), since we will get
|
* <li>We clear state on mouseReleased() and mouseExited(), since we will get
|
||||||
* at least one of those calls</li>
|
* at least one of those calls</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
*/
|
*/
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
public abstract class VisualGraphAbstractGraphMousePlugin<V extends VisualVertex,
|
public abstract class VisualGraphAbstractGraphMousePlugin<V extends VisualVertex,
|
||||||
|
@ -46,13 +49,18 @@ public abstract class VisualGraphAbstractGraphMousePlugin<V extends VisualVertex
|
||||||
protected E selectedEdge;
|
protected E selectedEdge;
|
||||||
|
|
||||||
public VisualGraphAbstractGraphMousePlugin() {
|
public VisualGraphAbstractGraphMousePlugin() {
|
||||||
this(InputEvent.BUTTON1_MASK);
|
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VisualGraphAbstractGraphMousePlugin(int selectionModifiers) {
|
public VisualGraphAbstractGraphMousePlugin(int selectionModifiers) {
|
||||||
super(selectionModifiers);
|
super(selectionModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean checkForVertex(MouseEvent e) {
|
protected boolean checkForVertex(MouseEvent e) {
|
||||||
if (!checkModifiers(e)) {
|
if (!checkModifiers(e)) {
|
||||||
selectedVertex = null;
|
selectedVertex = null;
|
||||||
|
|
|
@ -24,7 +24,10 @@ import edu.uci.ics.jung.visualization.control.AnimatedPickingGraphMousePlugin;
|
||||||
import ghidra.graph.viewer.*;
|
import ghidra.graph.viewer.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mouse handler to center a vertex when the header is double-clicked.
|
* A mouse handler to center a vertex when the header is double-clicked
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
*/
|
*/
|
||||||
public class VisualGraphAnimatedPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
public class VisualGraphAnimatedPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
extends AnimatedPickingGraphMousePlugin<V, E> implements VisualGraphMousePlugin<V, E> {
|
extends AnimatedPickingGraphMousePlugin<V, E> implements VisualGraphMousePlugin<V, E> {
|
||||||
|
@ -32,7 +35,7 @@ public class VisualGraphAnimatedPickingGraphMousePlugin<V extends VisualVertex,
|
||||||
private boolean isHandlingMouseEvents;
|
private boolean isHandlingMouseEvents;
|
||||||
|
|
||||||
public VisualGraphAnimatedPickingGraphMousePlugin() {
|
public VisualGraphAnimatedPickingGraphMousePlugin() {
|
||||||
super(InputEvent.BUTTON1_MASK);
|
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,17 @@ public class VisualGraphCursorRestoringGraphMousePlugin<V, E> extends AbstractGr
|
||||||
super(0);
|
super(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void mouseDragged(MouseEvent e) {
|
public void mouseDragged(MouseEvent e) {
|
||||||
// don't care
|
// don't care
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void mouseMoved(MouseEvent e) {
|
public void mouseMoved(MouseEvent e) {
|
||||||
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,9 +38,9 @@ public class VisualGraphEventForwardingGraphMousePlugin<V extends VisualVertex,
|
||||||
|
|
||||||
private boolean isHandlingEvent = false;
|
private boolean isHandlingEvent = false;
|
||||||
|
|
||||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
|
||||||
public VisualGraphEventForwardingGraphMousePlugin() {
|
public VisualGraphEventForwardingGraphMousePlugin() {
|
||||||
this(InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK);
|
this(InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON2_DOWN_MASK |
|
||||||
|
InputEvent.BUTTON3_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VisualGraphEventForwardingGraphMousePlugin(int modifiers) {
|
public VisualGraphEventForwardingGraphMousePlugin(int modifiers) {
|
||||||
|
@ -50,18 +50,18 @@ public class VisualGraphEventForwardingGraphMousePlugin<V extends VisualVertex,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkModifiers(MouseEvent e) {
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
int eventModifiers = e.getModifiers();
|
int eventModifiers = e.getModifiersEx();
|
||||||
eventModifiers = turnOffControlKey(eventModifiers);
|
eventModifiers = turnOffControlKey(eventModifiers);
|
||||||
return ((eventModifiers & getModifiers()) == eventModifiers);
|
return ((eventModifiers & getModifiers()) == eventModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int turnOffControlKey(int eventModifiers) {
|
private int turnOffControlKey(int eventModifiers) {
|
||||||
return eventModifiers & (~DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED);
|
return eventModifiers & (~DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isControlClick(MouseEvent e) {
|
private boolean isControlClick(MouseEvent e) {
|
||||||
int allModifiers = e.getModifiers();
|
int allModifiers = e.getModifiersEx();
|
||||||
int osSpecificMask = DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED;
|
int osSpecificMask = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||||
return (allModifiers & osSpecificMask) == osSpecificMask;
|
return (allModifiers & osSpecificMask) == osSpecificMask;
|
||||||
|
|
||||||
// can't use this until we fix the old modifiers usage
|
// can't use this until we fix the old modifiers usage
|
||||||
|
|
|
@ -61,6 +61,11 @@ public class VisualGraphHoverMousePlugin<V extends VisualVertex, E extends Visua
|
||||||
this.otherViewer = otherViewer;
|
this.otherViewer = otherViewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseMoved(MouseEvent e) {
|
public void mouseMoved(MouseEvent e) {
|
||||||
lastMouseEvent = e;
|
lastMouseEvent = e;
|
||||||
|
|
|
@ -28,7 +28,6 @@ import edu.uci.ics.jung.visualization.transform.MutableTransformer;
|
||||||
import ghidra.graph.viewer.*;
|
import ghidra.graph.viewer.*;
|
||||||
import ghidra.graph.viewer.renderer.*;
|
import ghidra.graph.viewer.renderer.*;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple plugin that allows clients to be notified of mouse events before any of the other
|
* A simple plugin that allows clients to be notified of mouse events before any of the other
|
||||||
* mouse plugins.
|
* mouse plugins.
|
||||||
|
@ -52,14 +51,15 @@ public class VisualGraphMouseTrackingGraphMousePlugin<V extends VisualVertex,
|
||||||
private int mouseMovedCount;
|
private int mouseMovedCount;
|
||||||
|
|
||||||
public VisualGraphMouseTrackingGraphMousePlugin(GraphViewer<V, E> viewer) {
|
public VisualGraphMouseTrackingGraphMousePlugin(GraphViewer<V, E> viewer) {
|
||||||
super(InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK);
|
super(InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON2_DOWN_MASK |
|
||||||
|
InputEvent.BUTTON3_DOWN_MASK);
|
||||||
this.viewer = Objects.requireNonNull(viewer);
|
this.viewer = Objects.requireNonNull(viewer);
|
||||||
viewer.addPostRenderPaintable(paintable);
|
viewer.addPostRenderPaintable(paintable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkModifiers(MouseEvent e) {
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
int eventModifiers = e.getModifiers();
|
int eventModifiers = e.getModifiersEx();
|
||||||
eventModifiers = turnOffControlKey(eventModifiers);
|
eventModifiers = turnOffControlKey(eventModifiers);
|
||||||
return ((eventModifiers & getModifiers()) == eventModifiers);
|
return ((eventModifiers & getModifiers()) == eventModifiers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -39,18 +38,17 @@ public class VisualGraphPickingGraphMousePlugin<V extends VisualVertex, E extend
|
||||||
// ALERT: -this class was created because mouseDragged() has a bug that generates a NPE
|
// ALERT: -this class was created because mouseDragged() has a bug that generates a NPE
|
||||||
// -also, mousePressed() has a bug in that it does not check the modifiers when the method is entered
|
// -also, mousePressed() has a bug in that it does not check the modifiers when the method is entered
|
||||||
|
|
||||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
|
||||||
public VisualGraphPickingGraphMousePlugin() {
|
public VisualGraphPickingGraphMousePlugin() {
|
||||||
super(InputEvent.BUTTON1_MASK,
|
super(InputEvent.BUTTON1_DOWN_MASK,
|
||||||
InputEvent.BUTTON1_MASK | DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED);
|
InputEvent.BUTTON1_DOWN_MASK | DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkModifiers(MouseEvent e) {
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
if (e.getModifiers() == addToSelectionModifiers) {
|
if (e.getModifiersEx() == addToSelectionModifiers) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.checkModifiers(e);
|
return e.getModifiersEx() == modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,7 +78,7 @@ public class VisualGraphPickingGraphMousePlugin<V extends VisualVertex, E extend
|
||||||
|
|
||||||
private void increaseDragRectangle(MouseEvent e) {
|
private void increaseDragRectangle(MouseEvent e) {
|
||||||
Point2D out = e.getPoint();
|
Point2D out = e.getPoint();
|
||||||
int theModifiers = e.getModifiers();
|
int theModifiers = e.getModifiersEx();
|
||||||
if (theModifiers == addToSelectionModifiers || theModifiers == modifiers) {
|
if (theModifiers == addToSelectionModifiers || theModifiers == modifiers) {
|
||||||
if (down != null) {
|
if (down != null) {
|
||||||
rect.setFrameFromDiagonal(down, out);
|
rect.setFrameFromDiagonal(down, out);
|
||||||
|
|
|
@ -29,7 +29,7 @@ public abstract class VisualGraphSatelliteAbstractGraphMousePlugin<V extends Vis
|
||||||
extends VisualGraphAbstractGraphMousePlugin<V, E> {
|
extends VisualGraphAbstractGraphMousePlugin<V, E> {
|
||||||
|
|
||||||
public VisualGraphSatelliteAbstractGraphMousePlugin() {
|
public VisualGraphSatelliteAbstractGraphMousePlugin() {
|
||||||
this(InputEvent.BUTTON1_MASK);
|
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VisualGraphSatelliteAbstractGraphMousePlugin(int selectionModifiers) {
|
public VisualGraphSatelliteAbstractGraphMousePlugin(int selectionModifiers) {
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.graph.viewer.event.mouse;
|
|
||||||
|
|
||||||
import ghidra.graph.viewer.VisualEdge;
|
|
||||||
import ghidra.graph.viewer.VisualVertex;
|
|
||||||
|
|
||||||
public class VisualGraphSatelliteAnimatedPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
|
||||||
extends VisualGraphAnimatedPickingGraphMousePlugin<V, E> {
|
|
||||||
|
|
||||||
// TODO - delete this class--it should not longer be needed
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package ghidra.graph.viewer.event.mouse;
|
|
||||||
|
|
||||||
import ghidra.graph.viewer.VisualEdge;
|
|
||||||
import ghidra.graph.viewer.VisualVertex;
|
|
||||||
|
|
||||||
public class VisualGraphSatelliteEdgeSelectionGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
|
||||||
extends VisualGraphEdgeSelectionGraphMousePlugin<V, E> {
|
|
||||||
|
|
||||||
// TODO this class probably can be deleted now
|
|
||||||
}
|
|
|
@ -25,7 +25,7 @@ public class VisualGraphSatelliteNavigationGraphMousePlugin<V extends VisualVert
|
||||||
extends VisualGraphSatelliteAbstractGraphMousePlugin<V, E> {
|
extends VisualGraphSatelliteAbstractGraphMousePlugin<V, E> {
|
||||||
|
|
||||||
public VisualGraphSatelliteNavigationGraphMousePlugin() {
|
public VisualGraphSatelliteNavigationGraphMousePlugin() {
|
||||||
super(InputEvent.BUTTON1_MASK);
|
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class VisualGraphSatelliteScalingGraphMousePlugin<V extends VisualVertex,
|
||||||
VisualGraphOptions options = viewer.getOptions();
|
VisualGraphOptions options = viewer.getOptions();
|
||||||
boolean scrollWheelPans = options.getScrollWheelPans();
|
boolean scrollWheelPans = options.getScrollWheelPans();
|
||||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||||
int eventModifiers = e.getModifiers();
|
int eventModifiers = e.getModifiersEx();
|
||||||
if (scrollWheelPans) {
|
if (scrollWheelPans) {
|
||||||
// scrolling will zoom if modified (unmodified in this case means to pan)
|
// scrolling will zoom if modified (unmodified in this case means to pan)
|
||||||
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;
|
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class VisualGraphSatelliteTranslatingGraphMousePlugin<V extends VisualVer
|
||||||
|
|
||||||
// Note: for ideas on resizing instead of moving, see LensTranslatingGraphMousePlugin
|
// Note: for ideas on resizing instead of moving, see LensTranslatingGraphMousePlugin
|
||||||
public VisualGraphSatelliteTranslatingGraphMousePlugin() {
|
public VisualGraphSatelliteTranslatingGraphMousePlugin() {
|
||||||
super(InputEvent.BUTTON1_MASK);
|
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||||
/**
|
/**
|
||||||
* Overridden implementation that allows us to change scaling behavior through options. This
|
* Overridden implementation that allows us to change scaling behavior through options. This
|
||||||
* class works on the opposite modifier setup as FunctionGraphScrollWheelPanningPlugin.
|
* class works on the opposite modifier setup as FunctionGraphScrollWheelPanningPlugin.
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
*/
|
*/
|
||||||
public class VisualGraphScalingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
public class VisualGraphScalingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
extends ScalingGraphMousePlugin implements VisualGraphMousePlugin<V, E> {
|
extends ScalingGraphMousePlugin implements VisualGraphMousePlugin<V, E> {
|
||||||
|
@ -51,8 +54,8 @@ public class VisualGraphScalingGraphMousePlugin<V extends VisualVertex, E extend
|
||||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
||||||
VisualGraphOptions options = viewer.getOptions();
|
VisualGraphOptions options = viewer.getOptions();
|
||||||
boolean scrollWheelPans = options.getScrollWheelPans();
|
boolean scrollWheelPans = options.getScrollWheelPans();
|
||||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED;
|
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||||
int eventModifiers = e.getModifiers();
|
int eventModifiers = e.getModifiersEx();
|
||||||
if (scrollWheelPans) {
|
if (scrollWheelPans) {
|
||||||
// scrolling will zoom if modified (unmodified in this case means to pan)
|
// scrolling will zoom if modified (unmodified in this case means to pan)
|
||||||
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;
|
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;
|
||||||
|
|
|
@ -16,8 +16,7 @@
|
||||||
package ghidra.graph.viewer.event.mouse;
|
package ghidra.graph.viewer.event.mouse;
|
||||||
|
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.*;
|
||||||
import java.awt.event.MouseWheelListener;
|
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
|
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
|
||||||
|
@ -31,9 +30,14 @@ public class VisualGraphScreenPositioningPlugin<V extends VisualVertex, E extend
|
||||||
super(0);
|
super(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
int eventModifiers = e.getModifiers();
|
int eventModifiers = e.getModifiersEx();
|
||||||
boolean controlKeyDown = (eventModifiers & DockingUtils.CONTROL_KEY_MODIFIER_MASK) != 0;
|
boolean controlKeyDown = (eventModifiers & DockingUtils.CONTROL_KEY_MODIFIER_MASK) != 0;
|
||||||
if (!controlKeyDown) {
|
if (!controlKeyDown) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,8 +16,7 @@
|
||||||
package ghidra.graph.viewer.event.mouse;
|
package ghidra.graph.viewer.event.mouse;
|
||||||
|
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.*;
|
||||||
import java.awt.event.MouseWheelListener;
|
|
||||||
|
|
||||||
import docking.DockingUtils;
|
import docking.DockingUtils;
|
||||||
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
|
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
|
||||||
|
@ -35,6 +34,11 @@ public class VisualGraphScrollWheelPanningPlugin<V extends VisualVertex,
|
||||||
super(0);
|
super(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
if (!isScrollModifiers(e)) {
|
if (!isScrollModifiers(e)) {
|
||||||
|
@ -91,7 +95,7 @@ public class VisualGraphScrollWheelPanningPlugin<V extends VisualVertex,
|
||||||
VisualGraphOptions options = viewer.getOptions();
|
VisualGraphOptions options = viewer.getOptions();
|
||||||
boolean scrollWheelPans = options.getScrollWheelPans();
|
boolean scrollWheelPans = options.getScrollWheelPans();
|
||||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||||
int eventModifiers = e.getModifiers();
|
int eventModifiers = e.getModifiersEx();
|
||||||
if (scrollWheelPans) {
|
if (scrollWheelPans) {
|
||||||
// scrolling will pan if *not* modified (modified in this case means to zoom)
|
// scrolling will pan if *not* modified (modified in this case means to zoom)
|
||||||
return !((scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle);
|
return !((scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle);
|
||||||
|
|
|
@ -33,8 +33,8 @@ import ghidra.graph.viewer.*;
|
||||||
* the graph display in the x and y direction. The default MouseButtonOne modifier can be overridden
|
* the graph display in the x and y direction. The default MouseButtonOne modifier can be overridden
|
||||||
* to cause a different mouse gesture to translate the display.
|
* to cause a different mouse gesture to translate the display.
|
||||||
*
|
*
|
||||||
*
|
* @param <V> the vertex type
|
||||||
*
|
* @param <E> the edge type
|
||||||
*/
|
*/
|
||||||
public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
extends AbstractGraphMousePlugin
|
extends AbstractGraphMousePlugin
|
||||||
|
@ -43,9 +43,8 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
|
||||||
private boolean panning;
|
private boolean panning;
|
||||||
private boolean isHandlingEvent;
|
private boolean isHandlingEvent;
|
||||||
|
|
||||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
|
||||||
public VisualGraphTranslatingGraphMousePlugin() {
|
public VisualGraphTranslatingGraphMousePlugin() {
|
||||||
this(InputEvent.BUTTON1_MASK);
|
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VisualGraphTranslatingGraphMousePlugin(int modifiers) {
|
public VisualGraphTranslatingGraphMousePlugin(int modifiers) {
|
||||||
|
@ -53,6 +52,11 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
|
||||||
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkModifiers(MouseEvent e) {
|
||||||
|
return e.getModifiersEx() == modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
GraphViewer<V, E> viewer = getGraphViewer(e);
|
GraphViewer<V, E> viewer = getGraphViewer(e);
|
||||||
|
@ -158,7 +162,7 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkModifiersForCursor(MouseEvent e) {
|
private boolean checkModifiersForCursor(MouseEvent e) {
|
||||||
if (e.getModifiers() == 0) {
|
if (e.getModifiersEx() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -24,13 +24,15 @@ import ghidra.graph.viewer.*;
|
||||||
/**
|
/**
|
||||||
* A handler to zoom nodes when double-clicked. If the vertex is zoomed out, then we will zoom
|
* A handler to zoom nodes when double-clicked. If the vertex is zoomed out, then we will zoom
|
||||||
* in and center. If the vertex is zoomed to full size, then we will zoom out and center.
|
* in and center. If the vertex is zoomed to full size, then we will zoom out and center.
|
||||||
|
*
|
||||||
|
* @param <V> the vertex type
|
||||||
|
* @param <E> the edge type
|
||||||
*/
|
*/
|
||||||
public class VisualGraphZoomingPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
public class VisualGraphZoomingPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||||
extends VisualGraphAbstractGraphMousePlugin<V, E> {
|
extends VisualGraphAbstractGraphMousePlugin<V, E> {
|
||||||
|
|
||||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
|
||||||
public VisualGraphZoomingPickingGraphMousePlugin() {
|
public VisualGraphZoomingPickingGraphMousePlugin() {
|
||||||
super(InputEvent.BUTTON1_MASK);
|
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||||
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,10 +72,11 @@ public class GraphServicesScreenShots extends GhidraScreenShotGenerator {
|
||||||
AttributedEdge e2 = graph.addEdge(v1, v3);
|
AttributedEdge e2 = graph.addEdge(v1, v3);
|
||||||
e2.setAttribute("EdgeType", "Unconditional-Call");
|
e2.setAttribute("EdgeType", "Unconditional-Call");
|
||||||
|
|
||||||
display.setGraph(graph, "test", false, TaskMonitor.DUMMY);
|
display.setGraph(graph, "Program Graph", false, TaskMonitor.DUMMY);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
setGraphWindowSize(700, 500);
|
setGraphWindowSize(700, 500);
|
||||||
((DefaultGraphDisplay) display).centerAndScale();
|
runSwing(() -> ((DefaultGraphDisplay) display).centerAndScale());
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
captureProvider(DefaultGraphDisplayComponentProvider.class);
|
captureProvider(DefaultGraphDisplayComponentProvider.class);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ public class GraphServicesScreenShots extends GhidraScreenShotGenerator {
|
||||||
provider.getComponent().requestFocus();
|
provider.getComponent().requestFocus();
|
||||||
paintFix(window);
|
paintFix(window);
|
||||||
});
|
});
|
||||||
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue