mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Fixed the GFilterTable to have the selection notification include when
the selection is cleared
This commit is contained in:
parent
41c453c545
commit
d68e9bbab8
5 changed files with 152 additions and 99 deletions
|
@ -17,7 +17,6 @@ package ghidra.app.plugin.core.calltree;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ import javax.swing.tree.TreePath;
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.WindowPosition;
|
import docking.WindowPosition;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.util.GraphicsUtils;
|
import docking.resources.icons.NumberIcon;
|
||||||
import docking.widgets.dialogs.NumberInputDialog;
|
import docking.widgets.dialogs.NumberInputDialog;
|
||||||
import docking.widgets.label.GLabel;
|
import docking.widgets.label.GLabel;
|
||||||
import docking.widgets.tree.*;
|
import docking.widgets.tree.*;
|
||||||
|
@ -1283,97 +1282,6 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NumberIcon implements Icon {
|
|
||||||
private String number;
|
|
||||||
private float bestFontSize = -1;
|
|
||||||
|
|
||||||
NumberIcon(int number) {
|
|
||||||
this.number = Integer.toString(number);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setNumber(int number) {
|
|
||||||
this.number = Integer.toString(number);
|
|
||||||
bestFontSize = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
|
||||||
g.setColor(Color.WHITE);
|
|
||||||
g.fillRect(x, y, getIconWidth(), getIconHeight());
|
|
||||||
g.setColor(new Color(0xb5d5ff));
|
|
||||||
g.drawRect(x, y, getIconWidth(), getIconHeight());
|
|
||||||
|
|
||||||
float fontSize = getMaxFontSize(g, getIconWidth() - 1, getIconHeight());
|
|
||||||
Font originalFont = g.getFont();
|
|
||||||
Font textFont = originalFont.deriveFont(fontSize).deriveFont(Font.BOLD);
|
|
||||||
g.setFont(textFont);
|
|
||||||
|
|
||||||
FontMetrics fontMetrics = g.getFontMetrics(textFont);
|
|
||||||
Rectangle2D stringBounds = fontMetrics.getStringBounds(number, g);
|
|
||||||
int textHeight = (int) stringBounds.getHeight();
|
|
||||||
int iconHeight = getIconHeight();
|
|
||||||
int space = y + iconHeight - textHeight;
|
|
||||||
int halfSpace = space >> 1;
|
|
||||||
int baselineY = y + iconHeight - halfSpace;// - halfTextHeight;// + halfTextHeight;
|
|
||||||
|
|
||||||
int textWidth = (int) stringBounds.getWidth();
|
|
||||||
int iconWidth = getIconWidth();
|
|
||||||
int halfWidth = iconWidth >> 1;
|
|
||||||
int halfTextWidth = textWidth >> 1;
|
|
||||||
int baselineX = x + halfWidth - halfTextWidth;
|
|
||||||
|
|
||||||
g.setColor(Color.BLACK);
|
|
||||||
JComponent jc = null;
|
|
||||||
if (c instanceof JComponent) {
|
|
||||||
jc = (JComponent) c;
|
|
||||||
}
|
|
||||||
GraphicsUtils.drawString(jc, g, number, baselineX, baselineY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getMaxFontSize(Graphics g, int width, int height) {
|
|
||||||
if (bestFontSize > 0) {
|
|
||||||
return bestFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
float size = 12f;
|
|
||||||
Font font = g.getFont().deriveFont(size); // reasonable default
|
|
||||||
if (textFitsInFont(g, font, width, height)) {
|
|
||||||
bestFontSize = size;
|
|
||||||
return bestFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
size--;
|
|
||||||
font = g.getFont().deriveFont(size);
|
|
||||||
}
|
|
||||||
while (!textFitsInFont(g, font, width, height));
|
|
||||||
|
|
||||||
bestFontSize = Math.max(1f, size);
|
|
||||||
return bestFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean textFitsInFont(Graphics g, Font font, int width, int height) {
|
|
||||||
FontMetrics fontMetrics = g.getFontMetrics(font);
|
|
||||||
int textWidth = fontMetrics.stringWidth(number);
|
|
||||||
if (textWidth > width) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int textHeight = fontMetrics.getHeight();
|
|
||||||
return textHeight < height;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getIconHeight() {
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getIconWidth() {
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PendingRootNode extends GTreeNode {
|
private class PendingRootNode extends GTreeNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* ###
|
||||||
|
* 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.resources.icons;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
import docking.util.GraphicsUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An icon that paints the given number
|
||||||
|
*/
|
||||||
|
public class NumberIcon implements Icon {
|
||||||
|
|
||||||
|
private String number;
|
||||||
|
private float bestFontSize = -1;
|
||||||
|
|
||||||
|
public NumberIcon(int number) {
|
||||||
|
this.number = Integer.toString(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumber(int number) {
|
||||||
|
this.number = Integer.toString(number);
|
||||||
|
bestFontSize = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||||
|
g.setColor(Color.WHITE);
|
||||||
|
g.fillRect(x, y, getIconWidth(), getIconHeight());
|
||||||
|
g.setColor(new Color(0xb5d5ff));
|
||||||
|
g.drawRect(x, y, getIconWidth(), getIconHeight());
|
||||||
|
|
||||||
|
float fontSize = getMaxFontSize(g, getIconWidth() - 1, getIconHeight());
|
||||||
|
Font originalFont = g.getFont();
|
||||||
|
Font textFont = originalFont.deriveFont(fontSize).deriveFont(Font.BOLD);
|
||||||
|
g.setFont(textFont);
|
||||||
|
|
||||||
|
FontMetrics fontMetrics = g.getFontMetrics(textFont);
|
||||||
|
Rectangle2D stringBounds = fontMetrics.getStringBounds(number, g);
|
||||||
|
int textHeight = (int) stringBounds.getHeight();
|
||||||
|
int iconHeight = getIconHeight();
|
||||||
|
int space = y + iconHeight - textHeight;
|
||||||
|
int halfSpace = space >> 1;
|
||||||
|
int baselineY = y + iconHeight - halfSpace;// - halfTextHeight;// + halfTextHeight;
|
||||||
|
|
||||||
|
int textWidth = (int) stringBounds.getWidth();
|
||||||
|
int iconWidth = getIconWidth();
|
||||||
|
int halfWidth = iconWidth >> 1;
|
||||||
|
int halfTextWidth = textWidth >> 1;
|
||||||
|
int baselineX = x + (halfWidth - halfTextWidth);
|
||||||
|
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
JComponent jc = null;
|
||||||
|
if (c instanceof JComponent) {
|
||||||
|
jc = (JComponent) c;
|
||||||
|
}
|
||||||
|
GraphicsUtils.drawString(jc, g, number, baselineX, baselineY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getMaxFontSize(Graphics g, int width, int height) {
|
||||||
|
if (bestFontSize > 0) {
|
||||||
|
return bestFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
float size = 12f;
|
||||||
|
Font font = g.getFont().deriveFont(size); // reasonable default
|
||||||
|
if (textFitsInFont(g, font, width, height)) {
|
||||||
|
bestFontSize = size;
|
||||||
|
return bestFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
size--;
|
||||||
|
font = g.getFont().deriveFont(size);
|
||||||
|
}
|
||||||
|
while (!textFitsInFont(g, font, width, height));
|
||||||
|
|
||||||
|
bestFontSize = Math.max(1f, size);
|
||||||
|
return bestFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean textFitsInFont(Graphics g, Font font, int width, int height) {
|
||||||
|
|
||||||
|
// padding so the text does not touch the border
|
||||||
|
int padding = 2;
|
||||||
|
FontMetrics fontMetrics = g.getFontMetrics(font);
|
||||||
|
int textWidth = fontMetrics.stringWidth(number) + padding;
|
||||||
|
if (textWidth > width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int textHeight = fontMetrics.getHeight();
|
||||||
|
return textHeight < height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconHeight() {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconWidth() {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,7 +70,7 @@ public class GFilterTable<ROW_OBJECT> extends JPanel {
|
||||||
private void addTableSelectionListener(GTable gTable) {
|
private void addTableSelectionListener(GTable gTable) {
|
||||||
gTable.getSelectionModel().addListSelectionListener(e -> {
|
gTable.getSelectionModel().addListSelectionListener(e -> {
|
||||||
if (!e.getValueIsAdjusting()) {
|
if (!e.getValueIsAdjusting()) {
|
||||||
rowSelected();
|
rowSelectionChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,7 @@ public class GFilterTable<ROW_OBJECT> extends JPanel {
|
||||||
|
|
||||||
public void clearSelection() {
|
public void clearSelection() {
|
||||||
table.clearSelection();
|
table.clearSelection();
|
||||||
|
table.getSelectionManager().clearSavedSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,19 +164,31 @@ public class GFilterTable<ROW_OBJECT> extends JPanel {
|
||||||
listeners.remove(l);
|
listeners.remove(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void rowSelectionChanged() {
|
||||||
* Notifies listeners that an item was selected.
|
|
||||||
*/
|
|
||||||
protected void rowSelected() {
|
|
||||||
ROW_OBJECT selectedObject = null;
|
ROW_OBJECT selectedObject = null;
|
||||||
if (table.getSelectedRow() >= 0) {
|
if (table.getSelectedRow() >= 0) {
|
||||||
selectedObject = getSelectedRowObject();
|
selectedObject = getSelectedRowObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedObject == null) {
|
if (selectedObject == null) {
|
||||||
|
rowSelectionCleared();
|
||||||
return; // can happen for transient events
|
return; // can happen for transient events
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rowSelected(selectedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void rowSelectionCleared() {
|
||||||
|
for (ObjectSelectedListener<ROW_OBJECT> l : listeners) {
|
||||||
|
l.objectSelected(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies listeners that an item was selected
|
||||||
|
* @param selectedObject the selected row object
|
||||||
|
*/
|
||||||
|
protected void rowSelected(ROW_OBJECT selectedObject) {
|
||||||
for (ObjectSelectedListener<ROW_OBJECT> l : listeners) {
|
for (ObjectSelectedListener<ROW_OBJECT> l : listeners) {
|
||||||
l.objectSelected(selectedObject);
|
l.objectSelected(selectedObject);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,16 @@
|
||||||
*/
|
*/
|
||||||
package docking.widgets.table;
|
package docking.widgets.table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for clients to know when an object is selected and when the selection is cleared
|
||||||
|
*
|
||||||
|
* @param <T> the object type
|
||||||
|
*/
|
||||||
public interface ObjectSelectedListener<T> {
|
public interface ObjectSelectedListener<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an object is select; null if the selection is cleared
|
||||||
|
* @param t the object selected or null
|
||||||
|
*/
|
||||||
public void objectSelected(T t);
|
public void objectSelected(T t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,7 +270,7 @@ public class HTMLUtilities {
|
||||||
* @param text the text to check
|
* @param text the text to check
|
||||||
* @return true if the text cannot be correctly broken into lines
|
* @return true if the text cannot be correctly broken into lines
|
||||||
*/
|
*/
|
||||||
private static boolean isUnbreakableHTML(String text) {
|
public static boolean isUnbreakableHTML(String text) {
|
||||||
if (text.contains(HTML_SPACE) && !text.contains(" ")) {
|
if (text.contains(HTML_SPACE) && !text.contains(" ")) {
|
||||||
// this can happen if the client has called a method on this class that turns spaces
|
// this can happen if the client has called a method on this class that turns spaces
|
||||||
// to the HTML_SPACE
|
// to the HTML_SPACE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue