mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 05:24:53 +08:00
Merge remote-tracking branch
'origin/GP-1093-dragonmacher-listing-xref-condensing' (Closes #1305)
This commit is contained in:
+35
-14
@@ -927,22 +927,43 @@
|
|||||||
<P><B>Display Local Block -</B> Prepends the name of the memory block containing the XREF
|
<P><B>Display Local Block -</B> Prepends the name of the memory block containing the XREF
|
||||||
source address to each XREF.</P>
|
source address to each XREF.</P>
|
||||||
|
|
||||||
|
<P><B>Namespace Options: </B>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><B>Display Non-local Namespace -</B> Select this option to prepend the namespace to all
|
||||||
|
XREFs that are not from an instruction within the current Function's body. Currently,
|
||||||
|
this would only affect XREFs that originate in some other function.<BR>
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<P><B>Display Library in Namespace -</B> Include the library name in the namespace.<BR>
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<P><B>Display Local Namespace -</B> Select this option to prepend the namespace to all
|
||||||
|
XREFs that are from the current Function.<BR>
|
||||||
|
</P>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P><B>Use Local Namespace Override</B> - Select this
|
||||||
|
option to show a fixed prefix for local XREFs instead of the function's name. This
|
||||||
|
option is only available if the "Display Local Namespace" option is on. The text box
|
||||||
|
contains the prefix to use for local XREFs.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P><B>Display Reference Type -</B> Shows a single letter to represent the type of reference.
|
||||||
|
Some of the possible types are:
|
||||||
|
<CODE>Read (R), Write (W), Data (*), Call (c), Jump (j) and Thunk (T)</CODE>.
|
||||||
|
|
||||||
|
<P><B>Group by Function -</B> Groups all references by the containing source function.
|
||||||
|
With this option off, all references within a function are displayed on their on row.
|
||||||
|
With this feature on, each function will get a single row, with all references displayed on
|
||||||
|
that row.
|
||||||
|
|
||||||
<P><B>Maximum Number of XREFs To Display -</B> The maximum number of lines used to display
|
<P><B>Maximum Number of XREFs To Display -</B> The maximum number of lines used to display
|
||||||
XREFs. Additional XREFs will not be displayed.</P>
|
XREFs. Additional XREFs will not be displayed.</P>
|
||||||
|
|
||||||
<P><B>Display Non-local Namespace -</B> Select this option to prepend the namespace to all
|
<P><B>Sort References by -</B> Allows the references to be sorted by Address or by type.
|
||||||
XREFs that are not from an instruction within the current Function's body. Currently,
|
This is most useful when <B>Group by Function</B> is off.
|
||||||
this would only affect XREFs that originate in some other function.<BR>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<P><B>Display Local Namespace -</B> Select this option to prepend the namespace to all
|
|
||||||
XREFs that are from the current Function.<BR>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<P><SPAN style="font-weight: bold;">Use Local Namespace Override</SPAN> - Select this
|
|
||||||
option to show a fixed prefix for local XREFs instead of the function's name. This
|
|
||||||
option is only available if the "Display Local Namespace" option is on. The text box
|
|
||||||
contains the prefix to use for local XREFs.</P>
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|||||||
+4
-7
@@ -988,8 +988,8 @@ public class CodeBrowserPlugin extends Plugin
|
|||||||
return; // not sure if this can happen
|
return; // not sure if this can happen
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Reference> refs = XReferenceUtil.getAllXrefs(location);
|
Set<Reference> refs = XReferenceUtils.getAllXrefs(location);
|
||||||
XReferenceUtil.showAllXrefs(connectedProvider, tool, service, location, refs);
|
XReferenceUtils.showXrefs(connectedProvider, tool, service, location, refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GhidraProgramTableModel<Address> createTableModel(CodeUnitIterator iterator,
|
private GhidraProgramTableModel<Address> createTableModel(CodeUnitIterator iterator,
|
||||||
@@ -1065,16 +1065,13 @@ public class CodeBrowserPlugin extends Plugin
|
|||||||
*/
|
*/
|
||||||
public boolean goToField(Address a, String fieldName, int occurrence, int row, int col,
|
public boolean goToField(Address a, String fieldName, int occurrence, int row, int col,
|
||||||
boolean scroll) {
|
boolean scroll) {
|
||||||
|
return Swing.runNow(() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
|
||||||
boolean result = SystemUtilities
|
|
||||||
.runSwingNow(() -> doGoToField(a, fieldName, occurrence, row, col, scroll));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doGoToField(Address a, String fieldName, int occurrence, int row, int col,
|
private boolean doGoToField(Address a, String fieldName, int occurrence, int row, int col,
|
||||||
boolean scroll) {
|
boolean scroll) {
|
||||||
|
|
||||||
SystemUtilities.assertThisIsTheSwingThread("GoTo must be performed on the Swing thread");
|
Swing.assertSwingThread("'Go To' must be performed on the Swing thread");
|
||||||
|
|
||||||
// make sure that the code browser is ready to go--sometimes it is not, due to timing
|
// make sure that the code browser is ready to go--sometimes it is not, due to timing
|
||||||
// during the testing process, like when the tool is first loaded.
|
// during the testing process, like when the tool is first loaded.
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ import ghidra.util.table.ReferencesFromTableModel;
|
|||||||
import ghidra.util.table.field.ReferenceEndpoint;
|
import ghidra.util.table.field.ReferenceEndpoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class to handle the generation of
|
* A utility class to handle the generation of direct and offcut cross-reference (xref) lists
|
||||||
* direct and offcut cross-reference (xref) lists
|
|
||||||
* on code units and stack variables.
|
* on code units and stack variables.
|
||||||
|
*
|
||||||
|
* @deprecated deprecated for 10.1; removal for 10.3 or later
|
||||||
*/
|
*/
|
||||||
|
@Deprecated // Use XReferenceUtils instead
|
||||||
public class XReferenceUtil {
|
public class XReferenceUtil {
|
||||||
private final static Address[] EMPTY_ADDR_ARRAY = new Address[0];
|
private final static Address[] EMPTY_ADDR_ARRAY = new Address[0];
|
||||||
private final static Reference[] EMPTY_REF_ARRAY = new Reference[0];
|
private final static Reference[] EMPTY_REF_ARRAY = new Reference[0];
|
||||||
@@ -59,11 +61,11 @@ public class XReferenceUtil {
|
|||||||
/**
|
/**
|
||||||
* Returns an array containing the first <b><code>maxNumber</code></b>
|
* Returns an array containing the first <b><code>maxNumber</code></b>
|
||||||
* direct xref addresses to the specified code unit.
|
* direct xref addresses to the specified code unit.
|
||||||
*
|
*
|
||||||
* @param cu the code unit to generate the xrefs
|
* @param cu the code unit to generate the xrefs
|
||||||
* @param maxNumber max number of xrefs to get,
|
* @param maxNumber max number of xrefs to get,
|
||||||
* or -1 to get all references
|
* or -1 to get all references
|
||||||
*
|
*
|
||||||
* @return array first <b><code>maxNumber</code></b> xrefs to the code unit
|
* @return array first <b><code>maxNumber</code></b> xrefs to the code unit
|
||||||
*/
|
*/
|
||||||
public final static Address[] getXRefList(CodeUnit cu, int maxNumber) {
|
public final static Address[] getXRefList(CodeUnit cu, int maxNumber) {
|
||||||
@@ -71,9 +73,8 @@ public class XReferenceUtil {
|
|||||||
if (prog == null) {
|
if (prog == null) {
|
||||||
return EMPTY_ADDR_ARRAY;
|
return EMPTY_ADDR_ARRAY;
|
||||||
}
|
}
|
||||||
List<Address> xrefList = new ArrayList<Address>();
|
List<Address> xrefList = new ArrayList<>();
|
||||||
//lookup the direct xrefs to the current code unit
|
// lookup the direct xrefs to the current code unit
|
||||||
//
|
|
||||||
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
|
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Reference ref = iter.next();
|
Reference ref = iter.next();
|
||||||
@@ -91,11 +92,11 @@ public class XReferenceUtil {
|
|||||||
/**
|
/**
|
||||||
* Returns an array containing the first <b><code>maxNumber</code></b>
|
* Returns an array containing the first <b><code>maxNumber</code></b>
|
||||||
* direct xref references to the specified code unit.
|
* direct xref references to the specified code unit.
|
||||||
*
|
*
|
||||||
* @param cu the code unit to generate the xrefs
|
* @param cu the code unit to generate the xrefs
|
||||||
* @param maxNumber max number of xrefs to get,
|
* @param maxNumber max number of xrefs to get,
|
||||||
* or -1 to get all references
|
* or -1 to get all references
|
||||||
*
|
*
|
||||||
* @return array first <b><code>maxNumber</code></b> xrefs to the code unit
|
* @return array first <b><code>maxNumber</code></b> xrefs to the code unit
|
||||||
*/
|
*/
|
||||||
public final static Reference[] getXReferences(CodeUnit cu, int maxNumber) {
|
public final static Reference[] getXReferences(CodeUnit cu, int maxNumber) {
|
||||||
@@ -103,7 +104,7 @@ public class XReferenceUtil {
|
|||||||
if (prog == null) {
|
if (prog == null) {
|
||||||
return EMPTY_REF_ARRAY;
|
return EMPTY_REF_ARRAY;
|
||||||
}
|
}
|
||||||
List<Reference> xrefList = new ArrayList<Reference>();
|
List<Reference> xrefList = new ArrayList<>();
|
||||||
//lookup the direct xrefs to the current code unit
|
//lookup the direct xrefs to the current code unit
|
||||||
//
|
//
|
||||||
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
|
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
|
||||||
@@ -156,7 +157,7 @@ public class XReferenceUtil {
|
|||||||
if (prog == null) {
|
if (prog == null) {
|
||||||
return EMPTY_ADDR_ARRAY;
|
return EMPTY_ADDR_ARRAY;
|
||||||
}
|
}
|
||||||
List<Address> offcutList = new ArrayList<Address>();
|
List<Address> offcutList = new ArrayList<>();
|
||||||
// Lookup the offcut xrefs...
|
// Lookup the offcut xrefs...
|
||||||
//
|
//
|
||||||
if (cu.getLength() > 1) {
|
if (cu.getLength() > 1) {
|
||||||
@@ -195,7 +196,7 @@ public class XReferenceUtil {
|
|||||||
if (prog == null) {
|
if (prog == null) {
|
||||||
return EMPTY_REF_ARRAY;
|
return EMPTY_REF_ARRAY;
|
||||||
}
|
}
|
||||||
List<Reference> offcutList = new ArrayList<Reference>();
|
List<Reference> offcutList = new ArrayList<>();
|
||||||
// Lookup the offcut xrefs...
|
// Lookup the offcut xrefs...
|
||||||
//
|
//
|
||||||
if (cu.getLength() > 1) {
|
if (cu.getLength() > 1) {
|
||||||
@@ -227,6 +228,7 @@ public class XReferenceUtil {
|
|||||||
* @return count of all offcut xrefs to the code unit
|
* @return count of all offcut xrefs to the code unit
|
||||||
*/
|
*/
|
||||||
public static int getOffcutXRefCount(CodeUnit cu) {
|
public static int getOffcutXRefCount(CodeUnit cu) {
|
||||||
|
|
||||||
Program prog = cu.getProgram();
|
Program prog = cu.getProgram();
|
||||||
if (prog == null) {
|
if (prog == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -300,7 +302,7 @@ public class XReferenceUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows all xrefs to the given location in a new table. These xrefs are retrieved
|
* Shows all xrefs to the given location in a new table. These xrefs are retrieved
|
||||||
* from the given supplier. Thus, it is up to the client to determine which xrefs to show.
|
* from the given supplier. Thus, it is up to the client to determine which xrefs to show.
|
||||||
*
|
*
|
||||||
* @param navigatable the navigatable used for navigation from the table
|
* @param navigatable the navigatable used for navigation from the table
|
||||||
@@ -322,7 +324,7 @@ public class XReferenceUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all xrefs to the given location. If in data, then xrefs to the specific data
|
* Returns all xrefs to the given location. If in data, then xrefs to the specific data
|
||||||
* component will be returned. Otherwise, the code unit containing the address of the
|
* component will be returned. Otherwise, the code unit containing the address of the
|
||||||
* given location will be used as the source of the xrefs.
|
* given location will be used as the source of the xrefs.
|
||||||
*
|
*
|
||||||
* @param location the location for which to get xrefs
|
* @param location the location for which to get xrefs
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.app.util;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import ghidra.app.nav.Navigatable;
|
||||||
|
import ghidra.app.plugin.core.table.TableComponentProvider;
|
||||||
|
import ghidra.app.util.query.TableService;
|
||||||
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataUtilities;
|
||||||
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.symbol.*;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
import ghidra.util.table.ReferencesFromTableModel;
|
||||||
|
import ghidra.util.table.field.ReferenceEndpoint;
|
||||||
|
|
||||||
|
public class XReferenceUtils {
|
||||||
|
|
||||||
|
// Methods in this class treat -1 as a key to return all references and
|
||||||
|
// not cap the result set.
|
||||||
|
private final static int ALL_REFS = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing the first <b><code>max</code></b>
|
||||||
|
* direct xref references to the specified code unit.
|
||||||
|
*
|
||||||
|
* @param cu the code unit to generate the xrefs
|
||||||
|
* @param max max number of xrefs to get, or -1 to get all references
|
||||||
|
*
|
||||||
|
* @return array first <b><code>max</code></b> xrefs to the code unit
|
||||||
|
*/
|
||||||
|
public final static List<Reference> getXReferences(CodeUnit cu, int max) {
|
||||||
|
Program program = cu.getProgram();
|
||||||
|
if (program == null) {
|
||||||
|
Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup the direct xrefs to the current code unit
|
||||||
|
List<Reference> xrefs = new ArrayList<>();
|
||||||
|
Address minAddress = cu.getMinAddress();
|
||||||
|
ReferenceIterator it = program.getReferenceManager().getReferencesTo(minAddress);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (xrefs.size() - max == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference ref = it.next();
|
||||||
|
xrefs.add(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for thunk reference
|
||||||
|
Function func = program.getFunctionManager().getFunctionAt(minAddress);
|
||||||
|
if (func != null) {
|
||||||
|
Address[] thunkAddrs = func.getFunctionThunkAddresses();
|
||||||
|
if (thunkAddrs != null) {
|
||||||
|
for (Address thunkAddr : thunkAddrs) {
|
||||||
|
xrefs.add(new ThunkReference(thunkAddr, func.getEntryPoint()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xrefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing all offcut xref references to the specified code unit
|
||||||
|
*
|
||||||
|
* @param cu the code unit to generate the offcut xrefs
|
||||||
|
* @param max max number of offcut xrefs to get, or -1 to get all offcut references
|
||||||
|
* @return array of all offcut xrefs to the code unit
|
||||||
|
*/
|
||||||
|
public static List<Reference> getOffcutXReferences(CodeUnit cu, int max) {
|
||||||
|
Program program = cu.getProgram();
|
||||||
|
if (program == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cu.getLength() <= 1) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Reference> offcuts = new ArrayList<>();
|
||||||
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
|
AddressSet set = new AddressSet(cu.getMinAddress().add(1), cu.getMaxAddress());
|
||||||
|
AddressIterator it = refMgr.getReferenceDestinationIterator(set, true);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Address addr = it.next();
|
||||||
|
ReferenceIterator refIter = refMgr.getReferencesTo(addr);
|
||||||
|
while (refIter.hasNext()) {
|
||||||
|
if (offcuts.size() - max == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference ref = refIter.next();
|
||||||
|
offcuts.add(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return offcuts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the provided lists with the direct and offcut xrefs to the specified variable
|
||||||
|
*
|
||||||
|
* @param var variable to get references
|
||||||
|
* @param xrefs list to put direct references in
|
||||||
|
* @param offcuts list to put offcut references in
|
||||||
|
*/
|
||||||
|
public static void getVariableRefs(Variable var, List<Reference> xrefs,
|
||||||
|
List<Reference> offcuts) {
|
||||||
|
getVariableRefs(var, xrefs, offcuts, ALL_REFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the provided lists with the direct and offcut xrefs to the specified variable
|
||||||
|
*
|
||||||
|
* @param var variable to get references
|
||||||
|
* @param xrefs list to put direct references in
|
||||||
|
* @param offcuts list to put offcut references in
|
||||||
|
* @param max max number of xrefs to get, or -1 to get all references
|
||||||
|
*/
|
||||||
|
public static void getVariableRefs(Variable var, List<Reference> xrefs,
|
||||||
|
List<Reference> offcuts, int max) {
|
||||||
|
|
||||||
|
Address addr = var.getMinAddress();
|
||||||
|
if (addr == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program program = var.getFunction().getProgram();
|
||||||
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
|
Reference[] refs = refMgr.getReferencesTo(var);
|
||||||
|
int total = 0;
|
||||||
|
for (Reference vref : refs) {
|
||||||
|
if (total++ - max == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr.equals(vref.getToAddress())) {
|
||||||
|
xrefs.add(vref);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
offcuts.add(vref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all xrefs to the given location. If in data, then xrefs to the specific data
|
||||||
|
* component will be returned. Otherwise, the code unit containing the address of the
|
||||||
|
* given location will be used as the source of the xrefs.
|
||||||
|
*
|
||||||
|
* @param location the location for which to get xrefs
|
||||||
|
* @return the xrefs
|
||||||
|
*/
|
||||||
|
public static Set<Reference> getAllXrefs(ProgramLocation location) {
|
||||||
|
|
||||||
|
CodeUnit cu = DataUtilities.getDataAtLocation(location);
|
||||||
|
if (cu == null) {
|
||||||
|
Address toAddress = location.getAddress();
|
||||||
|
Listing listing = location.getProgram().getListing();
|
||||||
|
cu = listing.getCodeUnitContaining(toAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cu == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Reference> xrefs = getXReferences(cu, ALL_REFS);
|
||||||
|
List<Reference> offcuts = getOffcutXReferences(cu, ALL_REFS);
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
Set<Reference> set = new HashSet<>();
|
||||||
|
set.addAll(xrefs);
|
||||||
|
set.addAll(offcuts);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows all xrefs to the given location in a new table.
|
||||||
|
*
|
||||||
|
* @param navigatable the navigatable used for navigation from the table
|
||||||
|
* @param serviceProvider the service provider needed to wire navigation
|
||||||
|
* @param service the service needed to show the table
|
||||||
|
* @param location the location for which to find references
|
||||||
|
* @param xrefs the xrefs to show
|
||||||
|
*/
|
||||||
|
public static void showXrefs(Navigatable navigatable, ServiceProvider serviceProvider,
|
||||||
|
TableService service, ProgramLocation location, Collection<Reference> xrefs) {
|
||||||
|
|
||||||
|
ReferencesFromTableModel model =
|
||||||
|
new ReferencesFromTableModel(new ArrayList<>(xrefs), serviceProvider,
|
||||||
|
location.getProgram());
|
||||||
|
TableComponentProvider<ReferenceEndpoint> provider = service.showTable(
|
||||||
|
"XRefs to " + location.getAddress().toString(), "XRefs", model, "XRefs", navigatable);
|
||||||
|
provider.installRemoveItemsAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
+78
-34
@@ -17,12 +17,11 @@ package ghidra.app.util.exporter;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.util.XReferenceUtil;
|
import ghidra.app.util.XReferenceUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.ReferenceManager;
|
|
||||||
|
|
||||||
class ReferenceLineDispenser extends AbstractLineDispenser {
|
class ReferenceLineDispenser extends AbstractLineDispenser {
|
||||||
|
|
||||||
@@ -35,48 +34,46 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
private Memory memory;
|
private Memory memory;
|
||||||
private ReferenceManager referenceManager;
|
private ReferenceManager referenceManager;
|
||||||
|
|
||||||
private List<String> lines = new ArrayList<String>();
|
private List<String> lines = new ArrayList<>();
|
||||||
|
|
||||||
ReferenceLineDispenser() {
|
ReferenceLineDispenser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReferenceLineDispenser(boolean forwardRefs, CodeUnit cu, Program program, ProgramTextOptions options) {
|
ReferenceLineDispenser(boolean forwardRefs, CodeUnit cu, Program program,
|
||||||
this.memory = program.getMemory();
|
ProgramTextOptions options) {
|
||||||
|
this.memory = program.getMemory();
|
||||||
this.referenceManager = program.getReferenceManager();
|
this.referenceManager = program.getReferenceManager();
|
||||||
this.displayRefHeader = options.isShowReferenceHeaders();
|
this.displayRefHeader = options.isShowReferenceHeaders();
|
||||||
this.prefix = options.getCommentPrefix();
|
this.prefix = options.getCommentPrefix();
|
||||||
this.header = (forwardRefs ? " FWD" : "XREF");
|
this.header = (forwardRefs ? " FWD" : "XREF");
|
||||||
this.headerWidth = options.getRefHeaderWidth();
|
this.headerWidth = options.getRefHeaderWidth();
|
||||||
this.width = options.getRefWidth();
|
this.width = options.getRefWidth();
|
||||||
this.fillAmount = options.getAddrWidth()
|
this.fillAmount =
|
||||||
+ options.getBytesWidth()
|
options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth();
|
||||||
+ options.getLabelWidth();
|
|
||||||
this.isHTML = options.isHTML();
|
this.isHTML = options.isHTML();
|
||||||
|
|
||||||
Address [] refs = (forwardRefs ? getForwardRefs(cu) : XReferenceUtil.getXRefList(cu));
|
Address[] refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
|
||||||
Address [] offcuts = (forwardRefs ? EMPTY_ADDR_ARR : XReferenceUtil.getOffcutXRefList(cu));
|
Address[] offcuts = (forwardRefs ? EMPTY_ADDR_ARR : getOffcutXRefList(cu));
|
||||||
|
|
||||||
processRefs(cu.getMinAddress(), refs, offcuts);
|
processRefs(cu.getMinAddress(), refs, offcuts);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReferenceLineDispenser(Variable var, Program program, ProgramTextOptions options) {
|
ReferenceLineDispenser(Variable var, Program program, ProgramTextOptions options) {
|
||||||
this.memory = program.getMemory();
|
this.memory = program.getMemory();
|
||||||
this.referenceManager = program.getReferenceManager();
|
this.referenceManager = program.getReferenceManager();
|
||||||
this.displayRefHeader = options.isShowReferenceHeaders();
|
this.displayRefHeader = options.isShowReferenceHeaders();
|
||||||
this.header = "XREF";
|
this.header = "XREF";
|
||||||
this.headerWidth = options.getRefHeaderWidth();
|
this.headerWidth = options.getRefHeaderWidth();
|
||||||
this.prefix = options.getCommentPrefix();
|
this.prefix = options.getCommentPrefix();
|
||||||
this.width = options.getStackVarXrefWidth();
|
this.width = options.getStackVarXrefWidth();
|
||||||
this.fillAmount = options.getStackVarPreNameWidth()
|
this.fillAmount = options.getStackVarPreNameWidth() + options.getStackVarNameWidth() +
|
||||||
+ options.getStackVarNameWidth()
|
options.getStackVarDataTypeWidth() + options.getStackVarOffsetWidth() +
|
||||||
+ options.getStackVarDataTypeWidth()
|
options.getStackVarCommentWidth();
|
||||||
+ options.getStackVarOffsetWidth()
|
|
||||||
+ options.getStackVarCommentWidth();
|
|
||||||
this.isHTML = options.isHTML();
|
this.isHTML = options.isHTML();
|
||||||
|
|
||||||
List<Reference> xrefs = new ArrayList<Reference>();
|
List<Reference> xrefs = new ArrayList<>();
|
||||||
List<Reference> offcuts = new ArrayList<Reference>();
|
List<Reference> offcuts = new ArrayList<>();
|
||||||
XReferenceUtil.getVariableRefs(var, xrefs, offcuts);
|
XReferenceUtils.getVariableRefs(var, xrefs, offcuts);
|
||||||
Address[] xrefAddr = extractFromAddr(xrefs);
|
Address[] xrefAddr = extractFromAddr(xrefs);
|
||||||
Address[] offcutsAddr = extractFromAddr(offcuts);
|
Address[] offcutsAddr = extractFromAddr(offcuts);
|
||||||
|
|
||||||
@@ -84,9 +81,9 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
xrefAddr, offcutsAddr);
|
xrefAddr, offcutsAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Address [] extractFromAddr(List<Reference> refs) {
|
private Address[] extractFromAddr(List<Reference> refs) {
|
||||||
Address [] addrs = new Address[refs.size()];
|
Address[] addrs = new Address[refs.size()];
|
||||||
for (int i=0; i < addrs.length; i++) {
|
for (int i = 0; i < addrs.length; i++) {
|
||||||
addrs[i] = refs.get(i).getFromAddress();
|
addrs[i] = refs.get(i).getFromAddress();
|
||||||
}
|
}
|
||||||
Arrays.sort(addrs);
|
Arrays.sort(addrs);
|
||||||
@@ -113,18 +110,18 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Address [] getForwardRefs(CodeUnit cu) {
|
private Address[] getForwardRefs(CodeUnit cu) {
|
||||||
boolean showRefs = false;
|
boolean showRefs = false;
|
||||||
|
|
||||||
Address cuAddr = cu.getMinAddress();
|
Address cuAddr = cu.getMinAddress();
|
||||||
Reference [] monRefs = cu.getMnemonicReferences();
|
Reference[] monRefs = cu.getMnemonicReferences();
|
||||||
Reference primMonRef = referenceManager.getPrimaryReferenceFrom(cuAddr, CodeUnit.MNEMONIC);
|
Reference primMonRef = referenceManager.getPrimaryReferenceFrom(cuAddr, CodeUnit.MNEMONIC);
|
||||||
showRefs = (monRefs.length == 1 && primMonRef == null) || (monRefs.length > 1);
|
showRefs = (monRefs.length == 1 && primMonRef == null) || (monRefs.length > 1);
|
||||||
|
|
||||||
if (!showRefs) {
|
if (!showRefs) {
|
||||||
int opCount = cu.getNumOperands();
|
int opCount = cu.getNumOperands();
|
||||||
for (int i = 0 ; i < opCount ; ++i) {
|
for (int i = 0; i < opCount; ++i) {
|
||||||
Reference [] opRefs = cu.getOperandReferences(i);
|
Reference[] opRefs = cu.getOperandReferences(i);
|
||||||
if (opRefs.length > 1) {
|
if (opRefs.length > 1) {
|
||||||
showRefs = true;
|
showRefs = true;
|
||||||
break;
|
break;
|
||||||
@@ -136,9 +133,9 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
return EMPTY_ADDR_ARR;
|
return EMPTY_ADDR_ARR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference [] mRefs = cu.getReferencesFrom();
|
Reference[] mRefs = cu.getReferencesFrom();
|
||||||
Address [] refs = new Address[mRefs.length];
|
Address[] refs = new Address[mRefs.length];
|
||||||
for (int i = 0 ; i < mRefs.length ; ++i) {
|
for (int i = 0; i < mRefs.length; ++i) {
|
||||||
refs[i] = mRefs[i].getToAddress();
|
refs[i] = mRefs[i].getToAddress();
|
||||||
}
|
}
|
||||||
Arrays.sort(refs);
|
Arrays.sort(refs);
|
||||||
@@ -147,7 +144,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void processRefs(Address addr, Address [] refs, Address [] offcuts) {
|
private void processRefs(Address addr, Address[] refs, Address[] offcuts) {
|
||||||
if (width < 1) {
|
if (width < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -157,8 +154,8 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
|
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
|
|
||||||
Address [] all = new Address[refs.length + offcuts.length];
|
Address[] all = new Address[refs.length + offcuts.length];
|
||||||
System.arraycopy( refs, 0, all, 0, refs.length);
|
System.arraycopy(refs, 0, all, 0, refs.length);
|
||||||
System.arraycopy(offcuts, 0, all, refs.length, offcuts.length);
|
System.arraycopy(offcuts, 0, all, refs.length, offcuts.length);
|
||||||
|
|
||||||
if (displayRefHeader) {
|
if (displayRefHeader) {
|
||||||
@@ -224,4 +221,51 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
|
|||||||
buf.delete(0, buf.length());
|
buf.delete(0, buf.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Address[] getXRefList(CodeUnit cu) {
|
||||||
|
Program prog = cu.getProgram();
|
||||||
|
if (prog == null) {
|
||||||
|
return new Address[0];
|
||||||
|
}
|
||||||
|
List<Address> xrefList = new ArrayList<>();
|
||||||
|
//lookup the direct xrefs to the current code unit
|
||||||
|
//
|
||||||
|
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Reference ref = iter.next();
|
||||||
|
xrefList.add(ref.getFromAddress());
|
||||||
|
}
|
||||||
|
Address[] arr = new Address[xrefList.size()];
|
||||||
|
xrefList.toArray(arr);
|
||||||
|
Arrays.sort(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Address[] getOffcutXRefList(CodeUnit cu) {
|
||||||
|
Program prog = cu.getProgram();
|
||||||
|
if (prog == null) {
|
||||||
|
return new Address[0];
|
||||||
|
}
|
||||||
|
List<Address> offcutList = new ArrayList<>();
|
||||||
|
// Lookup the offcut xrefs...
|
||||||
|
//
|
||||||
|
if (cu.getLength() > 1) {
|
||||||
|
ReferenceManager refMgr = prog.getReferenceManager();
|
||||||
|
AddressSet set =
|
||||||
|
new AddressSet(cu.getMinAddress().add(1), cu.getMaxAddress());
|
||||||
|
AddressIterator iter = refMgr.getReferenceDestinationIterator(set, true);
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Address addr = iter.next();
|
||||||
|
ReferenceIterator refIter = refMgr.getReferencesTo(addr);
|
||||||
|
while (refIter.hasNext()) {
|
||||||
|
Reference ref = refIter.next();
|
||||||
|
offcutList.add(ref.getFromAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Address[] arr = new Address[offcutList.size()];
|
||||||
|
offcutList.toArray(arr);
|
||||||
|
Arrays.sort(arr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,18 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.viewer.field;
|
package ghidra.app.util.viewer.field;
|
||||||
|
|
||||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
|
||||||
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
|
||||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.*;
|
||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||||
|
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
||||||
|
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field responsible for drawing +/- symbols when over an aggregate datatype that
|
* Field responsible for drawing +/- symbols when over an aggregate datatype that
|
||||||
@@ -177,7 +175,8 @@ public class IndentField implements ListingField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
g.setColor(Color.LIGHT_GRAY);
|
g.setColor(Color.LIGHT_GRAY);
|
||||||
|
|
||||||
// draw the vertical lines to the left of the data (these are shown when there are vertical
|
// draw the vertical lines to the left of the data (these are shown when there are vertical
|
||||||
@@ -228,6 +227,11 @@ public class IndentField implements ListingField {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -307,7 +311,7 @@ public class IndentField implements ListingField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
return new RowColLocation(0, 0);
|
return new DefaultRowColLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+30
-15
@@ -17,6 +17,8 @@ package ghidra.app.util.viewer.field;
|
|||||||
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
@@ -34,7 +36,7 @@ import ghidra.app.util.viewer.proxy.ProxyObj;
|
|||||||
*/
|
*/
|
||||||
public class ListingTextField implements ListingField, TextField {
|
public class ListingTextField implements ListingField, TextField {
|
||||||
|
|
||||||
private ProxyObj proxy;
|
private ProxyObj<?> proxy;
|
||||||
private FieldFactory factory;
|
private FieldFactory factory;
|
||||||
protected TextField field;
|
protected TextField field;
|
||||||
|
|
||||||
@@ -47,9 +49,11 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
* @param startX the starting X position of the field
|
* @param startX the starting X position of the field
|
||||||
* @param width the width of the field
|
* @param width the width of the field
|
||||||
* @param provider the highlight provider.
|
* @param provider the highlight provider.
|
||||||
|
* @return the text field.
|
||||||
*/
|
*/
|
||||||
public static ListingTextField createSingleLineTextField(FieldFactory factory, ProxyObj proxy,
|
public static ListingTextField createSingleLineTextField(FieldFactory factory,
|
||||||
FieldElement fieldElement, int startX, int width, HighlightProvider provider) {
|
ProxyObj<?> proxy, FieldElement fieldElement, int startX, int width,
|
||||||
|
HighlightProvider provider) {
|
||||||
|
|
||||||
HighlightFactory hlFactory =
|
HighlightFactory hlFactory =
|
||||||
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
||||||
@@ -58,7 +62,7 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ListingTextField createSingleLineTextFieldWithReverseClipping(
|
public static ListingTextField createSingleLineTextFieldWithReverseClipping(
|
||||||
AddressFieldFactory factory, ProxyObj proxy, FieldElement fieldElement, int startX,
|
AddressFieldFactory factory, ProxyObj<?> proxy, FieldElement fieldElement, int startX,
|
||||||
int width, HighlightProvider provider) {
|
int width, HighlightProvider provider) {
|
||||||
HighlightFactory hlFactory =
|
HighlightFactory hlFactory =
|
||||||
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
||||||
@@ -67,7 +71,7 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the given text, word-wrapping as needed to avoid clipping (up to the max number of
|
* Displays the given text, word-wrapping as needed to avoid clipping (up to the max number of
|
||||||
* lines.)
|
* lines.)
|
||||||
* @param factory the field factory that generated this field
|
* @param factory the field factory that generated this field
|
||||||
* @param proxy the object used to populate this field
|
* @param proxy the object used to populate this field
|
||||||
@@ -77,9 +81,10 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
* @param width the width of the field
|
* @param width the width of the field
|
||||||
* @param maxLines the maxLines to display.
|
* @param maxLines the maxLines to display.
|
||||||
* @param provider the highlight provider.
|
* @param provider the highlight provider.
|
||||||
|
* @return the text field.
|
||||||
*/
|
*/
|
||||||
public static ListingTextField createWordWrappedTextField(FieldFactory factory, ProxyObj proxy,
|
public static ListingTextField createWordWrappedTextField(FieldFactory factory,
|
||||||
FieldElement fieldElement, int startX, int width, int maxLines,
|
ProxyObj<?> proxy, FieldElement fieldElement, int startX, int width, int maxLines,
|
||||||
HighlightProvider provider) {
|
HighlightProvider provider) {
|
||||||
|
|
||||||
HighlightFactory hlFactory =
|
HighlightFactory hlFactory =
|
||||||
@@ -100,14 +105,16 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
* @param width the width of the field
|
* @param width the width of the field
|
||||||
* @param maxLines the maxLines to display.
|
* @param maxLines the maxLines to display.
|
||||||
* @param provider the highlight provider.
|
* @param provider the highlight provider.
|
||||||
|
* @return the text field.
|
||||||
*/
|
*/
|
||||||
public static ListingTextField createPackedTextField(FieldFactory factory, ProxyObj proxy,
|
public static ListingTextField createPackedTextField(FieldFactory factory, ProxyObj<?> proxy,
|
||||||
FieldElement[] textElements, int startX, int width, int maxLines,
|
FieldElement[] textElements, int startX, int width, int maxLines,
|
||||||
HighlightProvider provider) {
|
HighlightProvider provider) {
|
||||||
|
|
||||||
HighlightFactory hlFactory =
|
HighlightFactory hlFactory =
|
||||||
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
||||||
TextField field = new FlowLayoutTextField(textElements, startX, width, maxLines, hlFactory);
|
List<FieldElement> list = Arrays.asList(textElements);
|
||||||
|
TextField field = new FlowLayoutTextField(list, startX, width, maxLines, hlFactory);
|
||||||
return new ListingTextField(factory, proxy, field);
|
return new ListingTextField(factory, proxy, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,22 +125,24 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
* @param textElements the array of elements for the field.
|
* @param textElements the array of elements for the field.
|
||||||
* Each of these holds text, attributes and location information.
|
* Each of these holds text, attributes and location information.
|
||||||
* @param startX the starting X position of the field
|
* @param startX the starting X position of the field
|
||||||
* @param width the widht of the field
|
* @param width the width of the field
|
||||||
* @param maxLines the maxLines to display.
|
* @param maxLines the maxLines to display.
|
||||||
* @param provider the highlight provider
|
* @param provider the highlight provider
|
||||||
|
* @return the text field.
|
||||||
*/
|
*/
|
||||||
public static ListingTextField createMultilineTextField(FieldFactory factory, ProxyObj proxy,
|
public static ListingTextField createMultilineTextField(FieldFactory factory, ProxyObj<?> proxy,
|
||||||
FieldElement[] textElements, int startX, int width, int maxLines,
|
FieldElement[] textElements, int startX, int width, int maxLines,
|
||||||
HighlightProvider provider) {
|
HighlightProvider provider) {
|
||||||
|
|
||||||
HighlightFactory hlFactory =
|
HighlightFactory hlFactory =
|
||||||
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
new FieldHighlightFactory(provider, factory.getClass(), proxy.getObject());
|
||||||
|
List<FieldElement> list = Arrays.asList(textElements);
|
||||||
TextField field =
|
TextField field =
|
||||||
new VerticalLayoutTextField(textElements, startX, width, maxLines, hlFactory);
|
new VerticalLayoutTextField(list, startX, width, maxLines, hlFactory);
|
||||||
return new ListingTextField(factory, proxy, field);
|
return new ListingTextField(factory, proxy, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ListingTextField(FieldFactory factory, ProxyObj proxy, TextField field) {
|
protected ListingTextField(FieldFactory factory, ProxyObj<?> proxy, TextField field) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
this.field = field;
|
this.field = field;
|
||||||
@@ -186,7 +195,8 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
field.paint(c, g, context, clip, map, cursorLoc, rowHeight);
|
field.paint(c, g, context, clip, map, cursorLoc, rowHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +205,11 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
return field.contains(x, y);
|
return field.contains(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return field.getNumDataRows();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return field.getNumRows();
|
return field.getNumRows();
|
||||||
@@ -281,7 +296,7 @@ public class ListingTextField implements ListingField, TextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProxyObj getProxy() {
|
public ProxyObj<?> getProxy() {
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
return EmptyProxy.EMPTY_PROXY;
|
return EmptyProxy.EMPTY_PROXY;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -33,8 +33,8 @@ public class NamespacePropertyEditor extends PropertyEditorSupport implements Cu
|
|||||||
|
|
||||||
private static final String DISPLAY_LOCAL_NAMESPACE_LABEL = "Display Local Namespace";
|
private static final String DISPLAY_LOCAL_NAMESPACE_LABEL = "Display Local Namespace";
|
||||||
private static final String DISPLAY_NON_LOCAL_NAMESPACE_LABEL = "Display Non-local Namespace";
|
private static final String DISPLAY_NON_LOCAL_NAMESPACE_LABEL = "Display Non-local Namespace";
|
||||||
private static final String LOCAL_NAMESPACE_PREFIX_LABEL = "Local namespace prefix";
|
private static final String LOCAL_NAMESPACE_PREFIX_LABEL = "Local Namespace Prefix";
|
||||||
private static final String DISPLAY_LIBRARY_IN_NAMESPACE_LABEL = "Display library in namespace";
|
private static final String DISPLAY_LIBRARY_IN_NAMESPACE_LABEL = "Display library in Namespace";
|
||||||
|
|
||||||
private static final String[] NAMES =
|
private static final String[] NAMES =
|
||||||
{ DISPLAY_LOCAL_NAMESPACE_LABEL, DISPLAY_NON_LOCAL_NAMESPACE_LABEL,
|
{ DISPLAY_LOCAL_NAMESPACE_LABEL, DISPLAY_NON_LOCAL_NAMESPACE_LABEL,
|
||||||
@@ -94,7 +94,7 @@ public class NamespacePropertyEditor extends PropertyEditorSupport implements Cu
|
|||||||
|
|
||||||
showLocalCheckBox.addItemListener(e -> {
|
showLocalCheckBox.addItemListener(e -> {
|
||||||
boolean enabled = showLocalCheckBox.isSelected();
|
boolean enabled = showLocalCheckBox.isSelected();
|
||||||
// only enable the text field if we are showing namespaces AND we are
|
// only enable the text field if we are showing namespaces AND we are
|
||||||
// overriding the display value
|
// overriding the display value
|
||||||
localPrefixField.setEnabled(enabled && useLocalPrefixCheckBox.isSelected());
|
localPrefixField.setEnabled(enabled && useLocalPrefixCheckBox.isSelected());
|
||||||
useLocalPrefixCheckBox.setEnabled(enabled);
|
useLocalPrefixCheckBox.setEnabled(enabled);
|
||||||
|
|||||||
+15
-10
@@ -22,8 +22,7 @@ import javax.swing.JComponent;
|
|||||||
|
|
||||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.*;
|
||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
|
||||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||||
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
||||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||||
@@ -153,15 +152,16 @@ public class OpenCloseField implements ListingField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
|
|
||||||
// center in the heightAbove area (negative, since 0 is the baseline of text, which is at
|
// center in the heightAbove area (negative, since 0 is the baseline of text, which is at
|
||||||
// the bottom of the heightAbove)
|
// the bottom of the heightAbove)
|
||||||
int toggleHandleStartY = -((heightAbove / 2) + (toggleHandleSize / 2));
|
int toggleHandleStartY = -((heightAbove / 2) + (toggleHandleSize / 2));
|
||||||
int toggleHandleStartX = startX + (indentLevel * fieldWidth) + insetSpace;
|
int toggleHandleStartX = startX + (indentLevel * fieldWidth) + insetSpace;
|
||||||
|
|
||||||
// TODO: If we're in printing mode, trying to render these open/close images
|
// TODO: If we're in printing mode, trying to render these open/close images
|
||||||
// causes the JVM to bomb. We'd like to eventually figure out why but in
|
// causes the JVM to bomb. We'd like to eventually figure out why but in
|
||||||
// the meantime we can safely comment this out and still generate an acceptable
|
// the meantime we can safely comment this out and still generate an acceptable
|
||||||
// image.
|
// image.
|
||||||
//
|
//
|
||||||
@@ -178,7 +178,7 @@ public class OpenCloseField implements ListingField {
|
|||||||
|
|
||||||
g.setColor(Color.LIGHT_GRAY);
|
g.setColor(Color.LIGHT_GRAY);
|
||||||
|
|
||||||
// draw the vertical lines to the left of the toggle handle (these are shown when
|
// draw the vertical lines to the left of the toggle handle (these are shown when
|
||||||
// there are vertical bars drawn for inset data)
|
// there are vertical bars drawn for inset data)
|
||||||
int fieldTopY = -heightAbove;
|
int fieldTopY = -heightAbove;
|
||||||
int fieldBottomY = heightBelow;
|
int fieldBottomY = heightBelow;
|
||||||
@@ -205,7 +205,7 @@ public class OpenCloseField implements ListingField {
|
|||||||
|
|
||||||
boolean lastAndClosed = isLast && !isOpen;
|
boolean lastAndClosed = isLast && !isOpen;
|
||||||
if (!lastAndClosed) {
|
if (!lastAndClosed) {
|
||||||
// extended vertical line below toggle handle
|
// extended vertical line below toggle handle
|
||||||
int buttonBottomY = toggleHandleStartY + toggleHandleSize;
|
int buttonBottomY = toggleHandleStartY + toggleHandleSize;
|
||||||
g.drawLine(midpointX, buttonBottomY, midpointX, fieldBottomY);
|
g.drawLine(midpointX, buttonBottomY, midpointX, fieldBottomY);
|
||||||
}
|
}
|
||||||
@@ -231,6 +231,11 @@ public class OpenCloseField implements ListingField {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -310,7 +315,7 @@ public class OpenCloseField implements ListingField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
return new RowColLocation(0, 0);
|
return new DefaultRowColLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -332,7 +337,7 @@ public class OpenCloseField implements ListingField {
|
|||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Static Methods
|
// Static Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
static int getOpenCloseHandleSize() {
|
static int getOpenCloseHandleSize() {
|
||||||
return openImage.getIconWidth();
|
return openImage.getIconWidth();
|
||||||
|
|||||||
+7
-10
@@ -141,26 +141,23 @@ public class PlateFieldFactory extends FieldFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CodeUnit cu = (CodeUnit) proxy.getObject();
|
CodeUnit cu = (CodeUnit) proxy.getObject();
|
||||||
List<FieldElement> elementList = new ArrayList<>(10);
|
List<FieldElement> elements = new ArrayList<>(10);
|
||||||
boolean isClipped = false;
|
boolean isClipped = false;
|
||||||
String commentText = getCommentText(cu);
|
String commentText = getCommentText(cu);
|
||||||
if ((commentText == null) || (commentText.isEmpty())) {
|
if ((commentText == null) || (commentText.isEmpty())) {
|
||||||
generateDefaultPlate(elementList, cu);
|
generateDefaultPlate(elements, cu);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
isClipped = generateFormattedPlateComment(elementList, cu);
|
isClipped = generateFormattedPlateComment(elements, cu);
|
||||||
}
|
}
|
||||||
|
|
||||||
addBlankLines(elementList, cu);
|
addBlankLines(elements, cu);
|
||||||
|
|
||||||
if (elementList.size() == 0) {
|
if (elements.size() == 0) {
|
||||||
// no real or default comment
|
// no real or default comment
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldElement[] fields = new FieldElement[elementList.size()];
|
|
||||||
elementList.toArray(fields);
|
|
||||||
|
|
||||||
if (isNestedDataAtSameAddressAsParent(proxy)) {
|
if (isNestedDataAtSameAddressAsParent(proxy)) {
|
||||||
// This is data at the same address as the parent, which happens with the first
|
// This is data at the same address as the parent, which happens with the first
|
||||||
// element in a structure. We do not want to the plate comment here, but only at the
|
// element in a structure. We do not want to the plate comment here, but only at the
|
||||||
@@ -169,7 +166,7 @@ public class PlateFieldFactory extends FieldFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlateFieldTextField textField =
|
PlateFieldTextField textField =
|
||||||
new PlateFieldTextField(fields, this, proxy, startX, width, commentText, isClipped);
|
new PlateFieldTextField(elements, this, proxy, startX, width, commentText, isClipped);
|
||||||
return new PlateListingTextField(proxy, textField);
|
return new PlateListingTextField(proxy, textField);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,7 +703,7 @@ public class PlateFieldFactory extends FieldFactory {
|
|||||||
private boolean isCommentClipped;
|
private boolean isCommentClipped;
|
||||||
private String commentText;
|
private String commentText;
|
||||||
|
|
||||||
public PlateFieldTextField(FieldElement[] textElements, PlateFieldFactory factory,
|
public PlateFieldTextField(List<FieldElement> textElements, PlateFieldFactory factory,
|
||||||
ProxyObj<?> proxy, int startX, int width, String commentText,
|
ProxyObj<?> proxy, int startX, int width, String commentText,
|
||||||
boolean isCommentClipped) {
|
boolean isCommentClipped) {
|
||||||
super(textElements, startX, width, Integer.MAX_VALUE,
|
super(textElements, startX, width, Integer.MAX_VALUE,
|
||||||
|
|||||||
+5
-19
@@ -23,7 +23,7 @@ import docking.widgets.fieldpanel.field.*;
|
|||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
import ghidra.app.util.HighlightProvider;
|
import ghidra.app.util.HighlightProvider;
|
||||||
import ghidra.app.util.XReferenceUtil;
|
import ghidra.app.util.XReferenceUtils;
|
||||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
@@ -36,8 +36,6 @@ import ghidra.program.util.VariableXRefFieldLocation;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable Cross-reference Field Factory
|
* Variable Cross-reference Field Factory
|
||||||
* <br>
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class VariableXRefFieldFactory extends XRefFieldFactory {
|
public class VariableXRefFieldFactory extends XRefFieldFactory {
|
||||||
|
|
||||||
@@ -76,9 +74,6 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
initDisplayOptions();
|
initDisplayOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.util.viewer.field.FieldFactory#getField(ProxyObj, int)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ListingField getField(ProxyObj<?> proxy, int varWidth) {
|
public ListingField getField(ProxyObj<?> proxy, int varWidth) {
|
||||||
Object obj = proxy.getObject();
|
Object obj = proxy.getObject();
|
||||||
@@ -89,7 +84,7 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
Variable var = (Variable) obj;
|
Variable var = (Variable) obj;
|
||||||
List<Reference> xrefs = new ArrayList<>();
|
List<Reference> xrefs = new ArrayList<>();
|
||||||
List<Reference> offcuts = new ArrayList<>();
|
List<Reference> offcuts = new ArrayList<>();
|
||||||
XReferenceUtil.getVariableRefs(var, xrefs, offcuts);
|
XReferenceUtils.getVariableRefs(var, xrefs, offcuts, maxXRefs);
|
||||||
|
|
||||||
if (xrefs.size() + offcuts.size() == 0) {
|
if (xrefs.size() + offcuts.size() == 0) {
|
||||||
return null;
|
return null;
|
||||||
@@ -164,9 +159,6 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
width, maxXRefs, hlProvider);
|
width, maxXRefs, hlProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.util.viewer.field.FieldFactory#getFieldLocation(ghidra.app.util.viewer.field.ListingField, BigInteger, int, ghidra.program.util.ProgramLocation)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum,
|
public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum,
|
||||||
ProgramLocation loc) {
|
ProgramLocation loc) {
|
||||||
@@ -188,9 +180,6 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation(int row, int col, ListingField bf) {
|
public ProgramLocation getProgramLocation(int row, int col, ListingField bf) {
|
||||||
Object obj = bf.getProxy().getObject();
|
Object obj = bf.getProxy().getObject();
|
||||||
@@ -207,7 +196,7 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
Variable var = (Variable) obj;
|
Variable var = (Variable) obj;
|
||||||
List<Reference> xrefs = new ArrayList<>();
|
List<Reference> xrefs = new ArrayList<>();
|
||||||
List<Reference> offcuts = new ArrayList<>();
|
List<Reference> offcuts = new ArrayList<>();
|
||||||
XReferenceUtil.getVariableRefs(var, xrefs, offcuts);
|
XReferenceUtils.getVariableRefs(var, xrefs, offcuts, maxXRefs);
|
||||||
|
|
||||||
Reference ref = null;
|
Reference ref = null;
|
||||||
if (index < xrefs.size()) {
|
if (index < xrefs.size()) {
|
||||||
@@ -225,9 +214,6 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.app.util.viewer.field.FieldFactory#acceptsType(int, java.lang.Class)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptsType(int category, Class<?> proxyObjectClass) {
|
public boolean acceptsType(int category, Class<?> proxyObjectClass) {
|
||||||
if (!Variable.class.isAssignableFrom(proxyObjectClass)) {
|
if (!Variable.class.isAssignableFrom(proxyObjectClass)) {
|
||||||
@@ -239,7 +225,7 @@ public class VariableXRefFieldFactory extends XRefFieldFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
|
public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider,
|
||||||
ToolOptions displayOptions, ToolOptions fieldOptions) {
|
ToolOptions options, ToolOptions fieldOptions) {
|
||||||
return new VariableXRefFieldFactory(formatModel, provider, displayOptions, fieldOptions);
|
return new VariableXRefFieldFactory(formatModel, provider, options, fieldOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-3
@@ -15,16 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.viewer.field;
|
package ghidra.app.util.viewer.field;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import ghidra.app.nav.Navigatable;
|
import ghidra.app.nav.Navigatable;
|
||||||
import ghidra.app.util.XReferenceUtil;
|
import ghidra.app.util.XReferenceUtils;
|
||||||
import ghidra.app.util.query.TableService;
|
import ghidra.app.util.query.TableService;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.listing.Variable;
|
import ghidra.program.model.listing.Variable;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
|
import ghidra.program.model.symbol.ReferenceManager;
|
||||||
import ghidra.program.util.*;
|
import ghidra.program.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,7 +81,24 @@ public class VariableXRefFieldMouseHandler extends XRefFieldMouseHandler {
|
|||||||
VariableLocation variableLocation = (VariableLocation) location;
|
VariableLocation variableLocation = (VariableLocation) location;
|
||||||
Variable variable = variableLocation.getVariable();
|
Variable variable = variableLocation.getVariable();
|
||||||
|
|
||||||
Set<Reference> refs = XReferenceUtil.getVariableRefs(variable);
|
Set<Reference> refs = getVariableRefs(variable);
|
||||||
XReferenceUtil.showAllXrefs(navigatable, serviceProvider, service, location, refs);
|
XReferenceUtils.showXrefs(navigatable, serviceProvider, service, location, refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Reference> getVariableRefs(Variable var) {
|
||||||
|
|
||||||
|
Set<Reference> results = new HashSet<>();
|
||||||
|
Address addr = var.getMinAddress();
|
||||||
|
if (addr == null) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program program = var.getFunction().getProgram();
|
||||||
|
ReferenceManager refMgr = program.getReferenceManager();
|
||||||
|
Reference[] refs = refMgr.getReferencesTo(var);
|
||||||
|
for (Reference vref : refs) {
|
||||||
|
results.add(vref);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+517
-144
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -22,7 +22,7 @@ import docking.widgets.fieldpanel.field.FieldElement;
|
|||||||
import docking.widgets.fieldpanel.field.TextField;
|
import docking.widgets.fieldpanel.field.TextField;
|
||||||
import ghidra.app.nav.Navigatable;
|
import ghidra.app.nav.Navigatable;
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.util.XReferenceUtil;
|
import ghidra.app.util.XReferenceUtils;
|
||||||
import ghidra.app.util.query.TableService;
|
import ghidra.app.util.query.TableService;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
@@ -51,7 +51,7 @@ public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If I double-click on the XRef Header, show references to this place, also works on
|
// If I double-click on the XRef Header, show references to this place, also works on
|
||||||
// 'more' field. This is much nicer if you have multiple references to navigate.
|
// 'more' field. This is much nicer if you have multiple references to navigate.
|
||||||
if (isXREFHeaderLocation(location)) {
|
if (isXREFHeaderLocation(location)) {
|
||||||
showXRefDialog(sourceNavigatable, location, serviceProvider);
|
showXRefDialog(sourceNavigatable, location, serviceProvider);
|
||||||
@@ -105,8 +105,8 @@ public class XRefFieldMouseHandler implements FieldMouseHandlerExtension {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Reference> refs = XReferenceUtil.getAllXrefs(location);
|
Set<Reference> refs = XReferenceUtils.getAllXrefs(location);
|
||||||
XReferenceUtil.showAllXrefs(navigatable, serviceProvider, service, location, refs);
|
XReferenceUtils.showXrefs(navigatable, serviceProvider, service, location, refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProgramLocation getReferredToLocation(Navigatable sourceNavigatable,
|
protected ProgramLocation getReferredToLocation(Navigatable sourceNavigatable,
|
||||||
|
|||||||
+15
-7
@@ -16,17 +16,19 @@
|
|||||||
package ghidra.app.util.viewer.field;
|
package ghidra.app.util.viewer.field;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.field.*;
|
import docking.widgets.fieldpanel.field.*;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||||
import ghidra.app.util.HighlightProvider;
|
import ghidra.app.util.HighlightProvider;
|
||||||
import ghidra.app.util.XReferenceUtil;
|
import ghidra.app.util.XReferenceUtils;
|
||||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.program.util.XRefHeaderFieldLocation;
|
import ghidra.program.util.XRefHeaderFieldLocation;
|
||||||
|
|
||||||
@@ -126,14 +128,20 @@ public class XRefHeaderFieldFactory extends XRefFieldFactory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Program prog = cu.getProgram();
|
Program prog = cu.getProgram();
|
||||||
int xrefCnt = prog.getReferenceManager().getReferenceCountTo(cu.getMinAddress());
|
int xrefCount = prog.getReferenceManager().getReferenceCountTo(cu.getMinAddress());
|
||||||
int offcutCnt = XReferenceUtil.getOffcutXRefCount(cu);
|
List<Reference> offcuts = XReferenceUtils.getOffcutXReferences(cu, maxXRefs);
|
||||||
|
int offcutCount = offcuts.size();
|
||||||
|
|
||||||
if (offcutCnt > 0) {
|
if (offcutCount > 0) {
|
||||||
return "XREF[" + xrefCnt + "," + offcutCnt + "]: ";
|
String modifier = "";
|
||||||
|
if (offcutCount == maxXRefs) {
|
||||||
|
modifier = "+";
|
||||||
|
}
|
||||||
|
return "XREF[" + xrefCount + "," + offcutCount + modifier + "]: ";
|
||||||
}
|
}
|
||||||
if (xrefCnt > 0) {
|
|
||||||
return "XREF[" + xrefCnt + "]: ";
|
if (xrefCount > 0) {
|
||||||
|
return "XREF[" + xrefCount + "]: ";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-5
@@ -41,10 +41,6 @@ public class EolCommentFieldFactoryTest extends AbstractGhidraHeadedIntegrationT
|
|||||||
private Options fieldOptions;
|
private Options fieldOptions;
|
||||||
private Program program;
|
private Program program;
|
||||||
|
|
||||||
public EolCommentFieldFactoryTest() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
@@ -87,7 +83,7 @@ public class EolCommentFieldFactoryTest extends AbstractGhidraHeadedIntegrationT
|
|||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private ProgramDB buildProgram() throws Exception {
|
private ProgramDB buildProgram() throws Exception {
|
||||||
ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._TOY, this);
|
ProgramBuilder builder = new ProgramBuilder("sample", ProgramBuilder._TOY, this);
|
||||||
builder.createMemory(".text", "0x1001000", 0x6600);
|
builder.createMemory(".text", "0x1001000", 0x6600);
|
||||||
builder.createEmptyFunction(null, "0x1002000", 20, null);
|
builder.createEmptyFunction(null, "0x1002000", 20, null);
|
||||||
|
|
||||||
|
|||||||
+623
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -33,7 +33,7 @@ public class ClangTextField extends WrappingVerticalLayoutTextField {
|
|||||||
private FieldElement lineNumberFieldElement;
|
private FieldElement lineNumberFieldElement;
|
||||||
|
|
||||||
private static FieldElement createSingleLineElement(FieldElement[] textElements) {
|
private static FieldElement createSingleLineElement(FieldElement[] textElements) {
|
||||||
return new CompositeFieldElement(textElements, 0, textElements.length);
|
return new CompositeFieldElement(textElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+9
-9
@@ -48,7 +48,7 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
private static final PaintContext PAINT_CONTEXT = new PaintContext();
|
private static final PaintContext PAINT_CONTEXT = new PaintContext();
|
||||||
private static final ClipboardType TEXT_TYPE =
|
private static final ClipboardType TEXT_TYPE =
|
||||||
new ClipboardType(DataFlavor.stringFlavor, "Text");
|
new ClipboardType(DataFlavor.stringFlavor, "Text");
|
||||||
private static final List<ClipboardType> COPY_TYPES = new LinkedList<ClipboardType>();
|
private static final List<ClipboardType> COPY_TYPES = new LinkedList<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
COPY_TYPES.add(TEXT_TYPE);
|
COPY_TYPES.add(TEXT_TYPE);
|
||||||
@@ -58,7 +58,7 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
private FieldSelection selection;
|
private FieldSelection selection;
|
||||||
|
|
||||||
private boolean copyFromSelectionEnabled;
|
private boolean copyFromSelectionEnabled;
|
||||||
private Set<ChangeListener> listeners = new CopyOnWriteArraySet<ChangeListener>();
|
private Set<ChangeListener> listeners = new CopyOnWriteArraySet<>();
|
||||||
private int spaceCharWidthInPixels = 7;
|
private int spaceCharWidthInPixels = 7;
|
||||||
|
|
||||||
public DecompilerClipboardProvider(DecompilePlugin plugin, DecompilerProvider provider) {
|
public DecompilerClipboardProvider(DecompilePlugin plugin, DecompilerProvider provider) {
|
||||||
@@ -161,12 +161,12 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transferable copyText(TaskMonitor monitor) {
|
private Transferable copyText(TaskMonitor monitor) {
|
||||||
return createStringTransferable(getText());
|
return createStringTransferable(getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
String getText() {
|
private String getText() {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuilder buffer = new StringBuilder();
|
||||||
int numRanges = selection.getNumRanges();
|
int numRanges = selection.getNumRanges();
|
||||||
for (int i = 0; i < numRanges; i++) {
|
for (int i = 0; i < numRanges; i++) {
|
||||||
appendText(buffer, selection.getFieldRange(i));
|
appendText(buffer, selection.getFieldRange(i));
|
||||||
@@ -174,7 +174,7 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendText(StringBuffer buffer, FieldRange fieldRange) {
|
private void appendText(StringBuilder buffer, FieldRange fieldRange) {
|
||||||
int startIndex = fieldRange.getStart().getIndex().intValue();
|
int startIndex = fieldRange.getStart().getIndex().intValue();
|
||||||
int endIndex = fieldRange.getEnd().getIndex().intValue();
|
int endIndex = fieldRange.getEnd().getIndex().intValue();
|
||||||
if (startIndex == endIndex) { // single line selection (don't include padding)
|
if (startIndex == endIndex) { // single line selection (don't include padding)
|
||||||
@@ -189,7 +189,7 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendText(StringBuffer buffer, int lineNumber,
|
private void appendText(StringBuilder buffer, int lineNumber,
|
||||||
FieldSelection singleLineSelection) {
|
FieldSelection singleLineSelection) {
|
||||||
if (singleLineSelection.isEmpty()) {
|
if (singleLineSelection.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -224,7 +224,7 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendTextSingleLine(StringBuffer buffer, int lineNumber,
|
private void appendTextSingleLine(StringBuilder buffer, int lineNumber,
|
||||||
FieldSelection singleLineSelection) {
|
FieldSelection singleLineSelection) {
|
||||||
if (singleLineSelection.isEmpty()) {
|
if (singleLineSelection.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -249,7 +249,7 @@ public class DecompilerClipboardProvider extends ByteCopier
|
|||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Unsupported Operations
|
// Unsupported Operations
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean enablePaste() {
|
public boolean enablePaste() {
|
||||||
|
|||||||
+5
-4
@@ -24,9 +24,9 @@ import docking.widgets.fieldpanel.support.RowColLocation;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An object that wraps a string and provides data that describes how to render
|
* An object that wraps a string and provides data that describes how to render
|
||||||
* that string.
|
* that string.
|
||||||
* <p>
|
* <p>
|
||||||
* This class was created as a place to house attributes of rendering that
|
* This class was created as a place to house attributes of rendering that
|
||||||
* are not described by Java's Font object, like underlining.
|
* are not described by Java's Font object, like underlining.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -83,7 +83,7 @@ abstract public class AbstractTextFieldElement implements FieldElement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxCharactersForWidth(int width) {
|
public int getMaxCharactersForWidth(int width) {
|
||||||
return attributedString.getColumnPosition(width);
|
return attributedString.getCharPosition(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -112,7 +112,8 @@ abstract public class AbstractTextFieldElement implements FieldElement {
|
|||||||
@Override
|
@Override
|
||||||
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
||||||
if (characterIndex < 0 || characterIndex > attributedString.getText().length()) {
|
if (characterIndex < 0 || characterIndex > attributedString.getText().length()) {
|
||||||
throw new IllegalArgumentException("columnPosition is out of range: " + characterIndex);
|
throw new IllegalArgumentException("columnPosition is out of range: " + characterIndex +
|
||||||
|
"; range is [0," + attributedString.getText().length() + "]");
|
||||||
}
|
}
|
||||||
return new RowColLocation(row, column + characterIndex);
|
return new RowColLocation(row, column + characterIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -24,9 +24,9 @@ import docking.util.GraphicsUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* An object that wraps a string and provides data that describes how to render
|
* An object that wraps a string and provides data that describes how to render
|
||||||
* that string.
|
* that string.
|
||||||
* <p>
|
* <p>
|
||||||
* This class was created as a place to house attributes of rendering that
|
* This class was created as a place to house attributes of rendering that
|
||||||
* are not described by Java's Font object, like underlining.
|
* are not described by Java's Font object, like underlining.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -136,11 +136,11 @@ public class AttributedString {
|
|||||||
return fontMetrics.getMaxDescent() + UNDERLINE_HEIGHT;
|
return fontMetrics.getMaxDescent() + UNDERLINE_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getColumnPosition(int width) {
|
public int getCharPosition(int x) {
|
||||||
int subWidth = getIconWidth();
|
int subWidth = getIconWidth();
|
||||||
for (int i = 0; i < text.length(); i++) {
|
for (int i = 0; i < text.length(); i++) {
|
||||||
subWidth += fontMetrics.charWidth(text.charAt(i));
|
subWidth += fontMetrics.charWidth(text.charAt(i));
|
||||||
if (subWidth > width) {
|
if (subWidth > x) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-10
@@ -106,8 +106,7 @@ public class ClippingTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCol(int row, int x) {
|
public int getCol(int row, int x) {
|
||||||
int xPos = Math.max(x - startX, 0); // make x relative to this fields
|
int xPos = Math.max(x - startX, 0); // make x relative to this fields coordinate system
|
||||||
// coordinate system.
|
|
||||||
return textElement.getMaxCharactersForWidth(xPos);
|
return textElement.getMaxCharactersForWidth(xPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +133,13 @@ public class ClippingTextField implements TextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getNumCols() {
|
private int getNumCols() {
|
||||||
return textElement.length() + 1; // allow one column past the end of the text
|
// allow one column past the end of the text to allow the cursor to be placed after the text
|
||||||
|
return textElement.length() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -217,7 +222,8 @@ public class ClippingTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
if (context.isPrinting()) {
|
if (context.isPrinting()) {
|
||||||
print(g, context);
|
print(g, context);
|
||||||
}
|
}
|
||||||
@@ -329,14 +335,21 @@ public class ClippingTextField implements TextField {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
||||||
return textElement.getDataLocationForCharacterIndex(screenColumn);
|
return originalElement.getDataLocationForCharacterIndex(screenColumn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||||
int column = textElement.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
int column = textElement.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||||
return new RowColLocation(0, Math.max(column, 0));
|
if (column < 0) {
|
||||||
|
// place at the end if past the end
|
||||||
|
if (dataColumn >= textElement.length()) {
|
||||||
|
return new DefaultRowColLocation(0, textElement.length());
|
||||||
|
}
|
||||||
|
return new DefaultRowColLocation();
|
||||||
|
}
|
||||||
|
return new RowColLocation(0, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findX(int col) {
|
private int findX(int col) {
|
||||||
@@ -381,7 +394,8 @@ public class ClippingTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
return new RowColLocation(0, Math.min(textOffset, textElement.getText().length() - 1));
|
// allow the max position to be just after the last character
|
||||||
|
return new RowColLocation(0, Math.min(textOffset, textElement.getText().length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -395,9 +409,6 @@ public class ClippingTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
||||||
// TODO - this used to return the clipped value, which is not our clients wanted (at least one). If
|
|
||||||
// any odd navigation/tracking/action issues appear, then this could be the culprit.
|
|
||||||
// return textElement.getFieldElement(screenColumn);
|
|
||||||
return originalElement.getFieldElement(screenColumn);
|
return originalElement.getFieldElement(screenColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-26
@@ -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.
|
||||||
@@ -27,7 +26,7 @@ import javax.swing.JComponent;
|
|||||||
public class CompositeAttributedString extends AttributedString {
|
public class CompositeAttributedString extends AttributedString {
|
||||||
|
|
||||||
private String fullText;
|
private String fullText;
|
||||||
private AttributedString[] attributedStrings;
|
protected AttributedString[] attributedStrings;
|
||||||
private int heightAbove = -1;
|
private int heightAbove = -1;
|
||||||
private int heightBelow = -1;
|
private int heightBelow = -1;
|
||||||
|
|
||||||
@@ -35,7 +34,7 @@ public class CompositeAttributedString extends AttributedString {
|
|||||||
this(stringList.toArray(new AttributedString[stringList.size()]));
|
this(stringList.toArray(new AttributedString[stringList.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompositeAttributedString(AttributedString[] attributedStrings) {
|
public CompositeAttributedString(AttributedString... attributedStrings) {
|
||||||
this.attributedStrings = attributedStrings;
|
this.attributedStrings = attributedStrings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,17 +53,17 @@ public class CompositeAttributedString extends AttributedString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColumnPosition(int width) {
|
public int getCharPosition(int x) {
|
||||||
int remainingWidth = width;
|
int remainingWidth = x;
|
||||||
int totalCharacters = 0;
|
int totalCharacters = 0;
|
||||||
for (int i = 0; i < attributedStrings.length; i++) {
|
for (AttributedString attributedString : attributedStrings) {
|
||||||
int nextWidth = attributedStrings[i].getStringWidth();
|
int nextWidth = attributedString.getStringWidth();
|
||||||
if (nextWidth >= remainingWidth) {
|
if (nextWidth >= remainingWidth) {
|
||||||
totalCharacters += attributedStrings[i].getColumnPosition(remainingWidth);
|
totalCharacters += attributedString.getCharPosition(remainingWidth);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
remainingWidth -= nextWidth;
|
remainingWidth -= nextWidth;
|
||||||
totalCharacters += attributedStrings[i].length();
|
totalCharacters += attributedString.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalCharacters;
|
return totalCharacters;
|
||||||
@@ -86,8 +85,8 @@ public class CompositeAttributedString extends AttributedString {
|
|||||||
public int getHeightAbove() {
|
public int getHeightAbove() {
|
||||||
if (heightAbove < 0) {
|
if (heightAbove < 0) {
|
||||||
heightAbove = 0;
|
heightAbove = 0;
|
||||||
for (int i = 0; i < attributedStrings.length; i++) {
|
for (AttributedString attributedString : attributedStrings) {
|
||||||
heightAbove = Math.max(heightAbove, attributedStrings[i].getHeightAbove());
|
heightAbove = Math.max(heightAbove, attributedString.getHeightAbove());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return heightAbove;
|
return heightAbove;
|
||||||
@@ -97,23 +96,23 @@ public class CompositeAttributedString extends AttributedString {
|
|||||||
public int getHeightBelow() {
|
public int getHeightBelow() {
|
||||||
if (heightBelow < 0) {
|
if (heightBelow < 0) {
|
||||||
heightBelow = 0;
|
heightBelow = 0;
|
||||||
for (int i = 0; i < attributedStrings.length; i++) {
|
for (AttributedString attributedString : attributedStrings) {
|
||||||
heightBelow = Math.max(heightBelow, attributedStrings[i].getHeightBelow());
|
heightBelow = Math.max(heightBelow, attributedString.getHeightBelow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return heightBelow;
|
return heightBelow;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
// font metrics methods
|
// font metrics methods
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStringWidth() {
|
public int getStringWidth() {
|
||||||
if (textWidth == -1) {
|
if (textWidth == -1) {
|
||||||
textWidth = 0;
|
textWidth = 0;
|
||||||
for (int i = 0; i < attributedStrings.length; i++) {
|
for (AttributedString attributedString : attributedStrings) {
|
||||||
textWidth += attributedStrings[i].getStringWidth();
|
textWidth += attributedString.getStringWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return textWidth;
|
return textWidth;
|
||||||
@@ -123,24 +122,24 @@ public class CompositeAttributedString extends AttributedString {
|
|||||||
public String getText() {
|
public String getText() {
|
||||||
if (fullText == null) {
|
if (fullText == null) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
for (int i = 0; i < attributedStrings.length; i++) {
|
for (AttributedString attributedString : attributedStrings) {
|
||||||
buffer.append(attributedStrings[i].getText());
|
buffer.append(attributedString.getText());
|
||||||
}
|
}
|
||||||
fullText = buffer.toString();
|
fullText = buffer.toString();
|
||||||
}
|
}
|
||||||
return fullText;
|
return fullText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
// paint methods
|
// paint methods
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||||
int xPos = x;
|
int xPos = x;
|
||||||
for (int i = 0; i < attributedStrings.length; i++) {
|
for (AttributedString attributedString : attributedStrings) {
|
||||||
attributedStrings[i].paint(c, g, xPos, y);
|
attributedString.paint(c, g, xPos, y);
|
||||||
xPos += attributedStrings[i].getStringWidth();
|
xPos += attributedString.getStringWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-15
@@ -24,7 +24,7 @@ import javax.swing.JComponent;
|
|||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A FieldElement that is composed of other FieldElements.
|
* A FieldElement that is composed of other FieldElements. The elements are laid out horizontally.
|
||||||
*/
|
*/
|
||||||
public class CompositeFieldElement implements FieldElement {
|
public class CompositeFieldElement implements FieldElement {
|
||||||
|
|
||||||
@@ -34,19 +34,14 @@ public class CompositeFieldElement implements FieldElement {
|
|||||||
private int textWidth = -1;
|
private int textWidth = -1;
|
||||||
private String fullText;
|
private String fullText;
|
||||||
|
|
||||||
public CompositeFieldElement(List<? extends FieldElement> stringList) {
|
public CompositeFieldElement(List<? extends FieldElement> elements) {
|
||||||
this(stringList.toArray(new FieldElement[stringList.size()]));
|
this(elements.toArray(new FieldElement[elements.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompositeFieldElement(FieldElement[] fieldElements) {
|
public CompositeFieldElement(FieldElement[] fieldElements) {
|
||||||
this.fieldElements = fieldElements;
|
this.fieldElements = fieldElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompositeFieldElement(FieldElement[] elements, int start, int length) {
|
|
||||||
fieldElements = new FieldElement[length];
|
|
||||||
System.arraycopy(elements, start, fieldElements, 0, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IndexedOffset getIndexedOffsetForCharPosition(int charPosition) {
|
private IndexedOffset getIndexedOffsetForCharPosition(int charPosition) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (int i = 0; i < fieldElements.length; i++) {
|
for (int i = 0; i < fieldElements.length; i++) {
|
||||||
@@ -114,7 +109,7 @@ public class CompositeFieldElement implements FieldElement {
|
|||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// FontMetrics methods
|
// FontMetrics methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStringWidth() {
|
public int getStringWidth() {
|
||||||
@@ -130,7 +125,7 @@ public class CompositeFieldElement implements FieldElement {
|
|||||||
@Override
|
@Override
|
||||||
public String getText() {
|
public String getText() {
|
||||||
if (fullText == null) {
|
if (fullText == null) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
StringBuilder buffer = new StringBuilder();
|
||||||
for (FieldElement fieldElement : fieldElements) {
|
for (FieldElement fieldElement : fieldElements) {
|
||||||
buffer.append(fieldElement.getText());
|
buffer.append(fieldElement.getText());
|
||||||
}
|
}
|
||||||
@@ -141,7 +136,7 @@ public class CompositeFieldElement implements FieldElement {
|
|||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Paint methods
|
// Paint methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||||
@@ -217,9 +212,14 @@ public class CompositeFieldElement implements FieldElement {
|
|||||||
return getText().length();
|
return getText().length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getText();
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Location Info
|
// Location Info
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
||||||
@@ -229,12 +229,14 @@ public class CompositeFieldElement implements FieldElement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn) {
|
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn) {
|
||||||
int columnCount = 0;
|
int columnsSoFar = 0;
|
||||||
for (int i = fieldElements.length - 1; i >= 0; i--) {
|
for (int i = fieldElements.length - 1; i >= 0; i--) {
|
||||||
columnCount += fieldElements[i].length();
|
columnsSoFar += fieldElements[i].length();
|
||||||
int column = fieldElements[i].getCharacterIndexForDataLocation(dataRow, dataColumn);
|
int column = fieldElements[i].getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||||
if (column != -1) {
|
if (column != -1) {
|
||||||
return length() - columnCount + column;
|
// column value is relative to the current field; convert it to this field's offset
|
||||||
|
int fieldStart = length() - columnsSoFar;
|
||||||
|
return fieldStart + column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+596
File diff suppressed because it is too large
Load Diff
+9
-2
@@ -21,6 +21,7 @@ import javax.swing.JComponent;
|
|||||||
|
|
||||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||||
|
import docking.widgets.fieldpanel.support.DefaultRowColLocation;
|
||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,6 +80,11 @@ public class EmptyTextField implements Field {
|
|||||||
return startX;
|
return startX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -123,7 +129,8 @@ public class EmptyTextField implements Field {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
paintCursor(g, context.getCursorColor(), cursorLoc);
|
paintCursor(g, context.getCursorColor(), cursorLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +234,7 @@ public class EmptyTextField implements Field {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
return new RowColLocation(0, 0);
|
return new DefaultRowColLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+97
-72
@@ -30,155 +30,180 @@ import docking.widgets.fieldpanel.support.RowColLocation;
|
|||||||
public interface Field {
|
public interface Field {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current width of this field.
|
* Returns the current width of this field
|
||||||
|
* @return the current width of this field
|
||||||
*/
|
*/
|
||||||
int getWidth();
|
public int getWidth();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimum required width to paint the contents of this field
|
* The minimum required width to paint the contents of this field
|
||||||
* @return the minimum required width to paint the contents of this field
|
* @return the minimum required width to paint the contents of this field
|
||||||
*/
|
*/
|
||||||
int getPreferredWidth();
|
public int getPreferredWidth();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the height of this field when populated with the given data.
|
* Returns the height of this field when populated with the given data
|
||||||
|
* @return the height
|
||||||
*/
|
*/
|
||||||
int getHeight();
|
public int getHeight();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the height above the baseLine.
|
* Returns the height above the baseLine
|
||||||
|
* @return the height above
|
||||||
*/
|
*/
|
||||||
int getHeightAbove();
|
public int getHeightAbove();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the height below the baseLine.
|
* Returns the height below the baseLine
|
||||||
|
* @return the height below
|
||||||
*/
|
*/
|
||||||
int getHeightBelow();
|
public int getHeightBelow();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the horizontal position of this field.
|
* Returns the horizontal position of this field
|
||||||
|
* @return the position
|
||||||
*/
|
*/
|
||||||
int getStartX();
|
public int getStartX();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paints this field.
|
* Paints this field
|
||||||
* @param c the component to paint onto
|
* @param c the component to paint onto
|
||||||
* @param g the graphics context.
|
* @param g the graphics context
|
||||||
* @param context common paint parameters
|
* @param context common paint parameters
|
||||||
* @param clip the clipping region to paint into
|
* @param clip the clipping region to paint into
|
||||||
* @param colorManager contains background color information for the field.
|
* @param colorManager contains background color information for the field
|
||||||
* @param cursorLoc the row,column cursor location within the field or null if the field does
|
* @param cursorLoc the row,column cursor location within the field or null if the field does
|
||||||
* not contain the cursor
|
* not contain the cursor
|
||||||
* @param rowHeight the number of pixels in each row of text in the field.
|
* @param rowHeight the number of pixels in each row of text in the field
|
||||||
*/
|
*/
|
||||||
void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip,
|
public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip,
|
||||||
FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight);
|
FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given point is in this field.
|
* Returns true if the given point is in this field
|
||||||
* @param x the horizontal coordinate of the point.
|
* @param x the horizontal coordinate of the point
|
||||||
* @param y the relatve y position in this layout
|
* @param y the relative y position in this layout
|
||||||
|
* @return true if the given point is in this field
|
||||||
*/
|
*/
|
||||||
boolean contains(int x, int y);
|
public boolean contains(int x, int y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of data model rows represented by this field. Some fields may change
|
||||||
|
* the row count by wrapping or truncating. The value returned here will be the original data
|
||||||
|
* row count before any transformations were applied.
|
||||||
|
* @return the number of data rows
|
||||||
|
*/
|
||||||
|
public int getNumDataRows();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of rows in this field
|
* Returns the number of rows in this field
|
||||||
|
* @return the number of rows in this field
|
||||||
*/
|
*/
|
||||||
int getNumRows();
|
public int getNumRows();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of columns in the given row.
|
* Returns the number of columns in the given row
|
||||||
* @param row the row from which to get the number of columns.
|
* @param row the row from which to get the number of columns; this is the screen row
|
||||||
|
* @return the number of columns
|
||||||
*/
|
*/
|
||||||
int getNumCols(int row);
|
public int getNumCols(int row);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the x coordinate for the given cursor position.
|
* Returns the x coordinate for the given cursor position
|
||||||
* @param row the text row of interest.
|
* @param row the text row of interest
|
||||||
* @param col the character column.
|
* @param col the character column
|
||||||
|
* @return the x value
|
||||||
*/
|
*/
|
||||||
int getX(int row, int col);
|
public int getX(int row, int col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the y coordinate for the given row.
|
* Returns the y coordinate for the given row
|
||||||
* @param row the text row of interest.
|
* @param row the text row of interest
|
||||||
|
* @return the y value
|
||||||
*/
|
*/
|
||||||
int getY(int row);
|
public int getY(int row);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the row containing the given y coordinate.
|
* Returns the row containing the given y coordinate
|
||||||
* @param y vertical pixel coordinate relative to the top of the screen.
|
* @param y vertical pixel coordinate relative to the top of the screen
|
||||||
|
* @return the row
|
||||||
*/
|
*/
|
||||||
int getRow(int y);
|
public int getRow(int y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cursor column position for the given x coordinate on the given
|
* Returns the cursor column position for the given x coordinate on the given row
|
||||||
* row.
|
* @param row the text row to find the column on
|
||||||
* @param row the text row to find the column on.
|
* @param x the horizontal pixel coordinate for which to find the character position
|
||||||
* @param x the horizontal pixel coordinate for which to find the character position.
|
* @return the column
|
||||||
*/
|
*/
|
||||||
int getCol(int row, int x);
|
public int getCol(int row, int x);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given row and column represent a valid location for
|
* Returns true if the given row and column represent a valid location for this field with
|
||||||
* this field with the given data;
|
* the given data
|
||||||
* @param row the text row.
|
* @param row the text row
|
||||||
* @param col the character position.
|
* @param col the character position
|
||||||
|
* @return tru if valid
|
||||||
*/
|
*/
|
||||||
boolean isValid(int row, int col);
|
public boolean isValid(int row, int col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a bounding rectangle for the cursor at the given position.
|
* Returns a bounding rectangle for the cursor at the given position
|
||||||
* @param row the text row.
|
* @param row the text row
|
||||||
* @param col the character postion.
|
* @param col the character position
|
||||||
|
* @return the rectangle
|
||||||
*/
|
*/
|
||||||
Rectangle getCursorBounds(int row, int col);
|
public Rectangle getCursorBounds(int row, int col);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount to scroll to the next or previous line
|
* Returns the amount to scroll to the next or previous line
|
||||||
* @param topOfScreen - the current y pos of the top of the screen.
|
* @param topOfScreen the current y position of the top of the screen
|
||||||
* @param direction - the direction of the scroll (1 down, -1 up)
|
* @param direction the direction of the scroll (1 down, -1 up)
|
||||||
* @param max - the maximum amount to scroll for the entire row - will
|
* @param max the maximum amount to scroll for the entire row - will be positive for down, and
|
||||||
* be positive for down, and negative for up)
|
* negative for up)
|
||||||
|
* @return the scroll amount
|
||||||
*/
|
*/
|
||||||
int getScrollableUnitIncrement(int topOfScreen, int direction, int max);
|
public int getScrollableUnitIncrement(int topOfScreen, int direction, int max);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this field is "primary" (the most important)
|
* Returns true if this field is "primary" (the most important) field; used to determine the
|
||||||
* field; used to determine the "primary" line in the layout.
|
* "primary" line in the layout
|
||||||
|
* @return true if this field is "primary"
|
||||||
*/
|
*/
|
||||||
boolean isPrimary();
|
public boolean isPrimary();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* notifies field that the rowHeight changed
|
* notifies field that the rowHeight changed
|
||||||
* @param heightAbove the height above the baseline
|
* @param heightAbove the height above the baseline
|
||||||
* @param heightBelow the height below the baseline.
|
* @param heightBelow the height below the baseline
|
||||||
*/
|
*/
|
||||||
void rowHeightChanged(int heightAbove, int heightBelow);
|
public void rowHeightChanged(int heightAbove, int heightBelow);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string containing all the text in the field.
|
* Returns a string containing all the text in the field
|
||||||
|
* @return the string
|
||||||
*/
|
*/
|
||||||
String getText();
|
public String getText();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string containing all the text in the field with extra linefeeds
|
* Returns a string containing all the text in the field with extra newlines
|
||||||
* @return
|
* @return a string containing all the text in the field with extra newlines
|
||||||
*/
|
*/
|
||||||
String getTextWithLineSeparators();
|
public String getTextWithLineSeparators();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the row, column position for an offset into the string returned by getText().
|
* Returns the row, column position for an offset into the string returned by getText()
|
||||||
* @param textOffset the offset into the entire text string for this field.
|
* @param textOffset the offset into the entire text string for this field
|
||||||
* @return a RowColLocation that contains the row,column location in the field for a position in
|
* @return a RowColLocation that contains the row,column location in the field for a position in
|
||||||
* the overall field text.
|
* the overall field text
|
||||||
*/
|
*/
|
||||||
RowColLocation textOffsetToScreenLocation(int textOffset);
|
public RowColLocation textOffsetToScreenLocation(int textOffset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text offset in the overall field text string for the given row and column.
|
* Returns the text offset in the overall field text string for the given row and column
|
||||||
* @param row the row.
|
* @param row the row
|
||||||
* @param col the column.
|
* @param col the column
|
||||||
|
* @return the offset
|
||||||
*/
|
*/
|
||||||
int screenLocationToTextOffset(int row, int col);
|
public int screenLocationToTextOffset(int row, int col);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-10
@@ -23,7 +23,7 @@ import javax.swing.JComponent;
|
|||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by {@link Field}s to combine text, attributes and location information (for example to and
|
* Used by {@link Field}s to combine text, attributes and location information (for example to and
|
||||||
* from screen and data locations). FieldFactory classes can use the various implementations
|
* from screen and data locations). FieldFactory classes can use the various implementations
|
||||||
* of this interface, or create new ones, to include additional information specific to the fields
|
* of this interface, or create new ones, to include additional information specific to the fields
|
||||||
* that they create.
|
* that they create.
|
||||||
@@ -37,14 +37,14 @@ public interface FieldElement {
|
|||||||
public String getText();
|
public String getText();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the length of the text within this element. This is a convenience method for
|
* Returns the length of the text within this element. This is a convenience method for
|
||||||
* calling <code>getText().length()</code>.
|
* calling <code>getText().length()</code>.
|
||||||
* @return the length of the text within this element.
|
* @return the length of the text within this element.
|
||||||
*/
|
*/
|
||||||
public int length();
|
public int length();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string width of this element. The width is based upon the associated
|
* Returns the string width of this element. The width is based upon the associated
|
||||||
* FontMetrics object within this element.
|
* FontMetrics object within this element.
|
||||||
* @return the string width of this element.
|
* @return the string width of this element.
|
||||||
*/
|
*/
|
||||||
@@ -87,7 +87,7 @@ public interface FieldElement {
|
|||||||
public FieldElement substring(int start);
|
public FieldElement substring(int start);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new FieldElement containing just the characters beginning at the given start
|
* Returns a new FieldElement containing just the characters beginning at the given start
|
||||||
* index (inclusive) and ending at the given end index (exclusive).
|
* index (inclusive) and ending at the given end index (exclusive).
|
||||||
*
|
*
|
||||||
* @param start The starting index (inclusive) from which to substring this element.
|
* @param start The starting index (inclusive) from which to substring this element.
|
||||||
@@ -97,11 +97,11 @@ public interface FieldElement {
|
|||||||
public FieldElement substring(int start, int end);
|
public FieldElement substring(int start, int end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new FieldElement with all occurrences of the target characters replaced with the
|
* Returns a new FieldElement with all occurrences of the target characters replaced with the
|
||||||
* given replacement character.
|
* given replacement character.
|
||||||
* @param targets The array of characters to replace.
|
* @param targets The array of characters to replace.
|
||||||
* @param replacement The replacement character.
|
* @param replacement The replacement character.
|
||||||
* @return a new FieldElement with all occurrences of the target characters replaced with the
|
* @return a new FieldElement with all occurrences of the target characters replaced with the
|
||||||
* given replacement character.
|
* given replacement character.
|
||||||
*/
|
*/
|
||||||
public FieldElement replaceAll(char[] targets, char replacement);
|
public FieldElement replaceAll(char[] targets, char replacement);
|
||||||
@@ -111,13 +111,13 @@ public interface FieldElement {
|
|||||||
* element that will fit within the given width.
|
* element that will fit within the given width.
|
||||||
*
|
*
|
||||||
* @param width The width constraint
|
* @param width The width constraint
|
||||||
* @return the maximum number of characters from this field element that will fit within
|
* @return the maximum number of characters from this field element that will fit within
|
||||||
* the given width.
|
* the given width.
|
||||||
*/
|
*/
|
||||||
public int getMaxCharactersForWidth(int width);
|
public int getMaxCharactersForWidth(int width);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates the given character index to a data location related to the data model, as
|
* Translates the given character index to a data location related to the data model, as
|
||||||
* determined by the FieldFactory.
|
* determined by the FieldFactory.
|
||||||
*
|
*
|
||||||
* @param characterIndex The character index to translate.
|
* @param characterIndex The character index to translate.
|
||||||
@@ -129,13 +129,15 @@ public interface FieldElement {
|
|||||||
* Returns the character index appropriate for the given data location
|
* Returns the character index appropriate for the given data location
|
||||||
* @param dataRow the row in the data model as determined by the creating field factory.
|
* @param dataRow the row in the data model as determined by the creating field factory.
|
||||||
* @param dataColumn the column in the data model as determined by the creating field factory.
|
* @param dataColumn the column in the data model as determined by the creating field factory.
|
||||||
* @return the character index appropriate for the given data location
|
* @return the character index appropriate for the given data location; -1 if this field does
|
||||||
|
* not contain the given location
|
||||||
*/
|
*/
|
||||||
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn);
|
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paints the text contained in this field element at the given x,y screen coordinate using the
|
* Paints the text contained in this field element at the given x,y screen coordinate using the
|
||||||
* given Graphics object.
|
* given Graphics object.
|
||||||
|
* @param c the component being painted.
|
||||||
* @param g the Graphics object used to paint the field text.
|
* @param g the Graphics object used to paint the field text.
|
||||||
* @param x the horizontal screen position to paint
|
* @param x the horizontal screen position to paint
|
||||||
* @param y the vertical screen position to paint.
|
* @param y the vertical screen position to paint.
|
||||||
@@ -144,7 +146,7 @@ public interface FieldElement {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the inner-most FieldElement inside this field element at the given location
|
* Returns the inner-most FieldElement inside this field element at the given location
|
||||||
* @param column the charactor offset.
|
* @param column the character offset.
|
||||||
* @return the inner-most FieldElement inside this field element at the given location
|
* @return the inner-most FieldElement inside this field element at the given location
|
||||||
*/
|
*/
|
||||||
public FieldElement getFieldElement(int column);
|
public FieldElement getFieldElement(int column);
|
||||||
|
|||||||
+47
-32
@@ -15,67 +15,82 @@
|
|||||||
*/
|
*/
|
||||||
package docking.widgets.fieldpanel.field;
|
package docking.widgets.fieldpanel.field;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.support.HighlightFactory;
|
import docking.widgets.fieldpanel.support.HighlightFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a TextField implementation that takes multiple
|
* This class provides a TextField implementation that takes multiple AttributedStrings and places
|
||||||
* AttributedStrings and places as many that will fit on a line without clipping
|
* as many that will fit on a line without clipping before continuing to the next line.
|
||||||
* before continuing to the next line.
|
|
||||||
*/
|
*/
|
||||||
public class FlowLayoutTextField extends VerticalLayoutTextField {
|
public class FlowLayoutTextField extends VerticalLayoutTextField {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor will create a text field that will render one line of
|
* This constructor will create a text field that will render one line of text. If
|
||||||
* text. If <code>metrics.stringWidth(text) > width</code>, then the text
|
* <code>metrics.stringWidth(text) > width</code>, then the text will be wrapped.
|
||||||
* will be clipped. No wrapping will be performed. If <code>text</code>
|
* If <code>text</code> contains the highlight string, then it will be highlighted using the
|
||||||
* contains the highlight string, then it will be highlighted using the
|
|
||||||
* highlight color.
|
* highlight color.
|
||||||
*
|
*
|
||||||
* @param textElements
|
* @param textElements the AttributedStrings to display
|
||||||
* the AttributedStrings to display
|
* @param startX the x position to draw the string
|
||||||
* @param startX
|
* @param width the max width allocated to this field
|
||||||
* the x position to draw the string
|
* @param maxLines the max number of lines to display
|
||||||
* @param width
|
* @param hlFactory the highlight factory
|
||||||
* the max width allocated to this field
|
* @deprecated use the constructor that takes a list
|
||||||
* @param maxLines
|
|
||||||
* the max number of lines to display
|
|
||||||
* @param hlFactory
|
|
||||||
* the highlight factory
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "10.1", forRemoval = true)
|
||||||
public FlowLayoutTextField(FieldElement[] textElements, int startX,
|
public FlowLayoutTextField(FieldElement[] textElements, int startX,
|
||||||
int width, int maxLines, HighlightFactory hlFactory) {
|
int width, int maxLines, HighlightFactory hlFactory) {
|
||||||
super(createLineElements(textElements, width), startX, width, maxLines, hlFactory,"");
|
this(Arrays.asList(textElements), startX, width, maxLines, hlFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FieldElement[] createLineElements(FieldElement[] textElements, int width) {
|
/**
|
||||||
List<FieldElement> subFields = new ArrayList<FieldElement>();
|
* This constructor will create a text field that will render one line of text. If
|
||||||
|
* <code>metrics.stringWidth(text) > width</code>, then the text will be wrapped.
|
||||||
|
* If <code>text</code> contains the highlight string, then it will be highlighted using the
|
||||||
|
* highlight color.
|
||||||
|
*
|
||||||
|
* @param elements the AttributedStrings to display
|
||||||
|
* @param startX the x position to draw the string
|
||||||
|
* @param width the max width allocated to this field
|
||||||
|
* @param maxLines the max number of lines to display
|
||||||
|
* @param hlFactory the highlight factory
|
||||||
|
*/
|
||||||
|
public FlowLayoutTextField(List<FieldElement> elements, int startX,
|
||||||
|
int width, int maxLines, HighlightFactory hlFactory) {
|
||||||
|
super(createLineElements(elements, width), startX, width, maxLines, hlFactory, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FieldElement> createLineElements(List<FieldElement> elements,
|
||||||
|
int width) {
|
||||||
|
List<FieldElement> subFields = new ArrayList<>();
|
||||||
int currentIndex = 0;
|
int currentIndex = 0;
|
||||||
while (currentIndex < textElements.length) {
|
while (currentIndex < elements.size()) {
|
||||||
int numberPerLine = getNumberOfElementsPerLine(textElements, currentIndex, width);
|
int numberPerLine = getNumberOfElementsPerLine(elements, currentIndex, width);
|
||||||
subFields.add(new CompositeFieldElement(textElements, currentIndex, numberPerLine));
|
subFields.add(createLine(elements, currentIndex, numberPerLine));
|
||||||
currentIndex += numberPerLine;
|
currentIndex += numberPerLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
return subFields.toArray(new FieldElement[subFields.size()]);
|
return subFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getNumberOfElementsPerLine(FieldElement[] elements, int start, int width) {
|
private static CompositeFieldElement createLine(List<FieldElement> elements, int from,
|
||||||
|
int length) {
|
||||||
|
return new CompositeFieldElement(elements.subList(from, from + length));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getNumberOfElementsPerLine(List<FieldElement> elements, int start,
|
||||||
|
int width) {
|
||||||
int currentWidth = 0;
|
int currentWidth = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int n = elements.length;
|
for (FieldElement element : elements) {
|
||||||
for (int i = start; i < n; i++) {
|
currentWidth += element.getStringWidth();
|
||||||
currentWidth += elements[i].getStringWidth();
|
|
||||||
count++;
|
count++;
|
||||||
if (currentWidth > width) {
|
if (currentWidth > width) {
|
||||||
return Math.max(count - 1, 1);
|
return Math.max(count - 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return elements.size() - start;
|
||||||
return elements.length - start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-4
@@ -97,7 +97,7 @@ public class ReverseClippingTextField implements TextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isClipped = true;
|
isClipped = true;
|
||||||
// get the index of the start character that will fit
|
// get the index of the start character that will fit
|
||||||
startingCharIndex =
|
startingCharIndex =
|
||||||
textElement.getMaxCharactersForWidth(w - (availableWidth - DOT_DOT_DOT_WIDTH)) + 1;
|
textElement.getMaxCharactersForWidth(w - (availableWidth - DOT_DOT_DOT_WIDTH)) + 1;
|
||||||
startingCharIndex = Math.min(startingCharIndex, textElement.length());
|
startingCharIndex = Math.min(startingCharIndex, textElement.length());
|
||||||
@@ -150,6 +150,11 @@ public class ReverseClippingTextField implements TextField {
|
|||||||
return textElement.length() + 1; // allow one column past the end of the text
|
return textElement.length() + 1; // allow one column past the end of the text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -230,7 +235,8 @@ public class ReverseClippingTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
if (context.isPrinting()) {
|
if (context.isPrinting()) {
|
||||||
print(g, context);
|
print(g, context);
|
||||||
}
|
}
|
||||||
@@ -341,7 +347,10 @@ public class ReverseClippingTextField implements TextField {
|
|||||||
@Override
|
@Override
|
||||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||||
int column = textElement.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
int column = textElement.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
||||||
return new RowColLocation(0, Math.max(column, 0));
|
if (column < 0) {
|
||||||
|
return new DefaultRowColLocation();
|
||||||
|
}
|
||||||
|
return new RowColLocation(0, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findX(int col) {
|
private int findX(int col) {
|
||||||
@@ -389,7 +398,9 @@ public class ReverseClippingTextField implements TextField {
|
|||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
int col = textOffset + startingCharIndex;
|
int col = textOffset + startingCharIndex;
|
||||||
col = Math.max(col, 0);
|
if (col < 0) {
|
||||||
|
return new DefaultRowColLocation();
|
||||||
|
}
|
||||||
return new RowColLocation(0, Math.min(col, textElement.getText().length() - 1));
|
return new RowColLocation(0, Math.min(col, textElement.getText().length() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -22,6 +22,7 @@ import javax.swing.JComponent;
|
|||||||
|
|
||||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||||
|
import docking.widgets.fieldpanel.support.DefaultRowColLocation;
|
||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +47,8 @@ public class SimpleImageField implements Field {
|
|||||||
* @param startY the starting y coordinate of the field.
|
* @param startY the starting y coordinate of the field.
|
||||||
* @param width the width of the field.
|
* @param width the width of the field.
|
||||||
*/
|
*/
|
||||||
public SimpleImageField(ImageIcon icon, FontMetrics metrics, int startX, int startY, int width) {
|
public SimpleImageField(ImageIcon icon, FontMetrics metrics, int startX, int startY,
|
||||||
|
int width) {
|
||||||
this(icon, metrics, startX, startY, width, false);
|
this(icon, metrics, startX, startY, width, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +117,11 @@ public class SimpleImageField implements Field {
|
|||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -180,7 +187,8 @@ public class SimpleImageField implements Field {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
if (icon == null) {
|
if (icon == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -263,7 +271,7 @@ public class SimpleImageField implements Field {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
return new RowColLocation(0, 0);
|
return new DefaultRowColLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+10
-4
@@ -110,10 +110,15 @@ public class SimpleTextField implements Field {
|
|||||||
return startX;
|
return startX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @see docking.widgets.fieldpanel.field.Field#getNumRows()
|
* @see docking.widgets.fieldpanel.field.Field#getNumRows()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -199,7 +204,8 @@ public class SimpleTextField implements Field {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||||
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) {
|
Rectangle clip, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc,
|
||||||
|
int rowHeight) {
|
||||||
paintSelection(g, colorManager, 0);
|
paintSelection(g, colorManager, 0);
|
||||||
paintHighlights(g, hlFactory.getHighlights(this, text, -1));
|
paintHighlights(g, hlFactory.getHighlights(this, text, -1));
|
||||||
g.setFont(metrics.getFont());
|
g.setFont(metrics.getFont());
|
||||||
|
|||||||
+32
-14
@@ -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.
|
||||||
@@ -24,75 +23,94 @@ import javax.swing.JComponent;
|
|||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to force a clip to happen when the max lines is exceeded in the VerticalLayoutTextField
|
* Used to force a clip to happen by using this field with space characters and size that far
|
||||||
|
* exceeds the available painting width.
|
||||||
*/
|
*/
|
||||||
|
public class StrutFieldElement implements FieldElement {
|
||||||
public class EmptyFieldElement implements FieldElement {
|
|
||||||
|
|
||||||
private final int width;
|
private final int width;
|
||||||
|
|
||||||
public EmptyFieldElement(int width) {
|
public StrutFieldElement(int width) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public char charAt(int index) {
|
public char charAt(int index) {
|
||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn) {
|
public int getCharacterIndexForDataLocation(int dataRow, int dataColumn) {
|
||||||
return 0;
|
return -1; // we have not characters
|
||||||
}
|
|
||||||
|
|
||||||
public Color getColor(int charIndex) {
|
|
||||||
return Color.BLACK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
public RowColLocation getDataLocationForCharacterIndex(int characterIndex) {
|
||||||
return new RowColLocation(0, 0);
|
return new RowColLocation(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldElement getFieldElement(int column) {
|
@Override
|
||||||
|
public Color getColor(int charIndex) {
|
||||||
|
return Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldElement getFieldElement(int characterOffset) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getHeightAbove() {
|
public int getHeightAbove() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getHeightBelow() {
|
public int getHeightBelow() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxCharactersForWidth(int stringWidth) {
|
public int getMaxCharactersForWidth(int stringWidth) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getStringWidth() {
|
public int getStringWidth() {
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return width == 0 ? "" : " ";
|
return width == 0 ? "" : " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int length() {
|
public int length() {
|
||||||
return width == 0 ? 0 : 1;
|
return width == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void paint(JComponent c, Graphics g, int x, int y) {
|
public void paint(JComponent c, Graphics g, int x, int y) {
|
||||||
|
// nothing to paint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FieldElement replaceAll(char[] targets, char replacement) {
|
public FieldElement replaceAll(char[] targets, char replacement) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FieldElement substring(int start) {
|
public FieldElement substring(int start) {
|
||||||
return new EmptyFieldElement(0);
|
return new StrutFieldElement(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FieldElement substring(int start, int end) {
|
public FieldElement substring(int start, int end) {
|
||||||
return new EmptyFieldElement(0);
|
return new StrutFieldElement(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return ""; // empty text placeholder
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+25
-23
@@ -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.
|
||||||
@@ -16,37 +15,40 @@
|
|||||||
*/
|
*/
|
||||||
package docking.widgets.fieldpanel.field;
|
package docking.widgets.fieldpanel.field;
|
||||||
|
|
||||||
|
import docking.widgets.fieldpanel.support.DefaultRowColLocation;
|
||||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||||
|
|
||||||
|
|
||||||
public interface TextField extends Field {
|
public interface TextField extends Field {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets this field to be primary such that its row is primary
|
* Sets this field to be primary such that its row is primary
|
||||||
|
* @param b this field to be primary such that its row is primary
|
||||||
*/
|
*/
|
||||||
public void setPrimary(boolean b);
|
public void setPrimary(boolean b);
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates a screen coordinate to a row and column in the data from the factory
|
|
||||||
* @param screenRow the row in the displayed field text.
|
|
||||||
* @param screenColumn the column in the displayed field text.
|
|
||||||
* @return a RowColLocation containing the row and column within the data from the factory.
|
|
||||||
*/
|
|
||||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates a data row and column into a screen row and column.
|
|
||||||
* @param dataRow row as defined by the factory
|
|
||||||
* @param dataColumn the character offset into the dataRow
|
|
||||||
* @return row and column in the screen coordinate system.
|
|
||||||
*/
|
|
||||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the field is not displaying all the text information
|
* Translates a screen coordinate to a row and column in the data from the factory
|
||||||
*/
|
* @param screenRow the row in the displayed field text.
|
||||||
|
* @param screenColumn the column in the displayed field text.
|
||||||
|
* @return a RowColLocation containing the row and column within the data from the factory.
|
||||||
|
*/
|
||||||
|
public RowColLocation screenToDataLocation(int screenRow, int screenColumn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates a data row and column into a screen row and column.
|
||||||
|
* @param dataRow row as defined by the factory
|
||||||
|
* @param dataColumn the character offset into the dataRow
|
||||||
|
* @return row and column in the screen coordinate system; a {@link DefaultRowColLocation} if
|
||||||
|
* this field does not contain the given column
|
||||||
|
*/
|
||||||
|
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the field is not displaying all the text information
|
||||||
|
* @return true if the field is not displaying all the text information
|
||||||
|
*/
|
||||||
public boolean isClipped();
|
public boolean isClipped();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the FieldElement at the given screen location.
|
* Returns the FieldElement at the given screen location.
|
||||||
* @param screenRow the row on the screen
|
* @param screenRow the row on the screen
|
||||||
@@ -54,5 +56,5 @@ public interface TextField extends Field {
|
|||||||
* @return the FieldElement at the given screen location.
|
* @return the FieldElement at the given screen location.
|
||||||
*/
|
*/
|
||||||
public FieldElement getFieldElement(int screenRow, int screenColumn);
|
public FieldElement getFieldElement(int screenRow, int screenColumn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-11
@@ -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.
|
||||||
@@ -16,27 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package docking.widgets.fieldpanel.field;
|
package docking.widgets.fieldpanel.field;
|
||||||
|
|
||||||
|
public class TextFieldElement extends AbstractTextFieldElement {
|
||||||
public final class TextFieldElement extends AbstractTextFieldElement {
|
|
||||||
|
|
||||||
public TextFieldElement(AttributedString attributedString, int row, int column) {
|
public TextFieldElement(AttributedString attributedString, int row, int column) {
|
||||||
super(attributedString, row, column);
|
super(attributedString, row, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @see docking.widgets.fieldpanel.field.FieldElement#substring(int, int)
|
|
||||||
*/
|
|
||||||
public FieldElement substring(int start, int end) {
|
public FieldElement substring(int start, int end) {
|
||||||
AttributedString as = attributedString.substring(start, end);
|
AttributedString as = attributedString.substring(start, end);
|
||||||
if ( as == attributedString ) {
|
if (as == attributedString) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return new TextFieldElement(as, row, column+start);
|
return new TextFieldElement(as, row, column + start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @see docking.widgets.fieldpanel.field.FieldElement#replaceAll(char[], char)
|
|
||||||
*/
|
|
||||||
public FieldElement replaceAll(char[] targets, char replacement) {
|
public FieldElement replaceAll(char[] targets, char replacement) {
|
||||||
return new TextFieldElement(attributedString.replaceAll(targets, replacement), row, column);
|
return new TextFieldElement(attributedString.replaceAll(targets, replacement), row, column);
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-77
@@ -16,25 +16,24 @@
|
|||||||
package docking.widgets.fieldpanel.field;
|
package docking.widgets.fieldpanel.field;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||||
import docking.widgets.fieldpanel.support.*;
|
import docking.widgets.fieldpanel.support.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a TextField implementation that takes multiple FieldElements and places
|
* This class provides a TextField implementation that takes multiple FieldElements and places
|
||||||
* each on its own line within the field. It also can take a single FieldElements and
|
* each on its own line within the field.
|
||||||
* word wrap,creating new FieldElements (one per line).
|
|
||||||
*/
|
*/
|
||||||
public class VerticalLayoutTextField implements TextField {
|
public class VerticalLayoutTextField implements TextField {
|
||||||
|
|
||||||
protected FieldElement[] textElements;
|
protected List<TextField> subFields; // list of fields for FieldElements
|
||||||
protected List<Field> subFields; // list of fields for FieldElements
|
|
||||||
protected int startX;
|
protected int startX;
|
||||||
protected int width;
|
protected int width;
|
||||||
protected int preferredWidth;
|
protected int preferredWidth;
|
||||||
@@ -42,11 +41,34 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
|
|
||||||
private int height;
|
private int height;
|
||||||
private int heightAbove;
|
private int heightAbove;
|
||||||
|
private int numDataRows;
|
||||||
private boolean isPrimary;
|
private boolean isPrimary;
|
||||||
private String text;
|
|
||||||
|
// full text is all text with line separators, *but not with line delimiters*
|
||||||
|
private String fullText;
|
||||||
|
private List<String> lines;
|
||||||
|
|
||||||
|
// used in the getText() method to separate rows without adding newlines
|
||||||
|
private String rowSeparator;
|
||||||
|
|
||||||
protected boolean isClipped;
|
protected boolean isClipped;
|
||||||
private String lineDelimiter; // used in the getText() method to separate lines
|
|
||||||
|
/**
|
||||||
|
* This constructor will create a text field from an array of FieldElements, putting each
|
||||||
|
* element on its own line.
|
||||||
|
*
|
||||||
|
* @param textElements the FieldElements to display
|
||||||
|
* @param startX the x position to draw the element
|
||||||
|
* @param width the max width allocated to this field
|
||||||
|
* @param maxLines the max number of lines to display
|
||||||
|
* @param hlFactory the highlight factory
|
||||||
|
* @deprecated use the constructor that takes a list
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "10.1", forRemoval = true)
|
||||||
|
public VerticalLayoutTextField(FieldElement[] textElements, int startX, int width, int maxLines,
|
||||||
|
HighlightFactory hlFactory) {
|
||||||
|
this(Arrays.asList(textElements), startX, width, maxLines, hlFactory, " ");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor will create a text field from an array of FieldElements, putting each
|
* This constructor will create a text field from an array of FieldElements, putting each
|
||||||
@@ -58,7 +80,8 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
* @param maxLines the max number of lines to display
|
* @param maxLines the max number of lines to display
|
||||||
* @param hlFactory the highlight factory
|
* @param hlFactory the highlight factory
|
||||||
*/
|
*/
|
||||||
public VerticalLayoutTextField(FieldElement[] textElements, int startX, int width, int maxLines,
|
public VerticalLayoutTextField(List<FieldElement> textElements, int startX, int width,
|
||||||
|
int maxLines,
|
||||||
HighlightFactory hlFactory) {
|
HighlightFactory hlFactory) {
|
||||||
this(textElements, startX, width, maxLines, hlFactory, " ");
|
this(textElements, startX, width, maxLines, hlFactory, " ");
|
||||||
}
|
}
|
||||||
@@ -72,25 +95,46 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
* @param width the max width allocated to this field
|
* @param width the max width allocated to this field
|
||||||
* @param maxLines the max number of lines to display
|
* @param maxLines the max number of lines to display
|
||||||
* @param hlFactory the highlight factory
|
* @param hlFactory the highlight factory
|
||||||
* @param lineDelimiter The string to space lines of text when concatenated by the
|
* @param rowSeparator The string used to space lines of text when concatenated by the
|
||||||
* getText() method.
|
* getText() method.
|
||||||
*/
|
*/
|
||||||
protected VerticalLayoutTextField(FieldElement[] textElements, int startX, int width,
|
protected VerticalLayoutTextField(List<FieldElement> textElements, int startX, int width,
|
||||||
int maxLines, HighlightFactory hlFactory, String lineDelimiter) {
|
int maxLines, HighlightFactory hlFactory, String rowSeparator) {
|
||||||
|
|
||||||
this.textElements = textElements;
|
|
||||||
this.startX = startX;
|
this.startX = startX;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
|
||||||
this.hlFactory = hlFactory;
|
this.hlFactory = hlFactory;
|
||||||
this.lineDelimiter = lineDelimiter;
|
this.rowSeparator = rowSeparator;
|
||||||
|
|
||||||
subFields = layoutElements(maxLines);
|
lines = generateLines(textElements);
|
||||||
|
fullText = generateText(textElements, rowSeparator);
|
||||||
|
subFields = layoutElements(textElements, maxLines);
|
||||||
|
numDataRows = textElements.size();
|
||||||
|
|
||||||
this.preferredWidth = calculatePreferredWidth();
|
preferredWidth = calculatePreferredWidth();
|
||||||
calculateHeight();
|
calculateHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> generateLines(List<FieldElement> textElements) {
|
||||||
|
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (FieldElement field : textElements) {
|
||||||
|
list.add(field.getText());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateText(List<FieldElement> elements, String delimiter) {
|
||||||
|
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
int n = elements.size() - 1;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
buf.append(elements.get(i).getText()).append(delimiter);
|
||||||
|
}
|
||||||
|
buf.append(elements.get(n).getText());
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
protected void calculateHeight() {
|
protected void calculateHeight() {
|
||||||
heightAbove = (subFields.get(0)).getHeightAbove();
|
heightAbove = (subFields.get(0)).getHeightAbove();
|
||||||
for (Field field : subFields) {
|
for (Field field : subFields) {
|
||||||
@@ -108,15 +152,12 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getText() {
|
public String getText() {
|
||||||
if (text == null) {
|
return fullText;
|
||||||
text = generateText();
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTextWithLineSeparators() {
|
public String getTextWithLineSeparators() {
|
||||||
return generateText("\n");
|
return StringUtils.join(lines, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -144,6 +185,11 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
return startX;
|
return startX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumDataRows() {
|
||||||
|
return numDataRows;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumRows() {
|
public int getNumRows() {
|
||||||
return subFields.size();
|
return subFields.size();
|
||||||
@@ -157,11 +203,11 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRow(int y) {
|
public int getRow(int y) {
|
||||||
if (y < -heightAbove) {
|
if (y < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int heightSoFar = -heightAbove;
|
|
||||||
|
|
||||||
|
int heightSoFar = 0;
|
||||||
int n = subFields.size();
|
int n = subFields.size();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
Field f = subFields.get(i);
|
Field f = subFields.get(i);
|
||||||
@@ -247,7 +293,7 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
|
|
||||||
int startY = myStartY;
|
int startY = myStartY;
|
||||||
int translatedY = 0;
|
int translatedY = 0;
|
||||||
|
int extraSpace = rowSeparator.length();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
ClippingTextField subField = (ClippingTextField) subFields.get(i);
|
ClippingTextField subField = (ClippingTextField) subFields.get(i);
|
||||||
int subFieldHeight = subField.getHeight();
|
int subFieldHeight = subField.getHeight();
|
||||||
@@ -276,7 +322,7 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
startY += subFieldHeight;
|
startY += subFieldHeight;
|
||||||
g.translate(0, subFieldHeight);
|
g.translate(0, subFieldHeight);
|
||||||
translatedY += subFieldHeight;
|
translatedY += subFieldHeight;
|
||||||
columns += subField.getText().length() + lineDelimiter.length();
|
columns += subField.getText().length() + extraSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore the graphics to where it was when we started.
|
// restore the graphics to where it was when we started.
|
||||||
@@ -355,6 +401,7 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of subfields in this field.
|
* Returns the list of subfields in this field.
|
||||||
|
* @return the list of subfields in this field.
|
||||||
*/
|
*/
|
||||||
public List<Field> getSubfields() {
|
public List<Field> getSubfields() {
|
||||||
return Collections.unmodifiableList(subFields);
|
return Collections.unmodifiableList(subFields);
|
||||||
@@ -372,27 +419,29 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void rowHeightChanged(int heightAbove1, int heightBelow) {
|
public void rowHeightChanged(int heightAbove1, int heightBelow) {
|
||||||
// most fields don't care
|
// most fields don't care
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
public FieldElement getFieldElement(int screenRow, int screenColumn) {
|
||||||
|
|
||||||
FieldElement clickedField = textElements[screenRow];
|
TextField f = subFields.get(screenRow);
|
||||||
return clickedField.getFieldElement(screenColumn);
|
|
||||||
|
int fieldRow = 0; // each field is on a single row
|
||||||
|
return f.getFieldElement(fieldRow, screenColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Field> layoutElements(int maxLines) {
|
protected List<TextField> layoutElements(List<FieldElement> textElements, int maxLines) {
|
||||||
List<Field> newSubFields = new ArrayList<>();
|
List<TextField> newSubFields = new ArrayList<>();
|
||||||
|
|
||||||
boolean tooManyLines = textElements.length > maxLines;
|
boolean tooManyLines = textElements.size() > maxLines;
|
||||||
|
|
||||||
for (int i = 0; i < textElements.length && i < maxLines; i++) {
|
for (int i = 0; i < textElements.size() && i < maxLines; i++) {
|
||||||
FieldElement element = textElements[i];
|
FieldElement element = textElements.get(i);
|
||||||
if (tooManyLines && (i == maxLines - 1)) {
|
if (tooManyLines && (i == maxLines - 1)) {
|
||||||
FieldElement[] elements = new FieldElement[2];
|
FieldElement[] elements = new FieldElement[2];
|
||||||
elements[0] = element;
|
elements[0] = element;
|
||||||
elements[1] = new EmptyFieldElement(500);
|
elements[1] = new StrutFieldElement(500);
|
||||||
element = new CompositeFieldElement(elements);
|
element = new CompositeFieldElement(elements);
|
||||||
}
|
}
|
||||||
TextField field = new ClippingTextField(startX, width, element, hlFactory);
|
TextField field = new ClippingTextField(startX, width, element, hlFactory);
|
||||||
@@ -406,83 +455,70 @@ public class VerticalLayoutTextField implements TextField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates the row and column to a String index and character offset into
|
* Translates the row and column to a String index and character offset into
|
||||||
* that string.
|
* that string.
|
||||||
* @param screenRow the row containing the location.
|
* @param screenRow the row containing the location.
|
||||||
* @param screenColumn the character position in the row of the location
|
* @param screenColumn the character position in the row of the location
|
||||||
* @return a MultiStringLocation containing the string index and position
|
* @return a MultiStringLocation containing the string index and position
|
||||||
* within that string.
|
* within that string.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
public RowColLocation screenToDataLocation(int screenRow, int screenColumn) {
|
||||||
|
|
||||||
screenRow = Math.min(screenRow, textElements.length - 1);
|
screenRow = Math.min(screenRow, subFields.size() - 1);
|
||||||
screenRow = Math.max(screenRow, 0);
|
screenRow = Math.max(screenRow, 0);
|
||||||
|
|
||||||
screenColumn = Math.min(screenColumn, textElements[screenRow].length());
|
TextField field = subFields.get(screenRow);
|
||||||
|
screenColumn = Math.min(screenColumn, field.getText().length());
|
||||||
screenColumn = Math.max(screenColumn, 0);
|
screenColumn = Math.max(screenColumn, 0);
|
||||||
|
|
||||||
return textElements[screenRow].getDataLocationForCharacterIndex(screenColumn);
|
int fieldRow = 0; // each field is on a single row
|
||||||
|
return field.screenToDataLocation(fieldRow, screenColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the corresponding row, column for string index, and offset
|
|
||||||
* @param dataRow index into the string array
|
|
||||||
* @param dataColumn offset into the indexed string.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||||
for (int screenRow = textElements.length - 1; screenRow >= 0; screenRow--) {
|
|
||||||
FieldElement element = textElements[screenRow];
|
if (dataRow >= getNumRows()) {
|
||||||
int screenColumn = element.getCharacterIndexForDataLocation(dataRow, dataColumn);
|
TextField lastField = subFields.get(subFields.size());
|
||||||
if (screenColumn >= 0) {
|
return new DefaultRowColLocation(lastField.getText().length(), subFields.size() - 1);
|
||||||
return new RowColLocation(screenRow, screenColumn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RowColLocation(0, 0); // give up
|
TextField field = subFields.get(dataRow);
|
||||||
}
|
RowColLocation location = field.dataToScreenLocation(dataRow, dataColumn);
|
||||||
|
return location.withRow(dataRow);
|
||||||
protected String generateText() {
|
|
||||||
return generateText(lineDelimiter);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String generateText(String delimiter) {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
int n = textElements.length - 1;
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
buf.append(textElements[i].getText()).append(delimiter);
|
|
||||||
}
|
|
||||||
buf.append(textElements[n].getText());
|
|
||||||
return buf.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int screenLocationToTextOffset(int row, int col) {
|
public int screenLocationToTextOffset(int row, int col) {
|
||||||
if (row >= textElements.length) {
|
if (row >= subFields.size()) {
|
||||||
return getText().length();
|
return getText().length();
|
||||||
}
|
}
|
||||||
int extraSpace = lineDelimiter.length();
|
int extraSpace = rowSeparator.length();
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (int i = 0; i < row; i++) {
|
for (int i = 0; i < row; i++) {
|
||||||
len += textElements[i].getText().length() + extraSpace;
|
len += lines.get(i).length() + extraSpace;
|
||||||
}
|
}
|
||||||
len += Math.min(col, textElements[row].getText().length());
|
len += Math.min(col, lines.get(row).length());
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
public RowColLocation textOffsetToScreenLocation(int textOffset) {
|
||||||
int extraSpace = lineDelimiter.length();
|
int absoluteOffset = textOffset;
|
||||||
int n = textElements.length;
|
int extraSpace = rowSeparator.length();
|
||||||
|
int n = subFields.size();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
int len = textElements[i].getText().length();
|
int len = lines.get(i).length();
|
||||||
if (textOffset < len + extraSpace) {
|
if (absoluteOffset < len + extraSpace) {
|
||||||
return new RowColLocation(i, textOffset);
|
return new RowColLocation(i, absoluteOffset);
|
||||||
}
|
}
|
||||||
textOffset -= len + extraSpace;
|
absoluteOffset -= len + extraSpace;
|
||||||
}
|
}
|
||||||
return new RowColLocation(n - 1, textElements[n - 1].getText().length());
|
|
||||||
|
int lastRow = n - 1;
|
||||||
|
int lastColumn = subFields.get(lastRow).getText().length();
|
||||||
|
return new DefaultRowColLocation(lastRow, lastColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+13
-13
@@ -17,13 +17,16 @@ package docking.widgets.fieldpanel.field;
|
|||||||
|
|
||||||
import docking.widgets.fieldpanel.support.*;
|
import docking.widgets.fieldpanel.support.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text field meant to take a string of text and wrap as needed.
|
||||||
|
*/
|
||||||
public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor will create a text field from an single AttributedString. The string will
|
* This constructor will create a text field from an single AttributedString. The string will
|
||||||
* be word wrapped.
|
* be word wrapped.
|
||||||
*
|
*
|
||||||
* @param textElement the AttributedString to display
|
* @param textElement the element to display
|
||||||
* @param startX the x position to draw the string
|
* @param startX the x position to draw the string
|
||||||
* @param width the max width allocated to this field
|
* @param width the max width allocated to this field
|
||||||
* @param maxLines the max number of lines to display
|
* @param maxLines the max number of lines to display
|
||||||
@@ -31,12 +34,13 @@ public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
|||||||
*/
|
*/
|
||||||
public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width,
|
public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width,
|
||||||
int maxLines, HighlightFactory hlFactory) {
|
int maxLines, HighlightFactory hlFactory) {
|
||||||
|
super(FieldUtils.wrap(textElement, width), startX, width, maxLines, hlFactory, " ");
|
||||||
super(FieldUtils.wrap(textElement, width), startX, width, maxLines, hlFactory, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a text field from a single FieldElement. The text is wrapped, either an words or simply
|
* This constructor will create a text field from an single AttributedString. The string will
|
||||||
|
* be word wrapped.
|
||||||
|
*
|
||||||
* @param textElement is the element to display
|
* @param textElement is the element to display
|
||||||
* @param startX is the position to draw the string
|
* @param startX is the position to draw the string
|
||||||
* @param width is the max width allocated to this field
|
* @param width is the max width allocated to this field
|
||||||
@@ -47,16 +51,12 @@ public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField {
|
|||||||
public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width,
|
public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width,
|
||||||
int maxLines, HighlightFactory hlFactory, boolean breakOnWhiteSpace) {
|
int maxLines, HighlightFactory hlFactory, boolean breakOnWhiteSpace) {
|
||||||
super(FieldUtils.wrap(textElement, width, breakOnWhiteSpace), startX, width, maxLines,
|
super(FieldUtils.wrap(textElement, width, breakOnWhiteSpace), startX, width, maxLines,
|
||||||
hlFactory, "");
|
hlFactory, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the corresponding row, column for string index, and offset
|
|
||||||
* @param index index into the string array
|
|
||||||
* @param offset offset into the indexed string.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public RowColLocation dataToScreenLocation(int index, int offset) {
|
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
|
||||||
return textOffsetToScreenLocation(offset);
|
// we represent one data row that may be split into multiple screen rows
|
||||||
|
return textOffsetToScreenLocation(dataColumn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/* ###
|
||||||
|
* 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 docking.widgets.fieldpanel.support;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A location used to represent a an edge case where not suitable location can be found and the
|
||||||
|
* client does not wish to return null.
|
||||||
|
*/
|
||||||
|
public class DefaultRowColLocation extends RowColLocation {
|
||||||
|
public DefaultRowColLocation() {
|
||||||
|
super(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultRowColLocation(int row, int col) {
|
||||||
|
super(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RowColLocation withCol(int newColumn) {
|
||||||
|
return new DefaultRowColLocation(row, newColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RowColLocation withRow(int newRow) {
|
||||||
|
return new DefaultRowColLocation(newRow, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+13
-6
@@ -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.
|
||||||
@@ -35,9 +34,12 @@ public class FieldSelectionHelper {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the selected text that pertains to an individual field. Null is returned if the
|
* Gets the selected text that pertains to an individual field. Null is returned if the
|
||||||
* given selection spans more than one field.
|
* given selection spans more than one field.
|
||||||
|
* @param selection the selection
|
||||||
|
* @param panel the field panel
|
||||||
|
* @return the text
|
||||||
*/
|
*/
|
||||||
public static String getFieldSelectionText(FieldSelection selection, FieldPanel panel) {
|
public static String getFieldSelectionText(FieldSelection selection, FieldPanel panel) {
|
||||||
if (!isStringSelection(selection)) {
|
if (!isStringSelection(selection)) {
|
||||||
@@ -46,9 +48,14 @@ public class FieldSelectionHelper {
|
|||||||
return getTextForField(selection.getFieldRange(0), panel);
|
return getTextForField(selection.getFieldRange(0), panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the text within the given selection. */
|
/**
|
||||||
|
* Returns the text within the given selection.
|
||||||
|
* @param selection the selection
|
||||||
|
* @param panel the field panel
|
||||||
|
* @return the text
|
||||||
|
*/
|
||||||
public static String getAllSelectedText(FieldSelection selection, FieldPanel panel) {
|
public static String getAllSelectedText(FieldSelection selection, FieldPanel panel) {
|
||||||
StringBuffer buffy = new StringBuffer();
|
StringBuilder buffy = new StringBuilder();
|
||||||
int numRanges = selection.getNumRanges();
|
int numRanges = selection.getNumRanges();
|
||||||
for (int i = 0; i < numRanges; i++) {
|
for (int i = 0; i < numRanges; i++) {
|
||||||
FieldRange fieldRange = selection.getFieldRange(i);
|
FieldRange fieldRange = selection.getFieldRange(i);
|
||||||
@@ -99,7 +106,7 @@ public class FieldSelectionHelper {
|
|||||||
int startFieldNumber = startLoc.fieldNum;
|
int startFieldNumber = startLoc.fieldNum;
|
||||||
BigInteger endIndex = endLoc.getIndex();
|
BigInteger endIndex = endLoc.getIndex();
|
||||||
|
|
||||||
StringBuffer buffy = new StringBuffer();
|
StringBuilder buffy = new StringBuilder();
|
||||||
for (BigInteger i = startIndex; i.compareTo(endIndex) <= 0; i = i.add(BigInteger.ONE)) {
|
for (BigInteger i = startIndex; i.compareTo(endIndex) <= 0; i = i.add(BigInteger.ONE)) {
|
||||||
Layout layout = panel.getLayoutModel().getLayout(i);
|
Layout layout = panel.getLayoutModel().getLayout(i);
|
||||||
String text = null;
|
String text = null;
|
||||||
@@ -133,7 +140,7 @@ public class FieldSelectionHelper {
|
|||||||
|
|
||||||
private static String getTextForFieldsInLayout(Layout layout, FieldRange fieldRange,
|
private static String getTextForFieldsInLayout(Layout layout, FieldRange fieldRange,
|
||||||
int startFieldNumber, int endFieldNumber) {
|
int startFieldNumber, int endFieldNumber) {
|
||||||
StringBuffer buffy = new StringBuffer();
|
StringBuilder buffy = new StringBuilder();
|
||||||
for (int i = startFieldNumber; i < endFieldNumber; i++) {
|
for (int i = startFieldNumber; i < endFieldNumber; i++) {
|
||||||
Field field = layout.getField(i);
|
Field field = layout.getField(i);
|
||||||
buffy.append(field.getTextWithLineSeparators());
|
buffy.append(field.getTextWithLineSeparators());
|
||||||
|
|||||||
+18
-29
@@ -15,8 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package docking.widgets.fieldpanel.support;
|
package docking.widgets.fieldpanel.support;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.field.FieldElement;
|
import docking.widgets.fieldpanel.field.FieldElement;
|
||||||
|
|
||||||
@@ -42,14 +41,14 @@ public class FieldUtils {
|
|||||||
* Splits the given FieldElement into sub-elements by wrapping the element on whitespace.
|
* Splits the given FieldElement into sub-elements by wrapping the element on whitespace.
|
||||||
*
|
*
|
||||||
* @param fieldElement The element to wrap
|
* @param fieldElement The element to wrap
|
||||||
* @param width The maximum width to allow before wrapping
|
* @param width The maximum width to allow before wrapping
|
||||||
* @return The wrapped elements
|
* @return The wrapped elements
|
||||||
*/
|
*/
|
||||||
public static FieldElement[] wrap(FieldElement fieldElement, int width) {
|
public static List<FieldElement> wrap(FieldElement fieldElement, int width) {
|
||||||
|
|
||||||
FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' ');
|
FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' ');
|
||||||
if (originalFieldElement.getStringWidth() <= width) {
|
if (originalFieldElement.getStringWidth() <= width) {
|
||||||
return new FieldElement[] { originalFieldElement };
|
return Arrays.asList(originalFieldElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FieldElement> lines = new ArrayList<>();
|
List<FieldElement> lines = new ArrayList<>();
|
||||||
@@ -63,7 +62,7 @@ public class FieldUtils {
|
|||||||
wordWrapPos = findWordWrapPosition(originalFieldElement, width);
|
wordWrapPos = findWordWrapPosition(originalFieldElement, width);
|
||||||
}
|
}
|
||||||
lines.add(originalFieldElement);
|
lines.add(originalFieldElement);
|
||||||
return lines.toArray(new FieldElement[lines.size()]);
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,14 +74,14 @@ public class FieldUtils {
|
|||||||
* @param breakOnWhiteSpace determines whether line breaks should happen at white space chars
|
* @param breakOnWhiteSpace determines whether line breaks should happen at white space chars
|
||||||
* @return the wrapped elements
|
* @return the wrapped elements
|
||||||
*/
|
*/
|
||||||
public static FieldElement[] wrap(FieldElement fieldElement, int width,
|
public static List<FieldElement> wrap(FieldElement fieldElement, int width,
|
||||||
boolean breakOnWhiteSpace) {
|
boolean breakOnWhiteSpace) {
|
||||||
if (breakOnWhiteSpace) {
|
if (breakOnWhiteSpace) {
|
||||||
return wrap(fieldElement, width);
|
return wrap(fieldElement, width);
|
||||||
}
|
}
|
||||||
FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' ');
|
FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' ');
|
||||||
if (originalFieldElement.getStringWidth() <= width) {
|
if (originalFieldElement.getStringWidth() <= width) {
|
||||||
return new FieldElement[] { originalFieldElement };
|
return Arrays.asList(originalFieldElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FieldElement> lines = new ArrayList<>();
|
List<FieldElement> lines = new ArrayList<>();
|
||||||
@@ -99,14 +98,14 @@ public class FieldUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines.add(originalFieldElement);
|
lines.add(originalFieldElement);
|
||||||
return lines.toArray(new FieldElement[lines.size()]);
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splits the given FieldElement into sub-elements by wrapping the element on whitespace.
|
* Splits the given FieldElement into sub-elements by wrapping the element on whitespace.
|
||||||
*
|
*
|
||||||
* @param fieldElement The element to wrap
|
* @param fieldElement The element to wrap
|
||||||
* @param width The maximum width to allow before wrapping
|
* @param width The maximum width to allow before wrapping
|
||||||
* @return The wrapped elements
|
* @return The wrapped elements
|
||||||
*/
|
*/
|
||||||
public static List<FieldElement> wordWrapList(FieldElement fieldElement, int width) {
|
public static List<FieldElement> wordWrapList(FieldElement fieldElement, int width) {
|
||||||
@@ -133,10 +132,11 @@ public class FieldUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the position within the given element at which to split the line for word wrapping.
|
* Finds the position within the given element at which to split the line for word wrapping.
|
||||||
* This method only breaks on whitespace characters. It finds the last whitespace character
|
* This method finds the last whitespace character that completely fits within the given width.
|
||||||
* that completely fits within the given width. If there is no whitespace character before
|
* If there is no whitespace character before the width break point, it finds the first
|
||||||
* the width break point, it finds the first whitespace character after the width. If the
|
* whitespace character after the width. If no whitespace can be found, then the text will
|
||||||
* element cannot be split at all, it returns 0.
|
* be split at a non-whitespace character.
|
||||||
|
*
|
||||||
* @param element the element to split
|
* @param element the element to split
|
||||||
* @param width the max width to allow before looking for a word wrap positions
|
* @param width the max width to allow before looking for a word wrap positions
|
||||||
* @return 0 if the element cannot be split, else the character position of the string
|
* @return 0 if the element cannot be split, else the character position of the string
|
||||||
@@ -156,30 +156,19 @@ public class FieldUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return wrapPosition;
|
return wrapPosition;
|
||||||
// The following code was replace with the return just above. This has the effect
|
|
||||||
// of splitting contiguous words at the field width instead of at the next white
|
|
||||||
// space beyond.
|
|
||||||
// whiteSpacePosition = text.indexOf(" ", wrapPosition);
|
|
||||||
// if (whiteSpacePosition >= 0) {
|
|
||||||
// if (whiteSpacePosition + 1 >= element.length()) { // if whitespace at end, no split
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
// return whiteSpacePosition;
|
|
||||||
// }
|
|
||||||
// return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trims "goofy" characters off of the given label, like spaces, '[',']', etc.
|
* Trims unwanted characters off of the given label, like spaces, '[',']', etc.
|
||||||
* @param string The string to be trimmed
|
* @param string The string to be trimmed
|
||||||
* @return The trimmed string.
|
* @return The trimmed string.
|
||||||
*/
|
*/
|
||||||
public static String trimString(String string) {
|
public static String trimString(String string) {
|
||||||
// short-circuit case where the given string starts normally, but contains invalid
|
// short-circuit case where the given string starts normally, but contains invalid
|
||||||
// characters (e.g., param_1[EAX])
|
// characters (e.g., param_1[EAX])
|
||||||
StringBuffer buffer = new StringBuffer(string);
|
StringBuilder buffer = new StringBuilder(string);
|
||||||
if (Character.isJavaIdentifierPart(buffer.charAt(0))) {
|
if (Character.isJavaIdentifierPart(buffer.charAt(0))) {
|
||||||
// in this case just take all valid characters and then exit
|
// in this case just take all valid characters and then exit
|
||||||
for (int index = 1; index < buffer.length(); index++) {
|
for (int index = 1; index < buffer.length(); index++) {
|
||||||
int charAt = buffer.charAt(index);
|
int charAt = buffer.charAt(index);
|
||||||
if (!Character.isJavaIdentifierPart(charAt)) {
|
if (!Character.isJavaIdentifierPart(charAt)) {
|
||||||
@@ -189,7 +178,7 @@ public class FieldUtils {
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// the following case is when the given string is surrounded by "goofy" characters
|
// the following case is when the given string is surrounded by "goofy" characters
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int charAt = buffer.charAt(index);
|
int charAt = buffer.charAt(index);
|
||||||
while (!Character.isJavaIdentifierPart(charAt) && buffer.length() > 0) {
|
while (!Character.isJavaIdentifierPart(charAt) && buffer.length() > 0) {
|
||||||
|
|||||||
+35
-22
@@ -19,8 +19,9 @@ package docking.widgets.fieldpanel.support;
|
|||||||
* Simple class to return a row, column location.
|
* Simple class to return a row, column location.
|
||||||
*/
|
*/
|
||||||
public class RowColLocation {
|
public class RowColLocation {
|
||||||
private int row;
|
protected int row;
|
||||||
private int col;
|
protected int col;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new RowColLocation with the given row and column.
|
* Constructs a new RowColLocation with the given row and column.
|
||||||
* @param row the row location
|
* @param row the row location
|
||||||
@@ -30,36 +31,48 @@ public class RowColLocation {
|
|||||||
this.row = row;
|
this.row = row;
|
||||||
this.col = col;
|
this.col = col;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Returns the row.
|
|
||||||
*/
|
|
||||||
public int row() {
|
public int row() {
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Returns the column.
|
|
||||||
*/
|
|
||||||
public int col() {
|
public int col() {
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
*
|
public RowColLocation withCol(int newColumn) {
|
||||||
* @see java.lang.Object#toString()
|
return new RowColLocation(row, newColumn);
|
||||||
*/
|
}
|
||||||
@Override
|
|
||||||
public String toString() {
|
public RowColLocation withRow(int newRow) {
|
||||||
return "RowColLocation("+row+","+col+")";
|
return new RowColLocation(newRow, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals( Object object ) {
|
public String toString() {
|
||||||
|
return row + "," + col;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + col;
|
||||||
|
result = prime * result + row;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( object.getClass() == RowColLocation.class ) {
|
|
||||||
RowColLocation loc = (RowColLocation) object;
|
if (!getClass().equals(object.getClass())) {
|
||||||
return (row == loc.row) && (col == loc.col);
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
RowColLocation loc = (RowColLocation) object;
|
||||||
|
return (row == loc.row) && (col == loc.col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -72,7 +72,7 @@ public class RowLayout implements Layout {
|
|||||||
// Can only compress the last field, as the rest are potentially part of a grid surrounded
|
// Can only compress the last field, as the rest are potentially part of a grid surrounded
|
||||||
// by other layouts
|
// by other layouts
|
||||||
//
|
//
|
||||||
// Notes: we have to account for any offset for fields that are disabled and are in
|
// Notes: we have to account for any offset for fields that are disabled and are in
|
||||||
// the beginning of the row.
|
// the beginning of the row.
|
||||||
//
|
//
|
||||||
int startX = fields[0].getStartX();
|
int startX = fields[0].getStartX();
|
||||||
@@ -180,8 +180,9 @@ public class RowLayout implements Layout {
|
|||||||
gapIndex = fields.length;
|
gapIndex = fields.length;
|
||||||
}
|
}
|
||||||
int startX =
|
int startX =
|
||||||
gapIndex == 0 ? rect.x : fields[gapIndex - 1].getStartX() +
|
gapIndex == 0 ? rect.x
|
||||||
fields[gapIndex - 1].getWidth();
|
: fields[gapIndex - 1].getStartX() +
|
||||||
|
fields[gapIndex - 1].getWidth();
|
||||||
int endX = gapIndex >= fields.length ? rect.x + rect.width : fields[gapIndex].getStartX();
|
int endX = gapIndex >= fields.length ? rect.x + rect.width : fields[gapIndex].getStartX();
|
||||||
|
|
||||||
if (startX < endX) {
|
if (startX < endX) {
|
||||||
@@ -201,7 +202,7 @@ public class RowLayout implements Layout {
|
|||||||
Field field = fields[index];
|
Field field = fields[index];
|
||||||
|
|
||||||
cursorLoc.fieldNum = index;
|
cursorLoc.fieldNum = index;
|
||||||
cursorLoc.row = field.getRow(y - heightAbove);
|
cursorLoc.row = field.getRow(y);
|
||||||
cursorLoc.col = field.getCol(cursorLoc.row, x);
|
cursorLoc.col = field.getCol(cursorLoc.row, x);
|
||||||
return field.getX(cursorLoc.row, cursorLoc.col);
|
return field.getX(cursorLoc.row, cursorLoc.col);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-206
@@ -18,6 +18,8 @@ package docking.widgets.fieldpanel;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -32,10 +34,6 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
private FlowLayoutTextField textField;
|
private FlowLayoutTextField textField;
|
||||||
|
|
||||||
public FlowLayoutTextFieldTest() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // we mean to use getFontMetrics
|
@SuppressWarnings("deprecation") // we mean to use getFontMetrics
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -47,156 +45,18 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
Font font = new Font("Times New Roman", 0, 14);
|
Font font = new Font("Times New Roman", 0, 14);
|
||||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||||
FontMetrics fm = tk.getFontMetrics(font);
|
FontMetrics fm = tk.getFontMetrics(font);
|
||||||
FieldElement[] elements = new FieldElement[4];
|
List<FieldElement> elements = new ArrayList<>();
|
||||||
elements[0] = new TextFieldElement(new AttributedString("Hello ", Color.BLUE, fm), 0, 0);
|
|
||||||
elements[1] = new TextFieldElement(
|
elements.add(new TextFieldElement(new AttributedString("Hello ", Color.BLUE, fm), 0, 0));
|
||||||
new AttributedString("World ", Color.RED, fm, true, Color.BLUE), 1, 0);
|
elements.add(new TextFieldElement(
|
||||||
elements[2] =
|
new AttributedString("World ", Color.RED, fm, true, Color.BLUE), 1, 0));
|
||||||
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0);
|
elements.add(
|
||||||
elements[3] = new TextFieldElement(new AttributedString("Wow! ", Color.GRAY, fm), 3, 0);
|
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0));
|
||||||
|
elements.add(new TextFieldElement(new AttributedString("Wow! ", Color.GRAY, fm), 3, 0));
|
||||||
|
|
||||||
textField = new FlowLayoutTextField(elements, 100, 100, 3, factory);
|
textField = new FlowLayoutTextField(elements, 100, 100, 3, factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getWidth()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetWidth() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getHeight()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetHeight() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getStartX()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetStartX() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getNumRows()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetNumRows() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getNumCols(int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetNumCols() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getRow(int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetRow() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getCol(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetCol() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getY(int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetY() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getX(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetX() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.isValid(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testIsValid() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.paint(Graphics, PaintContext, boolean)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testPaint() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.paintCursor(Graphics, PaintContext, boolean, int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testPaintCursor() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getCursorBounds(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetCursorBounds() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.contains(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testContains() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getScrollableUnitIncrement(int, int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetScrollableUnitIncrement() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.isPrimary()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testIsPrimary() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.setPrimary(boolean)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSetPrimary() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getStringLocation(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testScreenToDataLocation() {
|
public void testScreenToDataLocation() {
|
||||||
assertEquals(new RowColLocation(0, 0), textField.screenToDataLocation(0, 0));
|
assertEquals(new RowColLocation(0, 0), textField.screenToDataLocation(0, 0));
|
||||||
@@ -222,9 +82,6 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
assertEquals(new RowColLocation(3, 5), textField.screenToDataLocation(50, 75));
|
assertEquals(new RowColLocation(3, 5), textField.screenToDataLocation(50, 75));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getWrappedLocation(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testDataToScreenLocation() {
|
public void testDataToScreenLocation() {
|
||||||
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 0));
|
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 0));
|
||||||
@@ -247,9 +104,6 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 75));
|
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 75));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getRowColumn(int)'
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRowColumn() {
|
public void testGetRowColumn() {
|
||||||
assertEquals(new RowColLocation(0, 0), textField.textOffsetToScreenLocation(0));
|
assertEquals(new RowColLocation(0, 0), textField.textOffsetToScreenLocation(0));
|
||||||
@@ -264,55 +118,5 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
assertEquals(new RowColLocation(1, 18), textField.textOffsetToScreenLocation(30));
|
assertEquals(new RowColLocation(1, 18), textField.textOffsetToScreenLocation(30));
|
||||||
|
|
||||||
assertEquals(new RowColLocation(2, 5), textField.textOffsetToScreenLocation(1000));
|
assertEquals(new RowColLocation(2, 5), textField.textOffsetToScreenLocation(1000));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getSubfields()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetSubfields() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getHeightAbove()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetHeightAbove() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getHeightBelow()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetHeightBelow() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.rowHeightChanged(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testRowHeightChanged() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getText()'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetText() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getTextOffset(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetTextOffset() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-24
@@ -18,6 +18,8 @@ package docking.widgets.fieldpanel;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -32,10 +34,6 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
private VerticalLayoutTextField textField;
|
private VerticalLayoutTextField textField;
|
||||||
|
|
||||||
public VerticalLayoutTextFieldTest() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // we mean to use getFontMetrics
|
@SuppressWarnings("deprecation") // we mean to use getFontMetrics
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -47,20 +45,19 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
Font font = new Font("Times New Roman", 0, 14);
|
Font font = new Font("Times New Roman", 0, 14);
|
||||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||||
FontMetrics fm = tk.getFontMetrics(font);
|
FontMetrics fm = tk.getFontMetrics(font);
|
||||||
FieldElement[] elements = new FieldElement[4];
|
|
||||||
elements[0] = new TextFieldElement(new AttributedString("Hello", Color.BLUE, fm), 0, 0);
|
List<FieldElement> elements = new ArrayList<>();
|
||||||
elements[1] = new TextFieldElement(
|
|
||||||
new AttributedString("World", Color.RED, fm, true, Color.BLUE), 1, 0);
|
elements.add(new TextFieldElement(new AttributedString("Hello", Color.BLUE, fm), 0, 0));
|
||||||
elements[2] =
|
elements.add(new TextFieldElement(
|
||||||
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0);
|
new AttributedString("World", Color.RED, fm, true, Color.BLUE), 1, 0));
|
||||||
elements[3] = new TextFieldElement(new AttributedString("Wow!", Color.GRAY, fm), 3, 0);
|
elements.add(
|
||||||
|
new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0));
|
||||||
|
elements.add(new TextFieldElement(new AttributedString("Wow!", Color.GRAY, fm), 3, 0));
|
||||||
|
|
||||||
textField = new VerticalLayoutTextField(elements, 100, 100, 5, factory);
|
textField = new VerticalLayoutTextField(elements, 100, 100, 5, factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getStringLocation(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testScreenToDataLocation() {
|
public void testScreenToDataLocation() {
|
||||||
assertEquals(new RowColLocation(0, 0), textField.screenToDataLocation(0, 0));
|
assertEquals(new RowColLocation(0, 0), textField.screenToDataLocation(0, 0));
|
||||||
@@ -81,11 +78,8 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
assertEquals(new RowColLocation(3, 4), textField.screenToDataLocation(50, 75));
|
assertEquals(new RowColLocation(3, 4), textField.screenToDataLocation(50, 75));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getWrappedLocation(int, int)'
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetWrappedLocation() {
|
public void testDataToScreenLocation() {
|
||||||
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 0));
|
assertEquals(new RowColLocation(0, 0), textField.dataToScreenLocation(0, 0));
|
||||||
assertEquals(new RowColLocation(0, 2), textField.dataToScreenLocation(0, 2));
|
assertEquals(new RowColLocation(0, 2), textField.dataToScreenLocation(0, 2));
|
||||||
assertEquals(new RowColLocation(0, 5), textField.dataToScreenLocation(0, 5));
|
assertEquals(new RowColLocation(0, 5), textField.dataToScreenLocation(0, 5));
|
||||||
@@ -96,26 +90,26 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
|
|||||||
|
|
||||||
assertEquals(new RowColLocation(2, 0), textField.dataToScreenLocation(2, 0));
|
assertEquals(new RowColLocation(2, 0), textField.dataToScreenLocation(2, 0));
|
||||||
assertEquals(new RowColLocation(2, 4), textField.dataToScreenLocation(2, 4));
|
assertEquals(new RowColLocation(2, 4), textField.dataToScreenLocation(2, 4));
|
||||||
assertEquals(new RowColLocation(2, 15), textField.dataToScreenLocation(2, 15));
|
assertEquals(new RowColLocation(2, 12), textField.dataToScreenLocation(2, 12));
|
||||||
|
assertEquals(new DefaultRowColLocation(2, 12), textField.dataToScreenLocation(2, 15));
|
||||||
|
|
||||||
assertEquals(new RowColLocation(3, 0), textField.dataToScreenLocation(3, 0));
|
assertEquals(new RowColLocation(3, 0), textField.dataToScreenLocation(3, 0));
|
||||||
assertEquals(new RowColLocation(3, 4), textField.dataToScreenLocation(3, 4));
|
assertEquals(new RowColLocation(3, 4), textField.dataToScreenLocation(3, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test method for 'ghidra.util.bean.field.WrappingTextField.getRowColumn(int)'
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRowColumn() {
|
public void testTextOffsetToScreenLocation() {
|
||||||
assertEquals(new RowColLocation(0, 0), textField.textOffsetToScreenLocation(0));
|
assertEquals(new RowColLocation(0, 0), textField.textOffsetToScreenLocation(0));
|
||||||
assertEquals(new RowColLocation(0, 5), textField.textOffsetToScreenLocation(5));
|
assertEquals(new RowColLocation(0, 5), textField.textOffsetToScreenLocation(5));
|
||||||
|
|
||||||
assertEquals(new RowColLocation(1, 0), textField.textOffsetToScreenLocation(6));
|
assertEquals(new RowColLocation(1, 0), textField.textOffsetToScreenLocation(6));
|
||||||
assertEquals(new RowColLocation(1, 4), textField.textOffsetToScreenLocation(10));
|
assertEquals(new RowColLocation(1, 4), textField.textOffsetToScreenLocation(10));
|
||||||
assertEquals(new RowColLocation(1, 5), textField.textOffsetToScreenLocation(11));
|
assertEquals(new RowColLocation(1, 5), textField.textOffsetToScreenLocation(11));
|
||||||
|
|
||||||
assertEquals(new RowColLocation(2, 0), textField.textOffsetToScreenLocation(12));
|
assertEquals(new RowColLocation(2, 0), textField.textOffsetToScreenLocation(12));
|
||||||
|
|
||||||
assertEquals(new RowColLocation(1, 4), textField.textOffsetToScreenLocation(10));
|
assertEquals(new RowColLocation(1, 4), textField.textOffsetToScreenLocation(10));
|
||||||
|
|
||||||
assertEquals(new RowColLocation(3, 4), textField.textOffsetToScreenLocation(1000));
|
assertEquals(new DefaultRowColLocation(3, 4), textField.textOffsetToScreenLocation(1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+586
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ import static org.junit.Assert.*;
|
|||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
@@ -219,7 +220,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for subclasses when a test has failed. This will be called
|
* A callback for subclasses when a test has failed. This will be called
|
||||||
* <b>after</b> <code>tearDown()</code>. This means that any diagnostics will have to
|
* <b>after</b> <code>tearDown()</code>. This means that any diagnostics will have to
|
||||||
* take into account items that have already been disposed.
|
* take into account items that have already been disposed.
|
||||||
*
|
*
|
||||||
* @param e the exception that happened when the test failed
|
* @param e the exception that happened when the test failed
|
||||||
@@ -1118,7 +1119,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this version of {@link #runSwing(Runnable)} when you expect your runnable <b>may</b>
|
* Call this version of {@link #runSwing(Runnable)} when you expect your runnable <b>may</b>
|
||||||
* throw exceptions
|
* throw exceptions
|
||||||
*
|
*
|
||||||
* @param callback the runnable code snippet to call
|
* @param callback the runnable code snippet to call
|
||||||
@@ -1148,13 +1149,13 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
|
|
||||||
public static void runSwing(Runnable runnable, boolean wait) {
|
public static void runSwing(Runnable runnable, boolean wait) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Special Case: this check handled re-entrant test code. That is, an calls to runSwing()
|
// Special Case: this check handled re-entrant test code. That is, an calls to runSwing()
|
||||||
// that are made from within a runSwing() call. Most clients do not do
|
// that are made from within a runSwing() call. Most clients do not do
|
||||||
// this, but it can happen when a client makes a test API call (which itself
|
// this, but it can happen when a client makes a test API call (which itself
|
||||||
// calls runSwing()) from within a runSwing() call.
|
// calls runSwing()) from within a runSwing() call.
|
||||||
//
|
//
|
||||||
// Calling the run method directly here ensures that the order of client
|
// Calling the run method directly here ensures that the order of client
|
||||||
// requests is preserved.
|
// requests is preserved.
|
||||||
//
|
//
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
@@ -1167,7 +1168,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't wait; invoke later; catch any exceptions ourselves in order to fail-fast
|
// don't wait; invoke later; catch any exceptions ourselves in order to fail-fast
|
||||||
Runnable swingExceptionCatcher = () -> {
|
Runnable swingExceptionCatcher = () -> {
|
||||||
try {
|
try {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
@@ -1243,11 +1244,11 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
doRun(swingExceptionCatcher);
|
doRun(swingExceptionCatcher);
|
||||||
}
|
}
|
||||||
catch (InterruptedException | InvocationTargetException e) {
|
catch (InterruptedException | InvocationTargetException e) {
|
||||||
// Assume that if we have an exception reported by our catcher, then that is
|
// Assume that if we have an exception reported by our catcher, then that is
|
||||||
// the root cause of this exception and do not report this one. The typical
|
// the root cause of this exception and do not report this one. The typical
|
||||||
// exception here is an InterrruptedException that is caused by our test
|
// exception here is an InterrruptedException that is caused by our test
|
||||||
// harness when it is interrupting the test thread after a previous Swing
|
// harness when it is interrupting the test thread after a previous Swing
|
||||||
// exception that we have detected--we don't care to report the
|
// exception that we have detected--we don't care to report the
|
||||||
// InterruptedException, as we caused it. The InvocationTargetException should
|
// InterruptedException, as we caused it. The InvocationTargetException should
|
||||||
// be handled by our runnable above.
|
// be handled by our runnable above.
|
||||||
}
|
}
|
||||||
@@ -1561,6 +1562,19 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
UIManager.put("TextArea.font", f);
|
UIManager.put("TextArea.font", f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a font metrics for the given font using a generic buffered image graphics context.
|
||||||
|
* @param font the font
|
||||||
|
* @return the font metrics
|
||||||
|
*/
|
||||||
|
public static FontMetrics getFontMetrics(Font font) {
|
||||||
|
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||||
|
Graphics g = image.getGraphics();
|
||||||
|
FontMetrics fm = g.getFontMetrics(font);
|
||||||
|
g.dispose();
|
||||||
|
return fm;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals that the client expected the System Under Test (SUT) to report errors. Use this
|
* Signals that the client expected the System Under Test (SUT) to report errors. Use this
|
||||||
* when you wish to verify that errors are reported and you do not want those errors to
|
* when you wish to verify that errors are reported and you do not want those errors to
|
||||||
@@ -1582,7 +1596,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
// Swing Methods
|
// Swing Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the Swing thread to process any pending events. This method
|
* Waits for the Swing thread to process any pending events. This method
|
||||||
@@ -1685,11 +1699,11 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
// calls all execute in the Swing thread in a blocking fashion, so when we are done
|
// calls all execute in the Swing thread in a blocking fashion, so when we are done
|
||||||
// flushing, there should be no more work scheduled due to us flushing. Due to other
|
// flushing, there should be no more work scheduled due to us flushing. Due to other
|
||||||
// potential background threads though, more work may be scheduled as we are working.
|
// potential background threads though, more work may be scheduled as we are working.
|
||||||
// Thus, for fast tests, you should not have background work happening that is not
|
// Thus, for fast tests, you should not have background work happening that is not
|
||||||
// directly related to your code being tested.
|
// directly related to your code being tested.
|
||||||
//
|
//
|
||||||
|
|
||||||
// arbitrary; we have at least one level of a manager triggering another manager,
|
// arbitrary; we have at least one level of a manager triggering another manager,
|
||||||
// which would be 2
|
// which would be 2
|
||||||
int n = 3;
|
int n = 3;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
@@ -1743,8 +1757,8 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||||||
SwingUtilities.invokeAndWait(empty);
|
SwingUtilities.invokeAndWait(empty);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// Assumption: since our runnable is empty, this can only an interrupted
|
// Assumption: since our runnable is empty, this can only an interrupted
|
||||||
// exception, which can happen if our test framework decides to
|
// exception, which can happen if our test framework decides to
|
||||||
// shut the operation down.
|
// shut the operation down.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user