GP-310 - Graphing - Updated mouse handling to be consistent with other graph widgets.

This commit is contained in:
ghidravore 2020-11-02 14:15:01 -05:00
parent 956e8ef342
commit d9a1c8906f
43 changed files with 1468 additions and 474 deletions

View File

@ -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/images/BigEndian.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/ImporterPlugin/images/About_pdb.png||GHIDRA||reviewed||END|
src/main/help/help/topics/ImporterPlugin/images/BatchImportDialog.png||GHIDRA||||END|

View File

@ -150,7 +150,9 @@
<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="Folders and Fragments" sortgroup="a" text="Folders and Fragments" target="help/topics/ProgramTreePlugin/program_tree.htm#FoldersAndFragments" />

View File

@ -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>

View File

@ -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>

View File

@ -50,11 +50,9 @@
<tocroot>
<tocref id="Graphing">
<tocdef id="Graph Services" text="Graph Services">
<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>
<tocref id="Graph Services">
<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" />
</tocref>
</tocroot>

View File

@ -5,103 +5,245 @@
<META name="generator" content=
"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">
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD>
<BODY lang="EN-US">
<A name="Default_Graph_Display"/>
<A name="Default_Graph_Display">
<H1>Default Graph Display</H1>
<H2>Visualization of a Graph</H2>
<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>
<BLOCKQUOTE>
<BLOCKQUOTE>
<P align="left"><IMG src="images/DefaultGraphDisplay.png" border="1"></P>
</BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2>Manipulating the Graph:</H2>
<ul>
<li>MouseButton1+drag will translate the display in the x and y axis</li>
<li>Mouse Wheel will zoom in and out</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>Ctrl+MouseButton1 will select a vertex or edge</li>
<ul>
<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>
</ul>
<li>Ctrl+MouseButton1+drag on an empty area will create a rectangular area and select enclosed vertices</li>
<li>Ctrl+MouseButton1+drag over a vertex will reposition all selected vertices</li>
</ul>
<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.
The Filter dialog buttons are created by examining the graph vertex/edge properties to discover candidates for filtering.</P></BLOCKQUOTE></BLOCKQUOTE>
<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>
<BLOCKQUOTE><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>
<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>
<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><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>
<BLOCKQUOTE>
<H3> Standard Popup Actions</H3>
<ul>
<li><A name="Hide Selected"/><B>Hide Selected</B> - Causes the display to not show selected vertices. </li>
<li><A name="Hide Unselected"/><B>Hide Unselected</B> - Causes the display to not show unselected vertices.</li>
<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="Create Subgraph"/><B>Display Selected As New Graph</B> - Creates a new graph and display from the currently selected vertices.</li>
</ul>
<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>
<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>
<ul>
<li><A name="Edge Source"/><B>Go To Edge Source</B> - Makes this edge's source vertex be the focused vertex.</li>
<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>
<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>
<H2>Manipulating the Graph</H2>
<UL>
<LI>Dragging in the graph or on any unselected vertices will pan the graph (translate the
display in the x and y axis)</LI>
<LI>Dragging a selected vertex will reposition all selected vertices</LI>
<LI>Using the <CODE>Mouse Wheel</CODE> will zoom the graph in and out</LI>
<LI><CODE>Control+Mouse Wheel</CODE> will zoom the graph in and out on the X-Axis only</LI>
<LI><CODE>ALT+Mouse Wheel</CODE> will zoom the graph in and out in the Y-Axis only</LI>
<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>
<P><A name="Scroll_To_Selection">
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="Free_Form_Selection">
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>
<P><A name="SatelliteView">
The <IMG alt="" src="images/network-wireless-16.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 alt="" 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 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>
<H2>Popup Actions</H2>
<BLOCKQUOTE>
<H3>Standard Popup Actions</H3>
<UL>
<LI><A name="Hide_Selected">
<B>Hide Selected</B> - Causes the display to not show selected vertices.</LI>
<LI><A name="Hide_Unselected">
<B>Hide Unselected</B> - Causes the display to not show unselected vertices.</LI>
<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>
<UL>
<LI><A name="Select_Vertex">
<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>
<UL>
<LI><A name="Edge_Source">
<B>Go To Edge Source</B> - Makes this edge's source vertex be the focused vertex.</LI>
<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>
<P class="providedbyplugin">Provided By:&nbsp; <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>
</HTML>
</HTML>

