Fixed the GFilterTable to have the selection notification include when

the selection is cleared
This commit is contained in:
dragonmacher 2021-01-05 18:52:18 -05:00
parent 41c453c545
commit d68e9bbab8
5 changed files with 152 additions and 99 deletions

View file

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

View file

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

View file

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

View file

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

View file

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