From c759dd1609acf1c25cd2c5888e9a62b0c06b36a7 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:01:17 -0400 Subject: [PATCH] GP-31 - fix Ghidra File chooser rendering on high dpi displays Filename display in the directory list mode were getting incorrectly truncated and shown with ellipses on high DPI display mode. The previous method was to manually calculate the necessary width of the directory list's cell renderer, but for some reason we were getting slightly different values when measuring strings when doing it in our code vs when swing's JLabel was painting, possible causing our manually sized cell renderer to be a few pixels too small. This fix is to yank all that out and let swing measure each element of the list to determine the necessary width. Also fixes the directory list cell renderer to inherit the -Dfont.size.override=XX setting from its parent panel instead of reseting the font back to non-overidden default. --- .../widgets/filechooser/DirectoryList.java | 78 ++++++------------- .../filechooser/FileListCellRenderer.java | 4 +- .../filechooser/GhidraFileChooser.java | 2 +- .../widgets/list/GListCellRenderer.java | 9 --- 4 files changed, 25 insertions(+), 68 deletions(-) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java index 98f028a99c..ba505bc949 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java @@ -25,8 +25,6 @@ import java.util.ArrayList; import java.util.List; import javax.swing.*; -import javax.swing.event.ListDataEvent; -import javax.swing.event.ListDataListener; import docking.event.mouse.GMouseListenerAdapter; import docking.widgets.AutoLookup; @@ -37,12 +35,10 @@ import ghidra.util.exception.AssertException; class DirectoryList extends GList implements GhidraFileChooserDirectoryModelIf { private static final int DEFAULT_ICON_SIZE = 16; - private static final int WIDTH_PADDING = 14; - private static final int HEIGHT_PADDING = 5; + private static final int MIN_HEIGHT_PADDING = 5; private GhidraFileChooser chooser; private DirectoryListModel model; - private FileListCellRenderer cellRenderer; private JLabel listEditorLabel; private JTextField listEditorField; private JPanel listEditor; @@ -50,35 +46,37 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod /** The file being edited */ private File editedFile; - DirectoryList(GhidraFileChooser chooser, DirectoryListModel model) { + /** + * Create a new DirectoryList instance. + * + * @param chooser the {@link GhidraFileChooser} this instance is nested in + * @param model the {@link DirectoryListModel} + * @param font the parent component's font, used to calculate row height in the list once + */ + DirectoryList(GhidraFileChooser chooser, DirectoryListModel model, Font font) { super(model); this.chooser = chooser; this.model = model; - build(); + build(font); } - private void build() { + private void build(Font font) { setLayoutOrientation(JList.VERTICAL_WRAP); - cellRenderer = new FileListCellRenderer(getFont(), chooser); + + FileListCellRenderer cellRenderer = new FileListCellRenderer(chooser); setCellRenderer(cellRenderer); - model.addListDataListener(new ListDataListener() { - @Override - public void contentsChanged(ListDataEvent e) { - // called when the list changes because a new file is inserted (ie. create new folder action) - recomputeListCellDimensions(null); - } - @Override - public void intervalAdded(ListDataEvent e) { - recomputeListCellDimensions(null); - } - - @Override - public void intervalRemoved(ListDataEvent e) { - // don't care - } - }); + // Enable the list to calculate the width of the cells on its own, but manually + // specify the height to ensure some padding between rows. + // We need the parent component's Font instead of using our + // own #getFont() because we are not a child of the parent yet and + // the font may be set to something other than the default. + FontMetrics metrics = cellRenderer.getFontMetrics(font); + setFixedCellHeight( + Math.max(metrics.getHeight(), DEFAULT_ICON_SIZE) + + Math.max(metrics.getHeight() / 3, MIN_HEIGHT_PADDING)); + setFixedCellWidth(-1); addMouseListener(new GMouseListenerAdapter() { @Override @@ -392,36 +390,6 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod } } - /** - * Resizes this list's cell dimensions based on the string widths found in the supplied - * list of files. - *

- * If there there are no files, uses the JScrollPane that contains us for the cellwidth. - * - * @param files list of files to use to resize the list's fixed cell dimensions. If null, uses - * the model's current set of files. - */ - private void recomputeListCellDimensions(List files) { - files = (files != null) ? files : model.getAllFiles(); - Dimension d = - cellRenderer.computePlainTextListCellDimensions(this, files, 0, DEFAULT_ICON_SIZE); - if (d.width == 0 && getParent() != null) { - // special case: if there were no files to measure, use the containing JScrollPane's - // width - if (getParent().getParent() instanceof JScrollPane) { - JScrollPane parent = (JScrollPane) getParent().getParent(); - Dimension parentSize = parent.getSize(); - Insets insets = parent.getInsets(); - d.width = parentSize.width - (insets != null ? insets.right + insets.left : 0); - } - } - else { - d.width += DEFAULT_ICON_SIZE + WIDTH_PADDING; - } - setFixedCellWidth(d.width); - setFixedCellHeight(d.height + HEIGHT_PADDING); - } - /*junit*/ JTextField getListEditorText() { return listEditorField; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileListCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileListCellRenderer.java index d6a7eb0bae..a311348655 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileListCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileListCellRenderer.java @@ -16,7 +16,6 @@ package docking.widgets.filechooser; import java.awt.Component; -import java.awt.Font; import java.io.File; import javax.swing.JList; @@ -29,8 +28,7 @@ class FileListCellRenderer extends GListCellRenderer { private GhidraFileChooser chooser; private GhidraFileChooserModel model; - public FileListCellRenderer(Font font, GhidraFileChooser chooser) { - super(font); + public FileListCellRenderer(GhidraFileChooser chooser) { this.chooser = chooser; this.model = chooser.getModel(); setShouldAlternateRowBackgroundColors(false); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java index f4220d8d51..01630c0bba 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java @@ -572,7 +572,7 @@ public class GhidraFileChooser extends DialogComponentProvider private JScrollPane buildDirectoryList() { directoryListModel = new DirectoryListModel(); - directoryList = new DirectoryList(this, directoryListModel); + directoryList = new DirectoryList(this, directoryListModel, rootPanel.getFont()); directoryList.setName("LIST"); directoryList.setBackground(BACKGROUND_COLOR); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java index d03132dc60..5b62739d92 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java @@ -60,15 +60,6 @@ public class GListCellRenderer extends AbstractGCellRenderer implements ListC setShouldAlternateRowBackgroundColors(false); } - /** - * Constructs a new GListCellRenderer using the specified font. - * @param f the font to use when rendering text in the lists' cells - */ - public GListCellRenderer(Font f) { - this(); - setFont(f); - } - /** * Return the cell renderer text * @param value Cell object value