View File

@ -11,19 +11,22 @@
</HEAD>
<BODY lang="EN-US">
<A name="Default Graph Exporter"/>
<A NAME="Graph_Exporter"/>
<H1>Graph Export Service</H1>
<H2> Export Dialog </H2>
<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>
<BR>
<BLOCKQUOTE>
<BLOCKQUOTE>
<P align="left"><IMG src="images/ExportDialog.png"></P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<CENTER>
<TABLE border="0" width="100%">
<TR>
<TD width="100%" align="center"><IMG alt="" border="1" src=
"images/ExportDialog.png"></TD>
</TR>
</TABLE>
</CENTER>
<BR>
<BLOCKQUOTE>
<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>Cancel</b> button will close the dialog and perform no other action.</p>
<P class="providedbyplugin">Provided By:&nbsp; <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>
</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

View File

@ -73,6 +73,6 @@ public class ExportAttributedGraphDisplayProvider implements GraphDisplayProvide
@Override
public HelpLocation getHelpLocation() {
return new HelpLocation("GraphServices", "Default_Graph_Exporter");
return new HelpLocation("GraphServices", "Graph_Exporter");
}
}

View File

@ -74,7 +74,7 @@ public class GraphExporterDialog extends DialogComponentProvider {
addWorkPanel(buildWorkPanel());
addOKButton();
addCancelButton();
setHelpLocation(new HelpLocation("ExporterPlugin", "Exporter_Dialog"));
setHelpLocation(new HelpLocation("GraphServices", "Graph_Exporter"));
validate();
}

View File

@ -27,10 +27,10 @@ final class 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 PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.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 FILTER_ICON = Icons.get("images/filter_on.png");
public static final Icon FILTER_ICON = Icons.CONFIGURE_FILTER_ICON;
}

View File

