Skip to content

Commit 3aac7da

Browse files
committed
Merge remote-tracking branch 'origin/patch'
Conflicts: Ghidra/Framework/Docking/src/main/java/docking/RootNode.java
2 parents 869a97a + 9ee0d29 commit 3aac7da

File tree

9 files changed

+122
-41
lines changed

9 files changed

+122
-41
lines changed

Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java

+19-6
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ private ListingField getFieldByFunction(ProxyObj<?> proxy, int varWidth,
385385
int availableLines = maxLines - functionRows.size();
386386
if (tooMany) {
387387
// save room for the "more" field at the end
388-
availableLines -= 1;
388+
availableLines = Math.max(1, availableLines--);
389389
}
390390

391391
//
@@ -394,7 +394,7 @@ private ListingField getFieldByFunction(ProxyObj<?> proxy, int varWidth,
394394

395395
//
396396
// Note: the objects we build here want the 'data' row as a parameter, not the screen row.
397-
// Out screen rows are what we are building to display; a data row we are here
397+
// Our screen rows are what we are building to display; a data row we are here
398398
// defining to be a single xref. This is a somewhat arbitrary decision.
399399
int dataRow = totalXrefs - noFunction.size();
400400
TextField noFunctionXrefsField =
@@ -802,10 +802,14 @@ public ProgramLocation getProgramLocation(int row, int col, ListingField listing
802802
RowColLocation loc = field.screenToDataLocation(row, col);
803803
if (element instanceof XrefFieldElement) {
804804
XrefFieldElement xrefElement = (XrefFieldElement) element;
805-
Reference xref = xrefElement.getXref();
806-
Address refAddr = xref.getFromAddress();
807-
return new XRefFieldLocation(cu.getProgram(), cu.getMinAddress(), cpath, refAddr, row,
808-
loc.col());
805+
return getXRefLocation(xrefElement, cu, cpath, loc, row);
806+
}
807+
else if (element instanceof StrutFieldElement) {
808+
FieldElement baseElement = ((StrutFieldElement) element).getBaseType();
809+
if (baseElement instanceof XrefFieldElement) {
810+
XrefFieldElement xrefElement = (XrefFieldElement) baseElement;
811+
return getXRefLocation(xrefElement, cu, cpath, loc, row);
812+
}
809813
}
810814

811815
String text = element.getText();
@@ -817,6 +821,15 @@ public ProgramLocation getProgramLocation(int row, int col, ListingField listing
817821
return null;
818822
}
819823

824+
private XRefFieldLocation getXRefLocation(XrefFieldElement xrefElement, CodeUnit cu,
825+
int[] cpath,
826+
RowColLocation loc, int row) {
827+
Reference xref = xrefElement.getXref();
828+
Address refAddr = xref.getFromAddress();
829+
return new XRefFieldLocation(cu.getProgram(), cu.getMinAddress(), cpath, refAddr, row,
830+
loc.col());
831+
}
832+
820833
protected String getBlockName(Program pgm, Address addr) {
821834
Memory mem = pgm.getMemory();
822835
MemoryBlock block = mem.getBlock(addr);

Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldMouseHandler.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
import java.awt.event.MouseEvent;
1919
import java.util.Set;
2020

21-
import docking.widgets.fieldpanel.field.FieldElement;
22-
import docking.widgets.fieldpanel.field.TextField;
21+
import docking.widgets.fieldpanel.field.*;
2322
import ghidra.app.nav.Navigatable;
2423
import ghidra.app.services.GoToService;
2524
import ghidra.app.util.XReferenceUtils;
@@ -58,8 +57,7 @@ public boolean fieldElementClicked(Object clickedObject, Navigatable sourceNavig
5857
}
5958

6059
Address referencedAddress = getFromReferenceAddress(location);
61-
String clickedText = getText(clickedObject);
62-
boolean isInvisibleXRef = XRefFieldFactory.MORE_XREFS_STRING.equals(clickedText);
60+
boolean isInvisibleXRef = isInvisibleXRef(clickedObject);
6361
if (isInvisibleXRef) {
6462
showXRefDialog(sourceNavigatable, location, serviceProvider);
6563
return true;
@@ -68,6 +66,21 @@ public boolean fieldElementClicked(Object clickedObject, Navigatable sourceNavig
6866
return goTo(sourceNavigatable, referencedAddress, goToService);
6967
}
7068

69+
private boolean isInvisibleXRef(Object clickedObject) {
70+
71+
String clickedText = getText(clickedObject);
72+
if (XRefFieldFactory.MORE_XREFS_STRING.equals(clickedText)) {
73+
return true;
74+
}
75+
76+
if (clickedObject instanceof StrutFieldElement) {
77+
// this implies that the xrefs field has been clipped and has used a struct to trigger
78+
// clipping
79+
return true;
80+
}
81+
return false;
82+
}
83+
7184
protected boolean isXREFHeaderLocation(ProgramLocation location) {
7285
return location instanceof XRefHeaderFieldLocation;
7386
}

Ghidra/Framework/Docking/src/main/java/docking/ComponentPlaceholder.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@
3535
* Class to hold information about a dockable component with respect to its position within the
3636
* windowing system. It also holds identification information about the provider so that its
3737
* location can be reused when the provider is re-opened.
38+
* <p>
39+
* The placeholder will be used to link previously saved position information. The tool will
40+
* initially construct plugins and their component providers with default position information.
41+
* Then, any existing xml data will be restored, which may have provider position information.
42+
* The restoring of the xml will create placeholders with this saved information. Finally, the
43+
* restored placeholders will be linked with existing component providers.
3844
*/
3945
public class ComponentPlaceholder {
4046
private String name;
@@ -68,7 +74,7 @@ public class ComponentPlaceholder {
6874
* @param name the name of the component
6975
* @param owner the owner of the component
7076
* @param group the window group
71-
* @param title the title
77+
* @param title the title
7278
* @param show whether or not the component is showing
7379
* @param node componentNode that has this placeholder
7480
* @param instanceID the instance ID
@@ -116,7 +122,7 @@ void setNode(ComponentNode node) {
116122
if (node != null && disposed) {
117123
//
118124
// TODO Hack Alert! (When this is removed, also update ComponentNode)
119-
//
125+
//
120126
// This should not happen! We have seen this bug recently
121127
Msg.debug(this, "Found disposed component that was not removed from the hierarchy " +
122128
"list: " + this, ReflectionUtilities.createJavaFilteredThrowable());

Ghidra/Framework/Docking/src/main/java/docking/DetachedWindowNode.java

+26-4
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,13 @@ private String getTitleOfChildren() {
242242

243243
/**
244244
* Creates a list of titles from the given component providers and placeholders. The utility
245-
* of this method is that it will group like component providers into one title value
245+
* of this method is that it will group like component providers into one title value
246246
* instead of having one value for each placeholder.
247247
*/
248248
private List<String> generateTitles(List<ComponentPlaceholder> placeholders) {
249249

250250
//
251-
// Decompose the given placeholders into a mapping of provider names to placeholders
251+
// Decompose the given placeholders into a mapping of provider names to placeholders
252252
// that share that name. This lets us group placeholders that are multiple instances of
253253
// the same provider.
254254
//
@@ -368,7 +368,7 @@ public void windowDeactivated(WindowEvent e) {
368368
}
369369

370370
/**
371-
* Ensures the bounds of this window have a valid location and size
371+
* Ensures the bounds of this window have a valid location and size
372372
*/
373373
private void adjustBounds() {
374374

@@ -474,6 +474,16 @@ else if (window != null) {
474474
@Override
475475
void dispose() {
476476

477+
disposeWindow();
478+
479+
if (child != null) {
480+
child.parent = null;
481+
child.dispose();
482+
child = null;
483+
}
484+
}
485+
486+
private void disposeWindow() {
477487
if (dropTargetHandler != null) {
478488
dropTargetHandler.dispose();
479489
}
@@ -485,12 +495,24 @@ void dispose() {
485495
window.dispose();
486496
window = null;
487497
}
498+
}
488499

500+
/**
501+
* An oddly named method for an odd use case. This method is meant to take an existing window,
502+
* such as that created by default when loading plugins, and hide it. Clients cannot simply
503+
* call dispose(), as that would also dispose the entire child hierarchy of this class. This
504+
* method is intended to keep all children not disposed while allowing this window node to go
505+
* away.
506+
*/
507+
void disconnect() {
508+
509+
// note: do not call child.dispose() here
489510
if (child != null) {
490511
child.parent = null;
491-
child.dispose();
492512
child = null;
493513
}
514+
515+
disposeWindow();
494516
}
495517

496518
@Override

Ghidra/Framework/Docking/src/main/java/docking/PlaceholderManager.java

+21-14
Original file line numberDiff line numberDiff line change
@@ -43,29 +43,36 @@ class PlaceholderManager {
4343
}
4444

4545
ComponentPlaceholder replacePlaceholder(ComponentProvider provider,
46-
ComponentPlaceholder oldPlaceholder) {
46+
ComponentPlaceholder defaultPlaceholder) {
4747

48-
ComponentPlaceholder newPlaceholder = createOrRecyclePlaceholder(provider, oldPlaceholder);
48+
// Note: the 'restoredPlaceholder' is from xml; the 'defaultPlaceholder' is that which was
49+
// created by a plugin as it was constructed. If there is no placeholder in the xml,
50+
// then the original 'defaultPlaceholder' will be returned from
51+
// createOrRecyclePlaceholder().
52+
ComponentPlaceholder restoredPlaceholder =
53+
createOrRecyclePlaceholder(provider, defaultPlaceholder);
4954

50-
moveActions(oldPlaceholder, newPlaceholder);
51-
if (!oldPlaceholder.isHeaderShowing()) {
52-
newPlaceholder.showHeader(false);
55+
moveActions(defaultPlaceholder, restoredPlaceholder);
56+
if (!defaultPlaceholder.isHeaderShowing()) {
57+
restoredPlaceholder.showHeader(false);
5358
}
5459

55-
if (oldPlaceholder.isShowing() != newPlaceholder.isShowing()) {
56-
if (newPlaceholder.isShowing()) {
60+
if (defaultPlaceholder.isShowing() != restoredPlaceholder.isShowing()) {
61+
if (restoredPlaceholder.isShowing()) {
5762
provider.componentShown();
5863
}
5964
else {
6065
provider.componentHidden();
6166
}
6267
}
6368

64-
if (newPlaceholder != oldPlaceholder) {
65-
oldPlaceholder.dispose();
66-
removePlaceholder(oldPlaceholder);
69+
// if we have found a replacement placeholder, then remove the default placeholder
70+
if (restoredPlaceholder != defaultPlaceholder) {
71+
defaultPlaceholder.dispose();
72+
removePlaceholder(defaultPlaceholder);
6773
}
68-
return newPlaceholder;
74+
75+
return restoredPlaceholder;
6976
}
7077

7178
/**
@@ -240,8 +247,8 @@ private ComponentPlaceholder findBestPlaceholderAnchor(
240247
// 1) share the same owner (plugin), and
241248
// 2) are in the same group, or related groups
242249
//
243-
// If there are not other providers that share the same owner as the one we are given,
244-
// then we will search all providers. This allows different plugins to share
250+
// If there are not other providers that share the same owner as the one we are given,
251+
// then we will search all providers. This allows different plugins to share
245252
// window arrangement.
246253
//
247254
Set<ComponentPlaceholder> buddies = activePlaceholders;
@@ -275,7 +282,7 @@ private ComponentPlaceholder findBestPlaceholderAnchor(
275282
* provider.
276283
* @param activePlaceholders the set of currently showing placeholders.
277284
* @param newInfo the placeholder for the new provider to be shown.
278-
* @return an existing matching placeholder or null.
285+
* @return an existing matching placeholder or null.
279286
*/
280287
private ComponentPlaceholder findBestPlaceholderToStackUpon(
281288
Set<ComponentPlaceholder> activePlaceholders, ComponentPlaceholder newInfo) {

Ghidra/Framework/Docking/src/main/java/docking/RootNode.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,13 @@ Element saveToXML() {
452452

453453
/**
454454
* Restores the component hierarchy from the given XML JDOM element.
455+
* <p>
456+
* The process of restoring from xml will create new {@link ComponentPlaceholder}s that will be
457+
* used to replace any existing matching placeholders. This allows the already loaded default
458+
* placeholders to be replaced by the previously saved configuration.
455459
*
456-
* @param root the XML from which to restore the state.
460+
* @param rootNodeElement the XML from which to restore the state.
461+
* @return the newly created placeholders
457462
*/
458463
List<ComponentPlaceholder> restoreFromXML(Element rootNodeElement) {
459464
invalid = true;
@@ -463,7 +468,7 @@ List<ComponentPlaceholder> restoreFromXML(Element rootNodeElement) {
463468
detachedWindows.clear();
464469
for (DetachedWindowNode windowNode : copy) {
465470
notifyWindowRemoved(windowNode);
466-
windowNode.dispose();
471+
windowNode.disconnect();
467472
}
468473

469474
int x = Integer.parseInt(rootNodeElement.getAttributeValue("X_POS"));
@@ -603,7 +608,7 @@ public Window getMainWindow() {
603608

604609
//==================================================================================================
605610
// Inner Classes
606-
//==================================================================================================
611+
//==================================================================================================
607612

608613
/** Interface to wrap JDialog and JFrame so that they can be used by one handle */
609614
private interface SwingWindowWrapper {

Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/CompositeVerticalLayoutTextField.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ private ClippingTextField createClippedField(FieldElement element) {
146146

147147
FieldElement[] elements = new FieldElement[] {
148148
element,
149-
new StrutFieldElement(500)
149+
new StrutFieldElement(element, 500)
150150
};
151151
FieldElement compositeElement = new CompositeFieldElement(elements);
152152
return new ClippingTextField(startX, width, compositeElement, hlFactory);
@@ -284,14 +284,13 @@ public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip
284284
int startY = myStartY;
285285
int translatedY = 0;
286286

287-
for (int i = 0; i < fieldRows.size(); i++) {
287+
for (FieldRow fieldRow : fieldRows) {
288288

289289
// if past clipping region we are done
290290
if (startY > clipEndY) {
291291
break;
292292
}
293293

294-
FieldRow fieldRow = fieldRows.get(i);
295294
TextField field = fieldRow.field;
296295
int subFieldHeight = fieldRow.field.getHeight();
297296
int endY = startY + subFieldHeight;

Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/StrutFieldElement.java

+20-3
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,29 @@
2828
*/
2929
public class StrutFieldElement implements FieldElement {
3030

31+
private final FieldElement baseElement;
3132
private final int width;
3233

33-
public StrutFieldElement(int width) {
34+
/**
35+
* Constructor. Clients may choose to pass
36+
*
37+
* @param baseElement the base type replaced by this strut; may be null if no type is being
38+
* replaced
39+
* @param width the width of this strut class
40+
*/
41+
public StrutFieldElement(FieldElement baseElement, int width) {
42+
this.baseElement = baseElement;
3443
this.width = width;
3544
}
3645

46+
/**
47+
* Returns the base type replaced by this strut; may be null
48+
* @return the base type replaced by this strut; may be null
49+
*/
50+
public FieldElement getBaseType() {
51+
return baseElement;
52+
}
53+
3754
@Override
3855
public char charAt(int index) {
3956
return ' ';
@@ -101,12 +118,12 @@ public FieldElement replaceAll(char[] targets, char replacement) {
101118

102119
@Override
103120
public FieldElement substring(int start) {
104-
return new StrutFieldElement(0);
121+
return new StrutFieldElement(baseElement, 0);
105122
}
106123

107124
@Override
108125
public FieldElement substring(int start, int end) {
109-
return new StrutFieldElement(0);
126+
return new StrutFieldElement(baseElement, 0);
110127
}
111128

112129
@Override

Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ protected List<FieldRow> layoutElements(List<FieldElement> textElements, int max
446446
if (tooManyLines && (i == maxLines - 1)) {
447447
FieldElement[] elements = new FieldElement[2];
448448
elements[0] = element;
449-
elements[1] = new StrutFieldElement(500);
449+
elements[1] = new StrutFieldElement(element, 500);
450450
element = new CompositeFieldElement(elements);
451451
}
452452
TextField field = createFieldForLine(element);
@@ -459,7 +459,6 @@ protected List<FieldRow> layoutElements(List<FieldElement> textElements, int max
459459
}
460460

461461
isClipped |= tooManyLines;
462-
463462
return newSubFields;
464463
}
465464

0 commit comments

Comments
 (0)