@ -23,7 +23,6 @@ import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.*;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@ -64,6 +63,8 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.graph.AttributeFilters;
import ghidra.graph.job.GraphJobRunner;
import ghidra.graph.viewer.popup.*;
import ghidra.graph.visualization.mouse.JgtPluggableGraphMouse;
import ghidra.graph.visualization.mouse.JgtUtils;
import ghidra.service.graph.*;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
@ -76,19 +77,18 @@ import resources.Icons;
*/
public class DefaultGraphDisplay implements GraphDisplay {
public static final String FAVORED_EDGE = "Fall-Through";
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);
private static final String ACTION_OWNER = "GraphServices";
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 String title;
/**
* the {@link Graph} to visualize
*/
private AttributedGraph graph;
/**
@ -97,91 +97,64 @@ public class DefaultGraphDisplay implements GraphDisplay {
private final int displayId;
/**
* the delegate viewer to display the ProgramGraph
* The delegate viewer to display the ProgramGraph
*/
private final VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
/**
* the {@link PluginTool}
* The {@link 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;
/**
* 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
* or the center of the set of selected vertices
*/
private boolean ensureVertexIsVisible = false;
/**
* allows selection of various {@link LayoutAlgorithm} ('arrangements')
* Allows selection of various {@link LayoutAlgorithm} ('arrangements')
*/
private final LayoutTransitionManager layoutTransitionManager;
/**
* provides graph displays for supplied graphs
* Provides graph displays for supplied graphs
*/
private final DefaultGraphDisplayProvider graphDisplayProvider;
/**
* the vertex that has been nominated to be 'focused' in the graph display and listing
*/
private AttributedVertex focusedVertex;
/**
* Runs animation jobs for updating the display
*/
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
*/
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;
/**
* holds the vertex icons (instead of recomputing them)
*/
private AttributeFilters edgeFilters;
private AttributeFilters vertexFilters;
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;
/**
* 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 hideUnselectedAction;
private SwitchableSelectionItemListener switchableSelectionListener;
@ -226,7 +199,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
.builder(viewer.getRenderContext().getVertexBoundsFunction())
.build());
graphMouse = new GhidraGraphMouse(componentProvider, viewer);
graphMouse = new JgtPluggableGraphMouse(this);
createToolbarActions();
createPopupActions();
@ -302,7 +275,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
private void createToolbarActions() {
// 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)
.description("Ensure that the 'focused' vertex is visible")
.selected(true)
@ -314,7 +287,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
// create a toggle for enabling 'free-form' selection: selection is
// 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)
.description("Trace Free-Form Shape to select multiple vertices (CTRL-click-drag)")
.selected(false)
@ -323,14 +296,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
.buildAndInstallLocal(componentProvider);
// 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)
.onAction(this::toggleSatellite)
.selected(graphDisplayProvider.getDefaultSatelliteState())
.buildAndInstallLocal(componentProvider);
// 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")
.toolBarIcon(Icons.REFRESH_ICON)
.onAction(context -> viewer.scaleToLayout())
@ -338,7 +311,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
// create a button to show the view magnify lens
LensSupport<LensGraphMouse> magnifyViewSupport = createMagnifier();
ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", actionOwnerName)
ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", ACTION_OWNER)
.description("Show View Magnifier")
.toolBarIcon(DefaultDisplayGraphIcons.VIEW_MAGNIFIER_ICON)
.onAction(context -> magnifyViewSupport.activate(
@ -349,90 +322,91 @@ public class DefaultGraphDisplay implements GraphDisplay {
componentProvider.addLocalAction(lensToggle);
// 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)
.onAction(context -> showFilterDialog())
.buildAndInstallLocal(componentProvider);
// create a menu with graph layout algorithm selections
new MultiStateActionBuilder<String>("Arrangement", actionOwnerName)
.description("Select Layout Arrangement Algorithm")
List<ActionState<String>> layoutActionStates = getLayoutActionStates();
new MultiStateActionBuilder<String>("Arrangement", ACTION_OWNER)
.description("Arrangement: " + layoutActionStates.get(0).getName())
.toolBarIcon(DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON)
.fireFirstAction(false)
.onActionStateChanged((s, t) -> layoutChanged(s.getName()))
.addStates(getLayoutActionStates())
.addStates(layoutActionStates)
.buildAndInstallLocal(componentProvider);
}
private void createPopupActions() {
new ActionBuilder("Select Vertex", actionOwnerName)
new ActionBuilder("Select Vertex", ACTION_OWNER)
.popupMenuPath("Select Vertex")
.popupMenuGroup("selection", "1")
.withContext(VertexGraphActionContext.class)
.enabledWhen(c -> !viewer.getSelectedVertexState().isSelected(c.getClickedVertex()))
.enabledWhen(c -> !isSelected(c.getClickedVertex()))
.onAction(c -> viewer.getSelectedVertexState().select(c.getClickedVertex()))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Deselect Vertex", actionOwnerName)
new ActionBuilder("Deselect Vertex", ACTION_OWNER)
.popupMenuPath("Deselect Vertex")
.popupMenuGroup("selection", "2")
.withContext(VertexGraphActionContext.class)
.enabledWhen(c -> viewer.getSelectedVertexState().isSelected(c.getClickedVertex()))
.enabledWhen(c -> isSelected(c.getClickedVertex()))
.onAction(c -> viewer.getSelectedVertexState().deselect(c.getClickedVertex()))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Select Edge", actionOwnerName)
new ActionBuilder("Select Edge", ACTION_OWNER)
.popupMenuPath("Select Edge")
.popupMenuGroup("selection", "1")
.withContext(EdgeGraphActionContext.class)
.enabledWhen(c -> !viewer.getSelectedEdgeState().isSelected(c.getClickedEdge()))
.enabledWhen(c -> !isSelected(c.getClickedEdge()))
.onAction(c -> selectEdge(c.getClickedEdge()))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Deselect Edge", actionOwnerName)
new ActionBuilder("Deselect Edge", ACTION_OWNER)
.popupMenuPath("Deselect Edge")
.popupMenuGroup("selection", "2")
.withContext(EdgeGraphActionContext.class)
.enabledWhen(c -> viewer.getSelectedEdgeState().isSelected(c.getClickedEdge()))
.enabledWhen(c -> isSelected(c.getClickedEdge()))
.onAction(c -> deselectEdge(c.getClickedEdge()))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Edge Source", actionOwnerName)
new ActionBuilder("Edge Source", ACTION_OWNER)
.popupMenuPath("Go To Edge Source")
.popupMenuGroup("Go To")
.withContext(EdgeGraphActionContext.class)
.onAction(c -> setFocusedVertex(graph.getEdgeSource(c.getClickedEdge())))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Edge Target", actionOwnerName)
new ActionBuilder("Edge Target", ACTION_OWNER)
.popupMenuPath("Go To Edge Target")
.popupMenuGroup("Go To")
.withContext(EdgeGraphActionContext.class)
.onAction(c -> setFocusedVertex(graph.getEdgeTarget(c.getClickedEdge())))
.buildAndInstallLocal(componentProvider);
hideSelectedAction = new ToggleActionBuilder("Hide Selected", actionOwnerName)
hideSelectedAction = new ToggleActionBuilder("Hide Selected", ACTION_OWNER)
.popupMenuPath("Hide Selected")
.popupMenuGroup("z", "1")
.description("Toggles whether or not to show selected vertices and edges")
.onAction(c -> manageVertexDisplay())
.buildAndInstallLocal(componentProvider);
hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", actionOwnerName)
hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", ACTION_OWNER)
.popupMenuPath("Hide Unselected")
.popupMenuGroup("z", "2")
.description("Toggles whether or not to show selected vertices and edges")
.onAction(c -> manageVertexDisplay())
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Invert Selection", actionOwnerName)
new ActionBuilder("Invert Selection", ACTION_OWNER)
.popupMenuPath("Invert Selection")
.popupMenuGroup("z", "3")
.description("Inverts the current selection")
.onAction(c -> invertSelection())
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Grow Selection To Targets", actionOwnerName)
new ActionBuilder("Grow Selection To Targets", ACTION_OWNER)
.popupMenuPath("Grow Selection To Targets")
.popupMenuGroup("z", "4")
.description("Extends the current selection by including the target vertex " +
@ -442,7 +416,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
.onAction(c -> growSelection(getTargetVerticesFromSelected()))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Grow Selection From Sources", actionOwnerName)
new ActionBuilder("Grow Selection From Sources", ACTION_OWNER)
.popupMenuPath("Grow Selection From Sources")
.popupMenuGroup("z", "4")
.description("Extends the current selection by including the target vertex " +
@ -452,15 +426,23 @@ public class DefaultGraphDisplay implements GraphDisplay {
.onAction(c -> growSelection(getSourceVerticesFromSelected()))
.buildAndInstallLocal(componentProvider);
new ActionBuilder("Create Subgraph", actionOwnerName)
.popupMenuPath("Display Selected as New Graph")
new ActionBuilder("Clear Selection", ACTION_OWNER)
.popupMenuPath("Clear Selection")
.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")
.enabledWhen(c -> !viewer.getSelectedVertexState().getSelected().isEmpty())
.onAction(c -> createAndDisplaySubGraph())
.buildAndInstallLocal(componentProvider);
togglePopupsAction = new ToggleActionBuilder("Display Popup Windows", actionOwnerName)
togglePopupsAction = new ToggleActionBuilder("Display Popup Windows", ACTION_OWNER)
.popupMenuPath("Display Popup Windows")
.popupMenuGroup("zz", "1")
.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() {
GraphDisplay display = graphDisplayProvider.getGraphDisplay(false, TaskMonitor.DUMMY);
try {
@ -556,7 +556,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
for (String layoutName : names) {
ActionState<String> state = new ActionState<>(layoutName,
DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON, layoutName);
state.setHelpLocation(new HelpLocation(actionOwnerName, layoutName));
state.setHelpLocation(new HelpLocation(ACTION_OWNER, layoutName));
actionStates.add(state);
}
return actionStates;
@ -603,24 +603,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
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(
VisualizationViewer<AttributedVertex, AttributedEdge> parentViewer) {
Dimension viewerSize = parentViewer.getSize();
@ -649,9 +631,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
return satellite;
}
/**
* close this graph display
*/
@Override
public void close() {
graphDisplayProvider.remove(this);
@ -662,10 +641,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
componentProvider.closeComponent();
}
/**
* accept a {@code GraphDisplayListener}
* @param listener the listener to be notified
*/
@Override
public void setGraphDisplayListener(GraphDisplayListener listener) {
if (this.listener != null) {
@ -697,7 +672,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
viewer.getSelectedVertexState().addItemListener(switchableSelectionListener);
}
protected void setFocusedVertex(AttributedVertex vertex) {
public void setFocusedVertex(AttributedVertex vertex) {
setFocusedVertex(vertex, EventTrigger.API_CALL);
}
@ -1008,8 +983,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
return new Point2D.Double(p.x, p.y);
}
// they did not pick a vertex to center, so
// just center the graph
// they did not pick a vertex to center, so just center the graph
Point2D center = viewer.getCenter();
Point p = Point.of(center.getX(), center.getY());
return new Point2D.Double(p.x, p.y);
@ -1211,13 +1185,13 @@ public class DefaultGraphDisplay implements GraphDisplay {
public ActionContext getActionContext(MouseEvent e) {
AttributedVertex pickedVertex = graphMouse.getPickedVertex(e);
AttributedVertex pickedVertex = JgtUtils.getVertex(e, viewer);
if (pickedVertex != null) {
return new VertexGraphActionContext(componentProvider, graph, getSelectedVertices(),
focusedVertex, pickedVertex);
}
AttributedEdge pickedEdge = graphMouse.getPickedEdge(e);
AttributedEdge pickedEdge = JgtUtils.getEdge(e, viewer);
if (pickedEdge != null) {
return new EdgeGraphActionContext(componentProvider, graph, getSelectedVertices(),
focusedVertex, pickedEdge);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.graph.visualization;
package ghidra.graph.visualization.mouse;
import static org.jungrapht.visualization.VisualizationServer.*;
@ -22,42 +22,86 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
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.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
* <ul>
* <li>a {@link VisualizationViewer} (to access the Graph and LayoutModel)
*
* Keeper of shared logic for jungrapht handling
*/
public class GhidraGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
public class JgtUtils {
private static final String PICK_AREA_SIZE_PROPERTY = PREFIX + "pickAreaSize";
private VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
private int pickSize;
/**
* create an instance with default values
* @param componentProvider the graph component provider
* @param viewer the graph viewer component
* Returns the edge 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 edge
*/
GhidraGraphMouse(ComponentProvider componentProvider,
VisualizationViewer<AttributedVertex, AttributedEdge> viewer) {
public static <V, E> E getEdge(MouseEvent e, VisualizationViewer<V, E> viewer) {
if (e == null) {
return null;
}
super(DefaultGraphMouse.<AttributedVertex, AttributedEdge> builder());
this.viewer = viewer;
pickSize = Integer.getInteger(GhidraGraphMouse.PICK_AREA_SIZE_PROPERTY, 4);
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());
}
private Rectangle2D getFootprint(MouseEvent e) {
/**
* 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(
e.getPoint().x - pickSize / 2f,
e.getPoint().y - pickSize / 2f,
@ -65,44 +109,4 @@ public class GhidraGraphMouse extends DefaultGraphMouse<AttributedVertex, Attrib
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());
}
}

View File

@ -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.
}
}

View File

@ -62,3 +62,10 @@ jungrapht.initialDimensionVertexDensity=0.3f
jungrapht.minScale=0.001
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

View File

@ -13,7 +13,7 @@
<BODY lang="EN-US">
<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
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
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.
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
@ -49,7 +49,7 @@
<P>Selection and Location events are synchronized between each
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
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>
</BLOCKQUOTE>
<H3>Location</H3>
<H2>Location</H2>
<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>
@ -95,7 +95,7 @@
current address location within Ghidra to change to the minimum address represented by the
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>
@ -220,99 +220,7 @@
</DIV>
</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> &lt;<I><B>a Call Model</B></I>&gt;</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>
<P>When <I>Reuse Graph</I> is turned on, creating any new graphs will re-use the active graph
@ -378,6 +286,123 @@
<P>When Show Location is turned <U><I>off</I></U>, the graph view will not change as the
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> &lt;<I><B>a Call Model</B></I>&gt;</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>

View File

@ -26,6 +26,7 @@ import ghidra.program.model.block.*;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.service.graph.*;
import ghidra.util.HelpLocation;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -47,6 +48,7 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
display.addAction(new ActionBuilder("Rename Vertex", "Block Graph")
.popupMenuPath("Rename Vertex")
.withContext(VertexGraphActionContext.class)
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename Vertex"))
// only enable action when vertex corresponds to an address
.enabledWhen(c -> getAddress(c.getClickedVertex().getId()) != null)
.onAction(this::updateVertexName)

View File

@ -1128,9 +1128,13 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
private V selectedVertex;
@SuppressWarnings("deprecation") // deprecated until we fix the checkModifiers() code
public VertexClickMousePlugin() {
super(InputEvent.BUTTON1_MASK);
super(InputEvent.BUTTON1_DOWN_MASK);
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
@Override
@ -1203,6 +1207,5 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
public void mouseExited(MouseEvent e) {
// stub
}
}
}

View File

@ -32,6 +32,9 @@ import ghidra.graph.viewer.*;
* <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 VisualGraphAbstractGraphMousePlugin<V extends VisualVertex,
@ -46,13 +49,18 @@ public abstract class VisualGraphAbstractGraphMousePlugin<V extends VisualVertex
protected E selectedEdge;
public VisualGraphAbstractGraphMousePlugin() {
this(InputEvent.BUTTON1_MASK);
this(InputEvent.BUTTON1_DOWN_MASK);
}
public VisualGraphAbstractGraphMousePlugin(int selectionModifiers) {
super(selectionModifiers);
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
protected boolean checkForVertex(MouseEvent e) {
if (!checkModifiers(e)) {
selectedVertex = null;

View File

@ -24,7 +24,10 @@ import edu.uci.ics.jung.visualization.control.AnimatedPickingGraphMousePlugin;
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>>
extends AnimatedPickingGraphMousePlugin<V, E> implements VisualGraphMousePlugin<V, E> {
@ -32,7 +35,7 @@ public class VisualGraphAnimatedPickingGraphMousePlugin<V extends VisualVertex,
private boolean isHandlingMouseEvents;
public VisualGraphAnimatedPickingGraphMousePlugin() {
super(InputEvent.BUTTON1_MASK);
super(InputEvent.BUTTON1_DOWN_MASK);
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}

View File

@ -29,10 +29,17 @@ public class VisualGraphCursorRestoringGraphMousePlugin<V, E> extends AbstractGr
super(0);
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
@Override
public void mouseDragged(MouseEvent e) {
// don't care
}
@Override
public void mouseMoved(MouseEvent e) {
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
}

View File

@ -38,9 +38,9 @@ public class VisualGraphEventForwardingGraphMousePlugin<V extends VisualVertex,
private boolean isHandlingEvent = false;
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
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) {
@ -50,18 +50,18 @@ public class VisualGraphEventForwardingGraphMousePlugin<V extends VisualVertex,
@Override
public boolean checkModifiers(MouseEvent e) {
int eventModifiers = e.getModifiers();
int eventModifiers = e.getModifiersEx();
eventModifiers = turnOffControlKey(eventModifiers);
return ((eventModifiers & getModifiers()) == 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) {
int allModifiers = e.getModifiers();
int osSpecificMask = DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED;
int allModifiers = e.getModifiersEx();
int osSpecificMask = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
return (allModifiers & osSpecificMask) == osSpecificMask;
// can't use this until we fix the old modifiers usage

View File

@ -61,6 +61,11 @@ public class VisualGraphHoverMousePlugin<V extends VisualVertex, E extends Visua
this.otherViewer = otherViewer;
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
@Override
public void mouseMoved(MouseEvent e) {
lastMouseEvent = e;

View File

@ -28,7 +28,6 @@ import edu.uci.ics.jung.visualization.transform.MutableTransformer;
import ghidra.graph.viewer.*;
import ghidra.graph.viewer.renderer.*;
/**
* A simple plugin that allows clients to be notified of mouse events before any of the other
* mouse plugins.
@ -52,14 +51,15 @@ public class VisualGraphMouseTrackingGraphMousePlugin<V extends VisualVertex,
private int mouseMovedCount;
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);
viewer.addPostRenderPaintable(paintable);
}
@Override
public boolean checkModifiers(MouseEvent e) {
int eventModifiers = e.getModifiers();
int eventModifiers = e.getModifiersEx();
eventModifiers = turnOffControlKey(eventModifiers);
return ((eventModifiers & getModifiers()) == eventModifiers);
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (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
// -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() {
super(InputEvent.BUTTON1_MASK,
InputEvent.BUTTON1_MASK | DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED);
super(InputEvent.BUTTON1_DOWN_MASK,
InputEvent.BUTTON1_DOWN_MASK | DockingUtils.CONTROL_KEY_MODIFIER_MASK);
}
@Override
public boolean checkModifiers(MouseEvent e) {
if (e.getModifiers() == addToSelectionModifiers) {
if (e.getModifiersEx() == addToSelectionModifiers) {
return true;
}
return super.checkModifiers(e);
return e.getModifiersEx() == modifiers;
}
@Override
@ -80,7 +78,7 @@ public class VisualGraphPickingGraphMousePlugin<V extends VisualVertex, E extend
private void increaseDragRectangle(MouseEvent e) {
Point2D out = e.getPoint();
int theModifiers = e.getModifiers();
int theModifiers = e.getModifiersEx();
if (theModifiers == addToSelectionModifiers || theModifiers == modifiers) {
if (down != null) {
rect.setFrameFromDiagonal(down, out);

View File

@ -29,7 +29,7 @@ public abstract class VisualGraphSatelliteAbstractGraphMousePlugin<V extends Vis
extends VisualGraphAbstractGraphMousePlugin<V, E> {
public VisualGraphSatelliteAbstractGraphMousePlugin() {
this(InputEvent.BUTTON1_MASK);
this(InputEvent.BUTTON1_DOWN_MASK);
}
public VisualGraphSatelliteAbstractGraphMousePlugin(int selectionModifiers) {

View File

@ -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
}

View File

@ -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
}

View File

@ -25,7 +25,7 @@ public class VisualGraphSatelliteNavigationGraphMousePlugin<V extends VisualVert
extends VisualGraphSatelliteAbstractGraphMousePlugin<V, E> {
public VisualGraphSatelliteNavigationGraphMousePlugin() {
super(InputEvent.BUTTON1_MASK);
super(InputEvent.BUTTON1_DOWN_MASK);
}
@Override

View File

@ -46,7 +46,7 @@ public class VisualGraphSatelliteScalingGraphMousePlugin<V extends VisualVertex,
VisualGraphOptions options = viewer.getOptions();
boolean scrollWheelPans = options.getScrollWheelPans();
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
int eventModifiers = e.getModifiers();
int eventModifiers = e.getModifiersEx();
if (scrollWheelPans) {
// scrolling will zoom if modified (unmodified in this case means to pan)
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;

View File

@ -35,7 +35,7 @@ public class VisualGraphSatelliteTranslatingGraphMousePlugin<V extends VisualVer
// Note: for ideas on resizing instead of moving, see LensTranslatingGraphMousePlugin
public VisualGraphSatelliteTranslatingGraphMousePlugin() {
super(InputEvent.BUTTON1_MASK);
super(InputEvent.BUTTON1_DOWN_MASK);
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
}

View File

@ -25,6 +25,9 @@ import ghidra.graph.viewer.options.VisualGraphOptions;
/**
* Overridden implementation that allows us to change scaling behavior through options. This
* 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>>
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
VisualGraphOptions options = viewer.getOptions();
boolean scrollWheelPans = options.getScrollWheelPans();
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED;
int eventModifiers = e.getModifiers();
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
int eventModifiers = e.getModifiersEx();
if (scrollWheelPans) {
// scrolling will zoom if modified (unmodified in this case means to pan)
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;

View File

@ -16,8 +16,7 @@
package ghidra.graph.viewer.event.mouse;
import java.awt.Point;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.*;
import docking.DockingUtils;
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
@ -31,9 +30,14 @@ public class VisualGraphScreenPositioningPlugin<V extends VisualVertex, E extend
super(0);
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
int eventModifiers = e.getModifiers();
int eventModifiers = e.getModifiersEx();
boolean controlKeyDown = (eventModifiers & DockingUtils.CONTROL_KEY_MODIFIER_MASK) != 0;
if (!controlKeyDown) {
return;

View File

@ -16,8 +16,7 @@
package ghidra.graph.viewer.event.mouse;
import java.awt.Point;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.*;
import docking.DockingUtils;
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
@ -35,6 +34,11 @@ public class VisualGraphScrollWheelPanningPlugin<V extends VisualVertex,
super(0);
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (!isScrollModifiers(e)) {
@ -91,7 +95,7 @@ public class VisualGraphScrollWheelPanningPlugin<V extends VisualVertex,
VisualGraphOptions options = viewer.getOptions();
boolean scrollWheelPans = options.getScrollWheelPans();
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
int eventModifiers = e.getModifiers();
int eventModifiers = e.getModifiersEx();
if (scrollWheelPans) {
// scrolling will pan if *not* modified (modified in this case means to zoom)
return !((scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle);

View File

@ -33,8 +33,8 @@ import ghidra.graph.viewer.*;
* 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 VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
extends AbstractGraphMousePlugin
@ -43,9 +43,8 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
private boolean panning;
private boolean isHandlingEvent;
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
public VisualGraphTranslatingGraphMousePlugin() {
this(InputEvent.BUTTON1_MASK);
this(InputEvent.BUTTON1_DOWN_MASK);
}
public VisualGraphTranslatingGraphMousePlugin(int modifiers) {
@ -53,6 +52,11 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
}
@Override
public boolean checkModifiers(MouseEvent e) {
return e.getModifiersEx() == modifiers;
}
@Override
public void mousePressed(MouseEvent e) {
GraphViewer<V, E> viewer = getGraphViewer(e);
@ -158,7 +162,7 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
}
private boolean checkModifiersForCursor(MouseEvent e) {
if (e.getModifiers() == 0) {
if (e.getModifiersEx() == 0) {
return true;
}
return false;

View File

@ -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
* 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>>
extends VisualGraphAbstractGraphMousePlugin<V, E> {
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
public VisualGraphZoomingPickingGraphMousePlugin() {
super(InputEvent.BUTTON1_MASK);
super(InputEvent.BUTTON1_DOWN_MASK);
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}

View File

@ -72,10 +72,11 @@ public class GraphServicesScreenShots extends GhidraScreenShotGenerator {
AttributedEdge e2 = graph.addEdge(v1, v3);
e2.setAttribute("EdgeType", "Unconditional-Call");
display.setGraph(graph, "test", false, TaskMonitor.DUMMY);
display.setGraph(graph, "Program Graph", false, TaskMonitor.DUMMY);
waitForSwing();
setGraphWindowSize(700, 500);
((DefaultGraphDisplay) display).centerAndScale();
runSwing(() -> ((DefaultGraphDisplay) display).centerAndScale());
waitForSwing();
captureProvider(DefaultGraphDisplayComponentProvider.class);
}
@ -95,7 +96,7 @@ public class GraphServicesScreenShots extends GhidraScreenShotGenerator {
provider.getComponent().requestFocus();
paintFix(window);
});
waitForSwing();
}
}