From b837bd3aa341a718f6d149973f3a5be9fbb79846 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 19 Aug 2022 16:52:15 -0400 Subject: [PATCH] GP-1981 - Theming - GColor migration fixes --- Ghidra/Features/Base/certification.manifest | 4 - .../Base/data/base.listing.theme.properties | 24 + .../Features/Base/data/base.theme.properties | 12 +- .../AnalysisEnablementTableModel.java | 21 +- .../commentwindow/CommentWindowProvider.java | 4 +- .../core/datawindow/DataWindowProvider.java | 16 +- .../plugin/core/progmgr/MultiTabPanel.java | 48 +- .../plugin/core/progmgr/ProgramListPanel.java | 23 +- .../util/viewer/format/FieldHeaderComp.java | 63 +- .../viewer/listingpanel/ListingPanel.java | 3 +- .../Decompiler/certification.manifest | 1 + .../data/decompiler.theme.properties | 7 + .../decompiler/component/DecompilerPanel.java | 3 +- .../Docking/data/docking.theme.properties | 17 +- .../java/docking/DialogComponentProvider.java | 14 +- .../src/main/java/docking/HeaderCursor.java | 30 +- .../src/main/java/docking/SplitPanel.java | 4 +- .../java/docking/help/GHelpHTMLEditorKit.java | 536 ++++++++++++++++++ .../docking/widgets/SelectFromListDialog.java | 15 +- .../java/docking/widgets/list/ListPanel.java | 31 +- .../src/main/java/resources/Icons.java | 30 +- .../src/main/java/generic/theme/GIcon.java | 24 + .../src/main/java/generic/theme/GTheme.java | 1 - .../src/main/java/generic/theme/Gui.java | 4 +- .../src/main/java/resources/IconProvider.java | 13 +- .../main/java/resources/ResourceManager.java | 7 + .../Project/data/project.theme.properties | 21 +- .../framework/main/ProjectDataPanel.java | 13 +- .../ghidra/framework/main/SaveDataDialog.java | 90 +-- .../main/datatree/DomainFilesPanel.java | 3 +- .../dialog/PluginInstallerDialog.java | 10 +- .../framework/task/gui/GProgressBar.java | 2 + .../task/gui/taskview/ScheduledTaskPanel.java | 5 +- 33 files changed, 866 insertions(+), 233 deletions(-) create mode 100644 Ghidra/Features/Decompiler/data/decompiler.theme.properties create mode 100644 Ghidra/Framework/Docking/src/main/java/docking/help/GHelpHTMLEditorKit.java diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index ebdad0323b..cece82d6aa 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -1002,7 +1002,6 @@ src/main/resources/images/cloudbarReversed.jpg||GHIDRA||reviewed||END| src/main/resources/images/codeInView.gif||GHIDRA||||END| src/main/resources/images/codeNotInView.gif||GHIDRA||||END| src/main/resources/images/collapse.gif||GHIDRA||||END| -src/main/resources/images/collapse_all.png||GHIDRA||||END| src/main/resources/images/conflictKeep.png||GHIDRA||||END| src/main/resources/images/conflictRename.png||GHIDRA||||END| src/main/resources/images/conflictReplace.png||GHIDRA||||END| @@ -1093,8 +1092,6 @@ src/main/resources/images/ledred.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set| src/main/resources/images/ledyellow.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| src/main/resources/images/link.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| src/main/resources/images/list-remove.png||Oxygen Icons - LGPL 3.0||||END| -src/main/resources/images/locationIn.gif||GHIDRA||||END| -src/main/resources/images/locationOut.gif||GHIDRA||||END| src/main/resources/images/lock.gif||GHIDRA||||END| src/main/resources/images/lock.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/magnifier.png||FAMFAMFAM Icons - CC 2.5||||END| @@ -1196,7 +1193,6 @@ src/main/resources/images/view-sort-ascending.png||Oxygen Icons - LGPL 3.0|||Oxy src/main/resources/images/view-sort-descending.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/viewedCode.gif||GHIDRA||||END| src/main/resources/images/viewmag.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| -src/main/resources/images/viewmagfit.png||Nuvola Icons - LGPL 2.1|||Nuvola|END| src/main/resources/images/warning.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/wizard.png||Nuvola Icons - LGPL 2.1|||nuvola|END| src/main/resources/images/x-office-document-template.png||Tango Icons - Public Domain|||tango icon set|END| diff --git a/Ghidra/Features/Base/data/base.listing.theme.properties b/Ghidra/Features/Base/data/base.listing.theme.properties index 6cfcfb8e57..448ee4895e 100644 --- a/Ghidra/Features/Base/data/base.listing.theme.properties +++ b/Ghidra/Features/Base/data/base.listing.theme.properties @@ -5,6 +5,18 @@ color.bg.currentline.listing = color.bg.currentline color.bg.selection.listing = color.bg.selection color.bg.highlight.listing = color.bg.highlight +color.bg.listing.tabs.selected = #788CBD +color.bg.listing.tabs.unselected = [color]control +color.bg.listing.tabs.highlighted = #ABC8FF +color.bg.listing.tabs.list = rgb(255, 255, 230) +color.fg.listing.tabs.text.selected = black +color.fg.listing.tabs.text.unselected = color.fg +color.fg.listing.tabs.list = black + + + +color.bg.listing.header.active.field = rgb(244, 221, 183) +color.fg.listing.header.active.field = color.fg color.cursor.focused.listing = color.cursor.focused color.cursor.unfocused.listing = color.cursor.unfocused @@ -62,6 +74,18 @@ color.fg.listing.pcode.userop = blue [Dark Defaults] +color.bg.listing.tabs.selected = #788CBD +color.bg.listing.tabs.unselected = [color]control +color.bg.listing.tabs.highlighted = #ABC8FF +color.bg.listing.tabs.list = rgb(255, 255, 230) +color.fg.listing.tabs.text.selected = black +color.fg.listing.tabs.text.unselected = color.fg +color.fg.listing.tabs.list = black + + +color.bg.listing.header.active.field = rgb(244, 221, 183) +color.fg.listing.header.active.field = black + #color.fg.listing.address = color.fg #color.fg.listing.ref.bad = red #color.fg.listing.bytes = blue diff --git a/Ghidra/Features/Base/data/base.theme.properties b/Ghidra/Features/Base/data/base.theme.properties index d267133b43..c56e8053dc 100644 --- a/Ghidra/Features/Base/data/base.theme.properties +++ b/Ghidra/Features/Base/data/base.theme.properties @@ -40,12 +40,16 @@ color.bg.search.current-line.highlight = yellow color.bg.tree.renderer.icon.fill = #9F9FFF color.bg.tree.renderer.icon.line = #8282FF - +color.bg.analysis.options.not.default.enablement = rgb(255, 255, 200) +color.bg.analysis.options.not.default.enablement.selected = rgb(177, 212, 236) +color.fg.analysis.options.prototype = crimson [Dark Defaults] color.bg = rgb(40, 42, 46) // TODO this should be in a more generic module +color.bg.undefined = #5C4D68 + color.flowtype.fall-through = rgb(164, 66, 66) color.flowtype.jump.conditional = rgb(95, 129, 157) color.flowtype.jump.unconditional = rgb(140, 148, 64) @@ -68,4 +72,8 @@ color.bg.search.highlight = rgb(189,183,107) color.bg.search.current-line.highlight = gold color.fg.listing.highlighter.scoped-read = rgb(100,100, 0) -color.fg.listing.highlighter.scoped-write = forestGreen \ No newline at end of file +color.fg.listing.highlighter.scoped-write = forestGreen + +color.bg.analysis.options.not.default.enablement = #D1D19E +color.bg.analysis.options.not.default.enablement.selected = rgb(177, 212, 236) +color.fg.analysis.options.prototype = lightcoral diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java index 0b3b5dd01e..d50651da09 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java @@ -23,10 +23,11 @@ import javax.swing.JComponent; import javax.swing.JTable; import docking.widgets.table.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; import ghidra.framework.plugintool.ServiceProviderStub; -import ghidra.util.ColorUtils; import ghidra.util.table.column.AbstractGColumnRenderer; import ghidra.util.table.column.GColumnRenderer; @@ -36,8 +37,12 @@ import ghidra.util.table.column.GColumnRenderer; public class AnalysisEnablementTableModel extends GDynamicColumnTableModel { - private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT = new Color(255, 255, 200); - private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT_SELECTED = new Color(177, 212, 236); + private static Color FG_COLOR_PROTOTYPE = new GColor("color.fg.analysis.options.prototype"); + + private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT = + new GColor("color.bg.analysis.options.not.default.enablement"); + private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT_SELECTED = + new GColor("color.bg.analysis.options.not.default.enablement.selected"); private List analyzerStates; private AnalysisPanel panel; @@ -203,10 +208,10 @@ public class AnalysisEnablementTableModel } String analyzerName = (String) value; - if (analyzerName.endsWith(AnalysisPanel.PROTOTYPE)) { - component.setForeground( - ColorUtils.deriveForeground(component.getBackground(), ColorUtils.HUE_RED)); + if (!data.isSelected()) { + component.setForeground(FG_COLOR_PROTOTYPE); + } } AnalyzerEnablementState state = (AnalyzerEnablementState) data.getRowObject(); @@ -215,10 +220,10 @@ public class AnalysisEnablementTableModel return component; } - // not the default enablement + // not the default enablement + component.setForeground(Palette.BLACK); if (data.isSelected()) { component.setBackground(BG_COLOR_NOT_DEFAULT_ENABLEMENT_SELECTED); - component.setForeground(Color.BLACK); } else { component.setBackground(BG_COLOR_NOT_DEFAULT_ENABLEMENT); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java index e427c082ac..6f22a7618a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java @@ -88,7 +88,9 @@ class CommentWindowProvider extends ComponentProviderAdapter { } void programClosed() { - commentModel.reload(null); + if (isVisible()) { + commentModel.reload(null); + } } void dispose() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java index 2569ea574d..a9eec895d9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java @@ -93,7 +93,9 @@ class DataWindowProvider extends ComponentProviderAdapter { } void programClosed() { - dataModel.reload(null); + if (isVisible()) { + dataModel.reload(null); + } } void dispose() { @@ -156,10 +158,14 @@ class DataWindowProvider extends ComponentProviderAdapter { } private void setDataTableRenderer() { - dataTable.getColumnModel().getColumn(DataTableModel.LOCATION_COL).setPreferredWidth( - DataTableModel.ADDRESS_COL_WIDTH); - dataTable.getColumnModel().getColumn(DataTableModel.SIZE_COL).setPreferredWidth( - DataTableModel.SIZE_COL_WIDTH); + dataTable.getColumnModel() + .getColumn(DataTableModel.LOCATION_COL) + .setPreferredWidth( + DataTableModel.ADDRESS_COL_WIDTH); + dataTable.getColumnModel() + .getColumn(DataTableModel.SIZE_COL) + .setPreferredWidth( + DataTableModel.SIZE_COL_WIDTH); } void reload() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java index 91c25c1b1e..073a69717a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java @@ -27,6 +27,7 @@ import javax.swing.border.*; import docking.actions.KeyBindingUtils; import docking.widgets.label.GDLabel; import docking.widgets.label.GIconLabel; +import generic.theme.GColor; import generic.util.WindowUtilities; import ghidra.framework.model.ProjectLocator; import ghidra.program.model.listing.Program; @@ -38,8 +39,9 @@ import resources.ResourceManager; */ public class MultiTabPanel extends JPanel { - private final static Color SELECTED_TAB_COLOR = new Color(120, 140, 189); - private final static Color HIGHLIGHTED_TAB_COLOR = SELECTED_TAB_COLOR.brighter(); + private final static Color SELECTED_TAB_COLOR = new GColor("color.bg.listing.tabs.selected"); + private final static Color HIGHLIGHTED_TAB_BG_COLOR = + new GColor("color.bg.listing.tabs.highlighted"); private final static Icon EMPTY16_ICON = ResourceManager.loadImage("images/EmptyIcon16.gif"); private final static Icon EMPTY8_ICON = ResourceManager.loadImage("images/empty8x16.png"); private final static Icon CLOSE_ICON = ResourceManager.loadImage("images/x.gif"); @@ -47,10 +49,13 @@ public class MultiTabPanel extends JPanel { private final static Icon LIST_ICON = ResourceManager.loadImage("images/VCRFastForward.gif"); private final static Icon TRANSIENT_ICON = ResourceManager.loadImage("images/link.png", 8, 16); - private final static Color TEXT_SELECTION_COLOR = Color.WHITE; - private final static Color TEXT_NON_SELECTION_COLOR = UIManager.getColor("Tree.textForeground"); + private final static Color TEXT_SELECTION_COLOR = + new GColor("color.fg.listing.tabs.text.selected"); + private final static Color TEXT_NON_SELECTION_COLOR = + new GColor("color.fg.listing.tabs.text.unselected"); private final static Color BG_SELECTION_COLOR = SELECTED_TAB_COLOR; - private final static Color BG_NON_SELECTION_COLOR = UIManager.getColor("Panel.background"); + private final static Color BG_NON_SELECTION_COLOR = + new GColor("color.bg.listing.tabs.unselected"); private static final Font LABEL_FONT = new Font("Tahoma", Font.PLAIN, 11); private static final Font LIST_LABEL_FONT = new Font("Tahoma", Font.BOLD, 9); @@ -70,8 +75,6 @@ public class MultiTabPanel extends JPanel { private MultiTabPlugin multiTabPlugin; private ProgramListPanel programListPanel; private Border defaultListLabelBorder; - private Border noTabsBorder; - private Border tabbedBorder; private JLabel showHiddenListLabel; private JDialog listWindow; private JTextField filterField; @@ -126,8 +129,8 @@ public class MultiTabPanel extends JPanel { currentProgram = null; ArrayList list = new ArrayList<>(linkedProgramMap.keySet()); - for (int i = 0; i < list.size(); i++) { - doRemoveProgram(list.get(i)); + for (Program element : list) { + doRemoveProgram(element); } linkedProgramMap.clear(); visibleTabList.clear(); @@ -912,7 +915,8 @@ public class MultiTabPanel extends JPanel { //================================================================================================== private class TabPanel extends JPanel { - private Color defaultBackgroundColor; + private Color defaultBgColor; + private Color defaultFgColor; protected final JLabel nameLabel; protected final JPanel labelPanel; protected final JLabel iconLabel; @@ -920,7 +924,8 @@ public class MultiTabPanel extends JPanel { private TabPanel(Color backgroundColor, Program program, JLabel nameLabel, JPanel labelPanel, JLabel iconLabel) { - this.defaultBackgroundColor = backgroundColor; + this.defaultBgColor = backgroundColor; + this.defaultFgColor = nameLabel.getForeground(); this.program = program; this.nameLabel = nameLabel; this.labelPanel = labelPanel; @@ -942,14 +947,19 @@ public class MultiTabPanel extends JPanel { } void paintHighlightedColor(boolean paintHighlight) { - Color newBackgroundColor = defaultBackgroundColor; + Color newBgColor = defaultBgColor; + Color newFgColor = defaultFgColor; if (paintHighlight) { - newBackgroundColor = HIGHLIGHTED_TAB_COLOR; + newBgColor = HIGHLIGHTED_TAB_BG_COLOR; + newFgColor = TEXT_SELECTION_COLOR; + } - setBackground(newBackgroundColor); - nameLabel.setBackground(newBackgroundColor); - labelPanel.setBackground(newBackgroundColor); - iconLabel.setBackground(newBackgroundColor); + + setBackground(newBgColor); + nameLabel.setBackground(newBgColor); + nameLabel.setForeground(newFgColor); + labelPanel.setBackground(newBgColor); + iconLabel.setBackground(newBgColor); } } @@ -985,9 +995,9 @@ public class MultiTabPanel extends JPanel { @Override void paintHighlightedColor(boolean paintHighlight) { super.paintHighlightedColor(paintHighlight); - Color foreground = Color.WHITE; + Color foreground = TEXT_NON_SELECTION_COLOR; if (paintHighlight) { - foreground = Color.BLACK; + foreground = TEXT_SELECTION_COLOR; } // this tab is selected, so change the foreground to be readable diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java index 1a05165d30..95a0e4fb21 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java @@ -30,16 +30,20 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Document; import docking.widgets.list.GListCellRenderer; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.program.model.listing.Program; /** - * Panel that displays the overflow of currently open programs that can be choosen. + * Panel that displays the overflow of currently open programs that can be chosen. *

* Programs that don't have a visible tab are displayed in bold. */ class ProgramListPanel extends JPanel { - private static final Color BACKGROUND_COLOR = new Color(255, 255, 230); + private static final Color BACKGROUND_COLOR = new GColor("color.bg.listing.tabs.list"); + private static final Color FOREGROUND_COLOR = new GColor("color.fg.listing.tabs.list"); + private List hiddenList; private List shownList; private JList programList; @@ -74,9 +78,6 @@ class ProgramListPanel extends JPanel { programList.clearSelection(); } - /** - * Return the JList component. - */ JList getList() { return programList; } @@ -115,6 +116,7 @@ class ProgramListPanel extends JPanel { initListModel(); programList = new JList<>(listModel); programList.setBackground(BACKGROUND_COLOR); + programList.setForeground(FOREGROUND_COLOR); programList.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); programList.addMouseMotionListener(new MouseMotionAdapter() { @Override @@ -147,7 +149,7 @@ class ProgramListPanel extends JPanel { // add some padding around the panel Border innerBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5); - Border outerBorder = BorderFactory.createLineBorder(Color.BLACK); + Border outerBorder = BorderFactory.createLineBorder(Java.BORDER); Border compoundBorder = BorderFactory.createCompoundBorder(outerBorder, innerBorder); setBorder(compoundBorder); @@ -157,6 +159,7 @@ class ProgramListPanel extends JPanel { private JTextField createFilterField() { JTextField newFilterField = new JTextField(20); newFilterField.setBackground(BACKGROUND_COLOR); + newFilterField.setForeground(FOREGROUND_COLOR); newFilterField.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); newFilterField.getDocument().addDocumentListener(new DocumentListener() { @@ -222,11 +225,11 @@ class ProgramListPanel extends JPanel { private void initListModel() { listModel.clear(); - for (int i = 0; i < hiddenList.size(); i++) { - listModel.addElement(hiddenList.get(i)); + for (Program element : hiddenList) { + listModel.addElement(element); } - for (int i = 0; i < shownList.size(); i++) { - listModel.addElement(shownList.get(i)); + for (Program element : shownList) { + listModel.addElement(element); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java index 9fec8465b4..4f743cdb9e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java @@ -22,6 +22,7 @@ import javax.swing.*; import javax.swing.border.Border; import docking.widgets.label.GDLabel; +import generic.theme.GColor; import ghidra.app.util.viewer.field.FieldFactory; import ghidra.util.HelpLocation; import ghidra.util.Swing; @@ -41,6 +42,11 @@ public class FieldHeaderComp extends JPanel { private static final int DEFAULT_SNAP_SIZE = 10; + private static final Color ACTIVE_FIELD_BG_COLOR = + new GColor("color.bg.listing.header.active.field"); // new Color(244, 221, 183); + private static final Color ACTIVE_FIELD_FG_COLOR = + new GColor("color.fg.listing.header.active.field"); // new Color(244, 221, 183); + private FieldFormatModel model; private JLabel label; private int rowHeight; @@ -52,8 +58,8 @@ public class FieldHeaderComp extends JPanel { private int anchorX; private int anchorY; private int snapSize = DEFAULT_SNAP_SIZE; - private Color buttonColor; - private Color highlightButtonColor; + private Color defaultButtonBgColor; + private Color defaultButtonFgColor; private boolean editInProgress; private MovingField moving; @@ -78,11 +84,11 @@ public class FieldHeaderComp extends JPanel { label = new GDLabel("Test"); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); - buttonColor = label.getBackground(); + defaultButtonBgColor = label.getBackground(); + defaultButtonFgColor = label.getForeground(); label.setBorder(BorderFactory.createCompoundBorder(border2, border1)); label.setFont(new Font("Tahoma", Font.PLAIN, 11)); Dimension d = label.getPreferredSize(); - highlightButtonColor = new Color(244, 221, 183); rowHeight = d.height; this.setMinimumSize(new Dimension(0, 2 * rowHeight)); renderPane = new CellRendererPane(); @@ -130,6 +136,7 @@ public class FieldHeaderComp extends JPanel { /** * Returns the currently displayed model. + * @return the currently displayed model. */ public FieldFormatModel getModel() { return model; @@ -190,9 +197,6 @@ public class FieldHeaderComp extends JPanel { } } - /** - * Callback for when the mouse button is pressed. - */ private void pressed(int x, int y) { editInProgress = true; headerPanel.setTabLock(true); @@ -211,9 +215,6 @@ public class FieldHeaderComp extends JPanel { } } - /** - * Callback for when the mouse button is released. - */ private void released(int x, int y) { if (!editInProgress) { return; @@ -242,9 +243,6 @@ public class FieldHeaderComp extends JPanel { Swing.runLater(() -> headerPanel.setTabLock(false)); } - /** - * Callback for when the mouse is dragged. - */ private void dragged(int x, int y) { int deltaX = x - anchorX; int deltaY = y - anchorY; @@ -263,9 +261,6 @@ public class FieldHeaderComp extends JPanel { } } - /** - * Callback as the user is resizing a field. - */ private void resize(int deltaX) { int row = curRow; int col = edgeCol; @@ -283,7 +278,8 @@ public class FieldHeaderComp extends JPanel { /** * Returns the row in the model that the point is over. - * @param p the point for which to find its corresponding row. + * @param p the point for which to find its corresponding row + * @return the row */ public int getRow(Point p) { if (p.y < 0) { @@ -297,9 +293,16 @@ public class FieldHeaderComp extends JPanel { } /** + <<<<<<< Upstream, based on origin/master * Returns the index of the field on the given row containing the give x pos. * @param row the row on which to find the index of the field contianing the x coordinate. * @param x the horizontal coordinate (in pixels) + ======= + * Returns the index of the field on the given row containing the give x position. + * @param row the row on which to find the index of the field containing the x coordinate. + * @param x the horizontal coordinate (in pixels) + * @return the column + >>>>>>> 1c5bb47 GP-1981 - Theming - GColor migration fixes */ public int getCol(int row, int x) { if (x < 0) { @@ -326,7 +329,7 @@ public class FieldHeaderComp extends JPanel { @Override public void paint(Graphics g) { - g.setColor(buttonColor); + g.setColor(defaultButtonBgColor); int nRows = model.getNumRows(); Dimension dim = getSize(); g.fillRect(0, 0, dim.width, dim.height); @@ -344,10 +347,12 @@ public class FieldHeaderComp extends JPanel { label.setText(name); label.setEnabled(factorys[j].isEnabled()); if (factorys[j] == selectedFactory) { - label.setBackground(highlightButtonColor); + label.setBackground(ACTIVE_FIELD_BG_COLOR); + label.setForeground(ACTIVE_FIELD_FG_COLOR); } else { - label.setBackground(buttonColor); + label.setBackground(defaultButtonBgColor); + label.setForeground(defaultButtonFgColor); } renderPane.paintComponent(g, label, this, startX, startY, width, height, true); @@ -363,9 +368,6 @@ public class FieldHeaderComp extends JPanel { } - /** - * Returns the preferredSize for this header component. - */ @Override public Dimension getPreferredSize() { FormatManager formatManager = model.getFormatManager(); @@ -380,7 +382,8 @@ public class FieldHeaderComp extends JPanel { /** * Returns a FieldHeaderLocation for the given point - * @param p the point to get a location for. + * @param p the point to get a location for + * @return the location */ public FieldHeaderLocation getFieldHeaderLocation(Point p) { int row = getRow(p); @@ -419,9 +422,6 @@ public class FieldHeaderComp extends JPanel { int widthRightField; int widthLeftField; - /** - * Construct a Moving Field for the field at the given row and column. - */ MovingField(int row, int col) { baseRow = row; baseCol = col; @@ -434,17 +434,11 @@ public class FieldHeaderComp extends JPanel { } - /** - * Moves the floating field by the given deltas. - */ void moveFloating(int deltaX, int deltaY) { floatingX += deltaX; floatingY += deltaY; } - /** - * Moves the base field to a new position in the header. - */ void move() { if (((floatingY - y) > rowHeight / 2) && baseRow < 11) { // move down @@ -508,9 +502,6 @@ public class FieldHeaderComp extends JPanel { } - /** - * Returns the start position of the base field. - */ private int getStart() { int start = 0; FieldFactory[] factorys = model.getFactorys(baseRow); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java index fe7b5024ae..79937f2812 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java @@ -32,6 +32,7 @@ import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.listener.*; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexedScrollPane; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.codebrowser.LayeredColorModel; import ghidra.app.plugin.core.codebrowser.hover.ListingHoverService; import ghidra.app.services.ButtonPressedListener; @@ -349,7 +350,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc splitPaneDividerLocation = splitPane.getDividerLocation(); } JPanel resizeablePanel = new JPanel(new ScrollpanelResizeablePanelLayout(scroller)); - resizeablePanel.setBackground(Color.WHITE); + resizeablePanel.setBackground(Colors.BACKGROUND); resizeablePanel.add(resizeableMarginProvider.getComponent()); splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, resizeablePanel, scroller); splitPane.setDividerSize(4); diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 48719dae14..2a833581c8 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -6,6 +6,7 @@ ##MODULE IP: Tango Icons - Public Domain .gitignore||GHIDRA||||END| Module.manifest||GHIDRA||||END| +data/decompiler.theme.properties||GHIDRA||||END| src/decompile/.cproject||GHIDRA||||END| src/decompile/.project||GHIDRA||||END| src/decompile/cpp/.gitignore||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/data/decompiler.theme.properties b/Ghidra/Features/Decompiler/data/decompiler.theme.properties new file mode 100644 index 0000000000..c8ad3a1e92 --- /dev/null +++ b/Ghidra/Features/Decompiler/data/decompiler.theme.properties @@ -0,0 +1,7 @@ + +[Defaults] + + + +[Dark Defaults] + diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java index a37dadf9c6..dff0039508 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java @@ -37,6 +37,7 @@ import docking.widgets.fieldpanel.field.FieldElement; import docking.widgets.fieldpanel.listener.*; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexedScrollPane; +import generic.theme.GColor; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.hover.DecompilerHoverService; import ghidra.app.decompiler.component.margin.*; @@ -59,7 +60,7 @@ import ghidra.util.task.SwingUpdateManager; public class DecompilerPanel extends JPanel implements FieldMouseListener, FieldLocationListener, FieldSelectionListener, ClangHighlightListener, LayoutListener { - private final static Color NON_FUNCTION_BACKGROUND_COLOR_DEF = new Color(220, 220, 220); + private final static Color NON_FUNCTION_BACKGROUND_COLOR_DEF = new GColor("color.bg.undefined"); // Default color for specially highlighted tokens private final static Color SPECIAL_COLOR_DEF = new Color(255, 100, 0, 128); diff --git a/Ghidra/Framework/Docking/data/docking.theme.properties b/Ghidra/Framework/Docking/data/docking.theme.properties index 957f84b895..d44b21f117 100644 --- a/Ghidra/Framework/Docking/data/docking.theme.properties +++ b/Ghidra/Framework/Docking/data/docking.theme.properties @@ -9,6 +9,12 @@ color.bg.header.active = steelblue color.bg.header.inactive = rgb(150, 150, 150) color.fg.header.active = ivory color.fg.header.inactive = black +color.header.drag.cursor = black + +color.fg.dialog.status.alert = orange +color.fg.dialog.status.error = color.fg.error +color.fg.dialog.status.warning = orange +color.fg.dialog.status.normal = blue color.bg.selection = rgb(180, 255, 180) // pale green color.bg.highlight = rgb(255,255,150) // pale yellow @@ -85,13 +91,20 @@ icon.theme.export = images/mail-folder-outbox.png [Dark Defaults] -color.bg = rgb(40, 42, 46) +color.bg = #46494B // color used by flatlaf dark theme color.fg = lightgray -color.bg.header.active = steelblue // color.palette.material.primary // lightcoral +color.bg.header.active = #788CBD color.bg.header.inactive = dimGray color.fg.header.active = lightGray color.fg.header.inactive = black +color.header.drag.cursor = lightGray + +color.fg.dialog.status.alert = orange +color.fg.dialog.status.error = color.fg.error +color.fg.dialog.status.warning = orange +color.fg.dialog.status.normal = lightBlue + color.bg.currentline = rgb(60,60,70) // dark gray color.cursor.focused = indianRed diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 605fb3d1f7..95e974f915 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -32,6 +32,7 @@ import docking.event.mouse.GMouseListenerAdapter; import docking.menu.DialogToolbarButton; import docking.util.AnimationUtils; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GColor; import ghidra.util.*; import ghidra.util.exception.AssertException; import ghidra.util.task.*; @@ -45,7 +46,10 @@ import utility.function.Callback; public class DialogComponentProvider implements ActionContextProvider, StatusListener, TaskListener { - private static final Color WARNING_COLOR = new Color(0xff9900); + private static final Color FG_COLOR_ALERT = new GColor("color.fg.dialog.status.alert"); + private static final Color FG_COLOR_ERROR = new GColor("color.fg.dialog.status.error"); + private static final Color FG_COLOR_WARNING = new GColor("color.fg.dialog.status.warning"); + private static final Color FG_COLOR_NORMAL = new GColor("color.fg.dialog.status.normal"); private final static int DEFAULT_DELAY = 750; @@ -699,13 +703,13 @@ public class DialogComponentProvider protected Color getStatusColor(MessageType type) { switch (type) { case ALERT: - return Color.orange; + return FG_COLOR_ALERT; case WARNING: - return WARNING_COLOR; + return FG_COLOR_WARNING; case ERROR: - return Color.red; + return FG_COLOR_ERROR; default: - return Color.blue; + return FG_COLOR_NORMAL; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java b/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java index a5b03c1574..cf88ecc39c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java @@ -19,11 +19,20 @@ import java.awt.*; import java.awt.dnd.DragSource; import java.awt.image.BufferedImage; +import generic.theme.*; + /** * The cursor values used when drag-n-dropping dockable components */ public class HeaderCursor { + private static final GColor CURSOR_COLOR = new GColor("color.header.drag.cursor"); + private static final ThemeListener THEME_LISTENER = event -> { + if (event.isColorChanged(CURSOR_COLOR.getId())) { + initilizeCursors(); + } + }; + static Cursor LEFT; static Cursor RIGHT; static Cursor TOP; @@ -33,6 +42,12 @@ public class HeaderCursor { static Cursor NO_DROP = DragSource.DefaultMoveNoDrop; static { + initilizeCursors(); + + Gui.addThemeListener(THEME_LISTENER); + } + + private static void initilizeCursors() { Toolkit tk = Toolkit.getDefaultToolkit(); Image image = drawLeftArrow(); @@ -57,7 +72,7 @@ public class HeaderCursor { private static Image drawLeftArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int y = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -76,7 +91,7 @@ public class HeaderCursor { private static Image drawRightArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int y = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -95,7 +110,7 @@ public class HeaderCursor { private static Image drawTopArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int x = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -113,7 +128,7 @@ public class HeaderCursor { private static Image drawBottomArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int x = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -131,7 +146,7 @@ public class HeaderCursor { private static Image drawStack() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); for (int i = 0; i < 3; i++) { int x = i * 3; int y = 6 - i * 3; @@ -149,10 +164,11 @@ public class HeaderCursor { private static Image drawNewWindow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int headerColor = new GColor("color.bg.header.active").getRGB(); + int v = CURSOR_COLOR.getRGB(); for (int i = 0; i < 5; i++) { for (int j = 0; j < 14; j++) { - image.setRGB(j, i, 0xff0000ff); + image.setRGB(j, i, headerColor); } } for (int i = 0; i < 14; i++) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java index 1e095352bd..9a3d9cea87 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java @@ -22,6 +22,8 @@ import java.awt.event.MouseMotionAdapter; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import generic.theme.GColor; + public class SplitPanel extends JPanel { private static int DIVIDER_SIZE = 4; private Component leftComp; @@ -38,7 +40,7 @@ public class SplitPanel extends JPanel { this.rightComp = rightComp; this.isHorizontal = isHorizontal; divider = new Divider(); - divider.setBackground(Color.LIGHT_GRAY); + divider.setBackground(new GColor("SplitPane.background")); add(leftComp); add(divider); add(rightComp); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/help/GHelpHTMLEditorKit.java b/Ghidra/Framework/Docking/src/main/java/docking/help/GHelpHTMLEditorKit.java new file mode 100644 index 0000000000..3207feb7f7 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/help/GHelpHTMLEditorKit.java @@ -0,0 +1,536 @@ +/* ### + * 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.help; + +import java.awt.Desktop; +import java.awt.Image; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.*; +import java.net.*; +import java.util.Collection; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JEditorPane; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.*; +import javax.swing.text.html.*; +import javax.swing.text.html.HTML.Tag; + +import generic.jar.ResourceFile; +import ghidra.framework.Application; +import ghidra.framework.preferences.Preferences; +import ghidra.util.Msg; +import resources.*; +import utilities.util.FileUtilities; + +/** + * A class that allows Ghidra to intercept JavaHelp navigation events in order to resolve them + * to Ghidra's help system. Without this class, contribution plugins have no way of + * referencing help documents within Ghidra's default help location. + *

+ * This class is currently installed by the {@link GHelpSet}. + * + * @see GHelpSet + */ +public class GHelpHTMLEditorKit extends HTMLEditorKit { + + private static final String G_HELP_STYLE_SHEET = "help/shared/Frontpage.css"; + + private static final Pattern EXTERNAL_URL_PATTERN = Pattern.compile("https?://.*"); + + /** A pattern to strip the font size value from a line of CSS */ + private static final Pattern FONT_SIZE_PATTERN = Pattern.compile("font-size:\\s*(\\d{1,2})"); + private static final String HELP_WINDOW_ZOOM_FACTOR = "HELP.WINDOW.FONT.SIZE.MODIFIER"; + private static int fontSizeModifier; + + private HyperlinkListener[] delegateListeners = null; + private HyperlinkListener resolverHyperlinkListener; + + public GHelpHTMLEditorKit() { + fontSizeModifier = + Integer.valueOf(Preferences.getProperty(HELP_WINDOW_ZOOM_FACTOR, "0", true)); + } + + @Override + public ViewFactory getViewFactory() { + return new GHelpHTMLFactory(); + } + + @Override + public void install(JEditorPane c) { + super.install(c); + + delegateListeners = c.getHyperlinkListeners(); + for (HyperlinkListener listener : delegateListeners) { + c.removeHyperlinkListener(listener); + } + + resolverHyperlinkListener = new ResolverHyperlinkListener(); + c.addHyperlinkListener(resolverHyperlinkListener); + + // add a listener to report trace information + c.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String propertyName = evt.getPropertyName(); + if ("page".equals(propertyName)) { + Msg.trace(this, "Page loaded: " + evt.getNewValue()); + } + } + }); + } + + @Override + public void deinstall(JEditorPane c) { + + c.removeHyperlinkListener(resolverHyperlinkListener); + + for (HyperlinkListener listener : delegateListeners) { + c.addHyperlinkListener(listener); + } + + super.deinstall(c); + } + + private class ResolverHyperlinkListener implements HyperlinkListener { + @Override + public void hyperlinkUpdate(HyperlinkEvent e) { + + if (delegateListeners == null) { + return; + } + + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + if (isExternalLink(e)) { + browseExternalLink(e); + return; + } + Msg.trace(this, "Link activated: " + e.getURL()); + e = validateURL(e); + Msg.trace(this, "Validated event: " + e.getURL()); + } + + for (HyperlinkListener listener : delegateListeners) { + listener.hyperlinkUpdate(e); + } + } + } + + private boolean isExternalLink(HyperlinkEvent e) { + String description = e.getDescription(); + return description != null && EXTERNAL_URL_PATTERN.matcher(description).matches(); + } + + private void browseExternalLink(HyperlinkEvent e) { + String description = e.getDescription(); + if (!Desktop.isDesktopSupported()) { + Msg.info(this, "Unable to launch external browser for " + description); + return; + } + + try { + // use an external browser + URI uri = e.getURL().toURI(); + Desktop.getDesktop().browse(uri); + } + catch (URISyntaxException | IOException e1) { + Msg.error(this, "Error browsing to external URL " + description, e1); + } + } + + /** + * Tests the URL of the given event. If the URL is invalid, a new event may be created if + * a new, valid URL can be created. Creates a new event with a patched URL if + * the given event's URL is invalid. + */ + private HyperlinkEvent validateURL(HyperlinkEvent event) { + URL url = event.getURL(); + try { + url.openStream();// assume that this will fail if the file does not exist + } + catch (IOException ioe) { + // assume this means that the url is invalid + Msg.trace(this, "URL of link is invalid: " + url.toExternalForm()); + return maybeCreateNewHyperlinkEventWithUpdatedURL(event); + } + + return event;// url is fine + } + + /** Generates a new event with a URL based upon Ghidra's resources if needed. */ + private HyperlinkEvent maybeCreateNewHyperlinkEventWithUpdatedURL(HyperlinkEvent event) { + Element element = event.getSourceElement(); + if (element == null) { + return event;// this shouldn't happen since we were triggered from an A tag + } + + AttributeSet a = element.getAttributes(); + AttributeSet anchor = (AttributeSet) a.getAttribute(HTML.Tag.A); + if (anchor == null) { + return event;// this shouldn't happen since we were triggered from an A tag + } + + String HREF = (String) anchor.getAttribute(HTML.Attribute.HREF); + Msg.trace(this, "HREF of tag: " + HREF); + URL newUrl = getURLForHREFFromResources(HREF); + if (newUrl == null) { + return event;// unable to locate a resource by the name--bad link! + } + + return new HyperlinkEvent(event.getSource(), event.getEventType(), newUrl, + event.getDescription(), event.getSourceElement()); + } + + private URL getURLForHREFFromResources(String originalHREF) { + int anchorIndex = originalHREF.indexOf("#"); + String HREF = originalHREF; + String anchor = null; + if (anchorIndex != -1) { + HREF = HREF.substring(0, anchorIndex); + anchor = originalHREF.substring(anchorIndex); + } + + // look for a URL using an installation environment setup... + URL newUrl = ResourceManager.getResource(HREF); + if (newUrl != null) { + return createURLWithAnchor(newUrl, anchor); + } + + // + // The item was not found by the ResourceManager (i.e., it is not in a 'resources' + // directory). See if it may be a relative link to a build's installation root (like + // a file in /docs). + // + newUrl = findApplicationfile(HREF); + return newUrl; + } + + private URL createURLWithAnchor(URL anchorlessURL, String anchor) { + if (anchorlessURL == null) { + return anchorlessURL; + } + + if (anchor == null) { + // nothing to do + return anchorlessURL; + } + + try { + // put the anchor back into the URL + return new URL(anchorlessURL, anchor); + } + catch (MalformedURLException e) { + // shouldn't happen, since the file exists + Msg.showError(this, null, "Unexpected Error", + "Unexpected error creating a valid URL: " + anchorlessURL + "#" + anchor); + return null; + } + } + + @Override + public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException { + + super.read(in, doc, pos); + + HTMLDocument htmlDoc = (HTMLDocument) doc; + loadGHelpStyleSheet(htmlDoc); + } + + private void loadGHelpStyleSheet(HTMLDocument doc) { + + Reader reader = getGStyleSheetReader(); + if (reader == null) { + return; + } + + StyleSheet ss = doc.getStyleSheet(); + try { + ss.loadRules(reader, null); + } + catch (IOException e) { + // shouldn't happen + Msg.debug(this, "Unable to load help style sheet"); + } + } + + private Reader getGStyleSheetReader() { + URL url = getGStyleSheetURL(); + if (url == null) { + return null; + } + + StringBuffer buffy = new StringBuffer(); + try { + List lines = FileUtilities.getLines(url); + for (String line : lines) { + changePixels(line, fontSizeModifier, buffy); + buffy.append('\n'); + } + } + catch (IOException e) { + // shouldn't happen + Msg.debug(this, "Unable to read the lines of the help style sheet: " + url); + } + + StringReader reader = new StringReader(buffy.toString()); + return reader; + } + + private void changePixels(String line, int amount, StringBuffer buffy) { + + Matcher matcher = FONT_SIZE_PATTERN.matcher(line); + while (matcher.find()) { + String oldFontSize = matcher.group(1); + String adjustFontSize = adjustFontSize(oldFontSize); + matcher.appendReplacement(buffy, "font-size: " + adjustFontSize); + } + + matcher.appendTail(buffy); + } + + private String adjustFontSize(String sizeString) { + try { + int size = Integer.parseInt(sizeString); + String adjusted = Integer.toString(size + fontSizeModifier); + return adjusted; + } + catch (NumberFormatException e) { + Msg.debug(this, "Unable to parse font size string '" + sizeString + "'"); + } + return sizeString; + } + + private URL getGStyleSheetURL() { + URL GStyleSheetURL = ResourceManager.getResource(G_HELP_STYLE_SHEET); + if (GStyleSheetURL != null) { + return GStyleSheetURL; + } + + return findModuleFile("help/shared/FrontPage.css"); + } + + private URL findApplicationfile(String relativePath) { + ResourceFile installDir = Application.getInstallationDirectory(); + ResourceFile file = new ResourceFile(installDir, relativePath); + if (file.exists()) { + try { + return file.toURL(); + } + catch (MalformedURLException e) { + Msg.showError(this, null, "Unexpected Error", + "Unexpected error parsing file to URL: " + file); + } + } + return null; + } + + private URL findModuleFile(String relativePath) { + Collection moduleDirs = Application.getModuleRootDirectories(); + for (ResourceFile dir : moduleDirs) { + ResourceFile file = new ResourceFile(dir, relativePath); + if (file.exists()) { + try { + return file.toURL(); + } + catch (MalformedURLException e) { + Msg.showError(this, null, "Unexpected Error", + "Unexpected error parsing file to URL: " + file); + return null; + } + } + } + return null; + } + + public static void zoomOut() { + fontSizeModifier -= 2; + saveZoomFactor(); + } + + public static void zoomIn() { + fontSizeModifier += 2; + saveZoomFactor(); + } + + private static void saveZoomFactor() { + Preferences.setProperty(HELP_WINDOW_ZOOM_FACTOR, Integer.toString(fontSizeModifier)); + Preferences.store(); + } + +//================================================================================================== +// Inner Classes +//================================================================================================== + + private class GHelpHTMLFactory extends HTMLFactory { + @Override + public View create(Element e) { + + AttributeSet attributes = e.getAttributes(); + Object elementName = attributes.getAttribute(AbstractDocument.ElementNameAttribute); + if (elementName != null) { + // not an HTML element + return super.create(e); + } + + Object html = attributes.getAttribute(StyleConstants.NameAttribute); + if (html instanceof HTML.Tag) { + HTML.Tag tag = (Tag) html; + if (tag == HTML.Tag.IMG) { + return new GHelpImageView(e); + } + } + + return super.create(e); + } + + } + + /** + * Overridden to allow us to find images that are defined as constants in places like + * {@link Icons} + */ + private class GHelpImageView extends ImageView { + + /* + * Unusual Code Alert! + * This class exists to enable our help system to find custom icons defined in source + * code. The default behavior herein is to supply a URL to the base class to load. This + * works fine. + * + * There is another use case where we wish to have the base class load an image of our + * choosing. Why? Well, we modify, in memory, some icons we use. We do this for things + * like overlays and rotations. + * + * In order to have our base class use the image that we want (and not the one + * it loads via a URL), we have to play a small game. We have to allow the base class + * to load the image it wants, which is done asynchronously. If we install our custom + * image during that process, the loading will throw away the image and not render + * anything. + * + * To get the base class to use our image, we override getImage(). However, we should + * only return our image when the base class is finished loading. (See the base class' + * paint() method for why we need to do this.) + * + * Note: if we start seeing unusual behavior, like images not rendering, or any size + * issues, then we can revert this code. + */ + private Image image; + private float spanX; + private float spanY; + + public GHelpImageView(Element elem) { + super(elem); + } + + @Override + public Image getImage() { + Image superImage = super.getImage(); + if (image == null) { + // no custom image + return superImage; + } + + if (isLoading()) { + return superImage; + } + + return image; + } + + private boolean isLoading() { + return spanX < 1 || spanY < 1; + } + + @Override + public float getPreferredSpan(int axis) { + float span = super.getPreferredSpan(axis); + if (axis == View.X_AXIS) { + spanX = span; + } + else { + spanY = span; + } + return span; + } + + @Override + public URL getImageURL() { + + AttributeSet attributes = getElement().getAttributes(); + Object src = attributes.getAttribute(HTML.Attribute.SRC); + if (src == null) { + return null; + } + + String srcString = src.toString(); + if (isJavaCode(srcString)) { + return installImageFromJavaCode(srcString); + } + + URL url = doGetImageURL(srcString); + return url; + } + + private URL installImageFromJavaCode(String srcString) { + + IconProvider iconProvider = getIconFromJavaCode(srcString); + if (iconProvider == null || iconProvider.isInvalid()) { + return null; + } + + this.image = iconProvider.getImage(); + + URL url = iconProvider.getOrCreateUrl(); + return url; + } + + private URL doGetImageURL(String srcString) { + + HTMLDocument htmlDocument = (HTMLDocument) getDocument(); + URL context = htmlDocument.getBase(); + try { + URL url = new URL(context, srcString); + if (FileUtilities.exists(url.toURI())) { + // it's a good one, let it through + return url; + } + } + catch (MalformedURLException | URISyntaxException e) { + // check below + } + + // Try the ResourceManager. This will work for images that start with GHelp + // relative link syntax such as 'help/', 'help/topics/' and 'images/' + URL resource = ResourceManager.getResource(srcString); + return resource; + } + + private boolean isJavaCode(String src) { + // not sure of the best way to handle this--be exact for now + return Icons.isIconsReference(src); + } + + private IconProvider getIconFromJavaCode(String src) { + return Icons.getIconForIconsReference(src); + } + + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java index a1c1723da5..2f6f77bb51 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java @@ -16,8 +16,6 @@ package docking.widgets; import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.List; import java.util.function.Function; @@ -44,13 +42,13 @@ public class SelectFromListDialog extends DialogComponentProvider { * @param list list of object of type T * @param title title of dialog * @param prompt prompt shown above list - * @param toStringFunc func that converts a T into a String. + * @param toStringFunction function that converts a T into a String. * @return the chosen T object, or null if dialog canceled. */ public static T selectFromList(List list, String title, String prompt, - Function toStringFunc) { + Function toStringFunction) { SelectFromListDialog dialog = - new SelectFromListDialog<>(title, prompt, list, toStringFunc); + new SelectFromListDialog<>(title, prompt, list, toStringFunction); SystemUtilities.runSwingNow(() -> dialog.doSelect()); return dialog.actionComplete ? dialog.getSelectedObject() : null; } @@ -123,12 +121,7 @@ public class SelectFromListDialog extends DialogComponentProvider { listPanel.setListModel(listModel); listPanel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); listPanel.setSelectedIndex(0); - listPanel.setDoubleClickActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - okCallback(); - } - }); + listPanel.setDoubleClickActionListener(e -> okCallback()); JPanel workPanel = new JPanel(new BorderLayout()); MultiLineLabel mll = new MultiLineLabel("\n" + prompt + ":"); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java index d4a79ab86e..3e0735d353 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java @@ -56,10 +56,9 @@ public class ListPanel extends JPanel { scrollpane = new JScrollPane(list); - // the next two lines of code cause the scroll bar not to - // work properly - //list.setBorder(emptyborder); - //scrollpane.setBorder(compoundborder); + // the next two lines of code cause the scroll bar not to work properly + // list.setBorder(emptyborder); + // scrollpane.setBorder(compoundborder); add(scrollpane, BorderLayout.CENTER); @@ -108,14 +107,15 @@ public class ListPanel extends JPanel { /** * Returns true if no list items are selected. + * @return true if no list items are selected. */ public boolean isSelectionEmpty() { return list.isSelectionEmpty(); } /** - * Returns the first selected value in the list or null if nothing - * is selected. + * Returns the first selected value in the list or null if nothing is selected. + * @return the first selected value in the list or null if nothing is selected. */ public Object getSelectedValue() { return list.getSelectedValue(); @@ -123,6 +123,7 @@ public class ListPanel extends JPanel { /** * Get the index of the selected item in the list. + * @return the index of the selected item in the list. */ public int getSelectedIndex() { return list.getSelectedIndex(); @@ -146,6 +147,7 @@ public class ListPanel extends JPanel { /** * Returns an array of all the selected items. + * @return an array of all the selected items. */ public Object[] getSelectedValues() { return list.getSelectedValues(); @@ -160,12 +162,16 @@ public class ListPanel extends JPanel { list.clearSelection(); } + /** + * Sets the list data + * @param data the data + */ public void setListData(Object[] data) { list.setListData(data); } /** - * Sets a ListModel for the internal Jlist to use. + * Sets a list model for the internal list to use. * @param listModel the list model to use. */ public void setListModel(ListModel listModel) { @@ -175,6 +181,7 @@ public class ListPanel extends JPanel { /** * Get the list model for the list. + * @return the list model for the list. */ public ListModel getListModel() { return (list.getModel()); @@ -182,6 +189,7 @@ public class ListPanel extends JPanel { /** * Return the JList component. + * @return the JList component. */ public JList getList() { return list; @@ -201,10 +209,12 @@ public class ListPanel extends JPanel { * means no one is to be notified. */ public void setListSelectionListener(ListSelectionListener listener) { - if (listSelectionListener != null) + if (listSelectionListener != null) { list.removeListSelectionListener(listSelectionListener); - if (listener != null) + } + if (listener != null) { list.addListSelectionListener(listener); + } listSelectionListener = listener; } @@ -236,7 +246,8 @@ public class ListPanel extends JPanel { * in the list. */ public void issueWarning() { - JOptionPane.showMessageDialog(null, DEFAULT_WARNING, "Warning", JOptionPane.WARNING_MESSAGE); + JOptionPane.showMessageDialog(null, DEFAULT_WARNING, "Warning", + JOptionPane.WARNING_MESSAGE); } /** diff --git a/Ghidra/Framework/Docking/src/main/java/resources/Icons.java b/Ghidra/Framework/Docking/src/main/java/resources/Icons.java index 1e9ef7ab76..3aee5c6f0a 100644 --- a/Ghidra/Framework/Docking/src/main/java/resources/Icons.java +++ b/Ghidra/Framework/Docking/src/main/java/resources/Icons.java @@ -17,7 +17,6 @@ package resources; import java.awt.*; import java.lang.reflect.Field; -import java.net.MalformedURLException; import java.net.URL; import javax.swing.Icon; @@ -112,7 +111,7 @@ public class Icons { return null; } - ImageIcon icon = getIconByFieldName(fieldName); + GIcon icon = getIconByFieldName(fieldName); if (icon == null) { return null; } @@ -137,7 +136,7 @@ public class Icons { } /** - * Gets the icon for the given icon path and scale it to the specifed width and height. + * Gets the icon for the given icon path and scale it to the specified width and height. * The given path should be relative to the classpath. * If an icon by that name can't be found, the default "bomb" icon is returned instead. *

@@ -164,11 +163,12 @@ public class Icons { return fieldName; } - private static ImageIcon getIconByFieldName(String fieldName) { + private static GIcon getIconByFieldName(String fieldName) { try { Field field = Icons.class.getField(fieldName); - ImageIcon icon = (ImageIcon) field.get(Icons.class); + Object object = field.get(Icons.class); + GIcon icon = (GIcon) object; return icon; } catch (Exception e) { @@ -178,27 +178,17 @@ public class Icons { } } - private static URL getUrlFromIcon(ImageIcon icon) { + private static URL getUrlFromIcon(GIcon icon) { if (icon == null) { return null; } - // Note: we embed the icon's URL in its description - String description = icon.getDescription(); - if (description == null) { - Msg.debug(Icons.class, "Unable to get URL for icon - icon description is missing"); - return null; - } - - try { - URL url = new URL(description); + URL url = icon.getUrl(); + if (url != null) { return url; } - catch (MalformedURLException e) { - Msg.trace(Icons.class, "Unable to get URL for icon: " + description); - return null; - } - + Msg.debug(Icons.class, "Unable to get URL for icon"); + return null; } // Creates a 16x16 icon with a scaled base icon and puts 3 dots below it. diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java index 1bfc79a18d..6460683f46 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java @@ -17,10 +17,14 @@ package generic.theme; import java.awt.Component; import java.awt.Graphics; +import java.net.URL; import javax.swing.Icon; +import javax.swing.ImageIcon; import ghidra.util.datastruct.WeakStore; +import resources.ResourceManager; +import resources.icons.UrlImageIcon; /** * An {@link Icon} whose value is dynamically determined by looking up its id into a global @@ -79,6 +83,26 @@ public class GIcon implements Icon { return id; } + /** + * Returns the url used to load the icon delegate of this class. If the delegate icon was not + * loaded from a url, then null will be returned. + * @return the icon or null + */ + public URL getUrl() { + if (delegate instanceof UrlImageIcon) { + return ((UrlImageIcon) delegate).getUrl(); + } + return null; + } + + /** + * Returns the image for this icon. + * @return the image + */ + public ImageIcon getImageIcon() { + return ResourceManager.getImageIcon(delegate); + } + @Override public void paintIcon(Component c, Graphics g, int x, int y) { delegate.paintIcon(c, g, x, y); diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java index d80148bf26..2591a65444 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java @@ -241,7 +241,6 @@ public class GTheme extends GThemeValueMap { * @param outputFile the file to save to * @param includeDefaults if true, write all values to the theme file including default values. * Otherwise, just values that are not the default values are written to the file. - * @return a new FileGTheme that represents the new file/theme * @throws IOException if an I/O error occurs writing the theme file */ public void saveToZip(File outputFile, boolean includeDefaults) throws IOException { diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java index 085fac5389..35abb524ce 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java @@ -520,7 +520,7 @@ public class Gui { if (color == null) { if (validate && isInitialized) { Throwable t = getFilteredTrace(); - Msg.error(Gui.class, "No color value registered for: " + id, t); + Msg.error(Gui.class, "No color value registered for: '" + id + "'", t); } return Color.CYAN; } @@ -538,7 +538,7 @@ public class Gui { if (icon == null) { if (validate && isInitialized) { Throwable t = getFilteredTrace(); - Msg.error(Gui.class, "No icon value registered for: " + id, t); + Msg.error(Gui.class, "No icon value registered for: '" + id + "'", t); } return ResourceManager.getDefaultIcon(); } diff --git a/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java b/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java index 8198341755..e47046c6b9 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java @@ -15,6 +15,7 @@ */ package resources; +import java.awt.Image; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; @@ -23,6 +24,7 @@ import java.net.URL; import javax.swing.ImageIcon; import generic.Images; +import generic.theme.GIcon; import generic.util.image.ImageUtils; import ghidra.util.Msg; @@ -35,18 +37,18 @@ import ghidra.util.Msg; */ public class IconProvider { - private ImageIcon icon; + private GIcon icon; private URL url; private URL tempUrl; private boolean tempFileFailed; - public IconProvider(ImageIcon icon, URL url) { + public IconProvider(GIcon icon, URL url) { this.icon = icon; this.url = url; } - public ImageIcon getIcon() { - return icon; + public Image getImage() { + return icon.getImageIcon().getImage(); } public boolean isInvalid() { @@ -94,7 +96,8 @@ public class IconProvider { try { File imageFile = File.createTempFile("temp.help.icon", null); imageFile.deleteOnExit(); // don't let this linger - ImageUtils.writeFile(icon.getImage(), imageFile); + ImageIcon imageIcon = icon.getImageIcon(); + ImageUtils.writeFile(imageIcon.getImage(), imageFile); return imageFile.toURI().toURL(); } catch (IOException e) { diff --git a/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java b/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java index cec8a034fe..954be29ac8 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java @@ -31,6 +31,7 @@ import javax.swing.*; import org.apache.commons.lang3.StringUtils; import generic.Images; +import generic.theme.GIcon; import ghidra.framework.Application; import ghidra.util.Msg; import ghidra.util.SystemUtilities; @@ -397,6 +398,9 @@ public class ResourceManager { if (icon instanceof ImageIcon) { return (ImageIcon) icon; } + if (icon instanceof GIcon) { + return ((GIcon) icon).getImageIcon(); + } return new DerivedImageIcon(icon); } @@ -416,6 +420,9 @@ public class ResourceManager { if (icon instanceof ImageIcon) { iconName = ((ImageIcon) icon).getDescription(); } + if (icon instanceof GIcon) { + return ((GIcon) icon).getId(); + } /* TODO - not sure why we wanted just the name and not the entire URL? Delete this diff --git a/Ghidra/Framework/Project/data/project.theme.properties b/Ghidra/Framework/Project/data/project.theme.properties index 5f8dcc4907..64fe54603e 100644 --- a/Ghidra/Framework/Project/data/project.theme.properties +++ b/Ghidra/Framework/Project/data/project.theme.properties @@ -18,6 +18,9 @@ color.fg.pluginpanel.details.novalue = lightGray color.border.pluginpanel = darkGray +color.fg.plugin.installer.table.has.dependents = red +color.fg.plugin.installer.table.has.dependents.selected = pink + [Dark Defaults] color.fg.pluginpanel.details.title = indianRed color.fg.pluginpanel.details.name.no-dependents = forestGreen @@ -30,5 +33,19 @@ color.fg.pluginpanel.details.developer =mediumVioletRed color.fg.pluginpanel.details.dependency = forestGreen color.fg.pluginpanel.details.novalue = dimGray -color.fg.pluginpanel.name = lightGray -color.fg.pluginpanel.description = Gray +color.fg.pluginpanel.name = #d3d3d3 // LightGray +color.fg.pluginpanel.description = #808080 // Gray + +color.fg.pluginpanel.details.category = #d361d3 +color.fg.pluginpanel.details.class = #808080 // Gray +color.fg.pluginpanel.details.dependency = #228b22 // ForestGreen +color.fg.pluginpanel.details.description = #aaaaff +color.fg.pluginpanel.details.developer = #c71585 // MediumVioletRed +color.fg.pluginpanel.details.loc = #a9a9a9 // DarkGray +color.fg.pluginpanel.details.name.has-dependents = #cd939f +color.fg.pluginpanel.details.name.no-dependents = #66ff66 +color.fg.pluginpanel.details.novalue = #999900 +color.fg.pluginpanel.details.title = #cd939f + +color.fg.plugin.installer.table.has.dependents = #FF66FF +color.fg.plugin.installer.table.has.dependents.selected = #FF99CC \ No newline at end of file diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectDataPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectDataPanel.java index 6c6b795d3b..7606c410e1 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectDataPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ProjectDataPanel.java @@ -76,8 +76,17 @@ class ProjectDataPanel extends JSplitPane { projectTab.addTab("Tree View", activePanel); projectTab.addTab("Table View", tablePanel); - // setup the active data tree panel - this.add(projectTab, JSplitPane.LEFT); + + // + // Setup the active data tree panel + // + // Use a panel for the left side of the split pane so the split pane background does not + // shine through. This allows users to change the split pane background to change the + // divider color without affecting the background of the front end. + // + JPanel leftPanel = new JPanel(new BorderLayout()); + leftPanel.add(projectTab); + this.add(leftPanel, JSplitPane.LEFT); projectTab.setBorder(BorderFactory.createTitledBorder(BORDER_PREFIX)); // initialize the read-only project view tabbed pane diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java index da43ed0367..b6241928c4 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/SaveDataDialog.java @@ -16,8 +16,8 @@ package ghidra.framework.main; import java.awt.*; -import java.awt.event.*; -import java.lang.reflect.InvocationTargetException; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; @@ -28,11 +28,11 @@ import docking.DialogComponentProvider; import docking.options.editor.ButtonPanelFactory; import docking.widgets.checkbox.GCheckBox; import docking.widgets.list.ListPanel; +import generic.theme.GThemeDefaults.Colors; import ghidra.framework.model.DomainFile; import ghidra.framework.model.ProjectLocator; import ghidra.framework.plugintool.PluginTool; -import ghidra.util.HelpLocation; -import ghidra.util.Msg; +import ghidra.util.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.*; @@ -80,20 +80,12 @@ public class SaveDataDialog extends DialogComponentProvider { yesButton = new JButton("Save"); yesButton.setMnemonic('S'); addButton(yesButton); - yesButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - okCallback(); - } - }); + yesButton.addActionListener(evt -> okCallback()); noButton = new JButton("Don't Save"); noButton.setMnemonic('n'); - noButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - operationCompleted = true; - close(); - } + noButton.addActionListener(evt -> { + operationCompleted = true; + close(); }); addButton(noButton); addCancelButton(); @@ -178,7 +170,7 @@ public class SaveDataDialog extends DialogComponentProvider { deselectAllButton = new JButton(DESELECT_ALL); deselectAllButton.setMnemonic('N'); - JPanel buttonPanel = ButtonPanelFactory.createButtonPanel( + JPanel myButtonPanel = ButtonPanelFactory.createButtonPanel( new JButton[] { selectAllButton, deselectAllButton }); // @@ -189,7 +181,7 @@ public class SaveDataDialog extends DialogComponentProvider { listPanel.setMouseListener(new ListMouseListener()); // Layout Main Panel - parentPanel.add(buttonPanel, BorderLayout.EAST); + parentPanel.add(myButtonPanel, BorderLayout.EAST); parentPanel.add(listPanel, BorderLayout.CENTER); parentPanel.setBorder(new TitledBorder("Data")); @@ -201,19 +193,9 @@ public class SaveDataDialog extends DialogComponentProvider { * Add listeners to the buttons. */ private void addListeners() { - selectAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - selectAll(); - } - }); + selectAllButton.addActionListener(e -> selectAll()); - deselectAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - deselectAll(); - } - }); + deselectAllButton.addActionListener(e -> deselectAll()); } @@ -265,7 +247,7 @@ public class SaveDataDialog extends DialogComponentProvider { yesButton.setEnabled(false); for (int i = 0; i < files.size(); i++) { checkboxes[i] = new GCheckBox(files.get(i).getName()); - checkboxes[i].setBackground(Color.white); + checkboxes[i].setBackground(Colors.BACKGROUND); saveable[i] = files.get(i).canSave(); if (!saveable[i]) { String text = files.get(i).getName() + readOnlyString; @@ -285,10 +267,9 @@ public class SaveDataDialog extends DialogComponentProvider { } listPanel.refreshList(checkboxes); - setFocusComponent(yesButton);//.requestFocusInWindow(); + setFocusComponent(yesButton); } - ///////////////////////////////////////////////////////////////////////// /** * Cell renderer to show the checkboxes for the changed data files. */ @@ -307,7 +288,7 @@ public class SaveDataDialog extends DialogComponentProvider { // set color to red if file cannot be saved 'as is' if (!saveable[index]) { - checkboxes[index].setForeground(Color.red); + checkboxes[index].setForeground(Colors.ERROR); checkboxes[index].setFont(boldFont); } return checkboxes[index]; @@ -340,10 +321,6 @@ public class SaveDataDialog extends DialogComponentProvider { } } - ///////////////////////////////////////////////////////////////////////// - /** - * Task to save files. - */ private class SaveTask extends Task { private DomainFile[] domainFiles; @@ -352,9 +329,6 @@ public class SaveDataDialog extends DialogComponentProvider { this.domainFiles = files; } - /** - * @see ghidra.util.task.Task#run(TaskMonitor) - */ @Override public void run(TaskMonitor monitor) { try { @@ -377,42 +351,12 @@ public class SaveDataDialog extends DialogComponentProvider { t); } if (operationCompleted) { - try { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - close(); - } - }); - } - catch (InterruptedException e) { - // don't care? - } - catch (InvocationTargetException e) { - // don't care? - } + Swing.runNow(() -> close()); } else if (monitor.isCancelled()) { - updateList(); + Swing.runNow(() -> initList()); } } - /** - * Refresh the list of files that need saving. - */ - private void updateList() { - Runnable r = new Runnable() { - @Override - public void run() { - initList(); - } - }; - try { - SwingUtilities.invokeAndWait(r); - } - catch (Exception e) { - // don't care? - } - } } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DomainFilesPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DomainFilesPanel.java index 897eaaffac..a0022472a1 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DomainFilesPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DomainFilesPanel.java @@ -25,6 +25,7 @@ import javax.swing.*; import docking.widgets.checkbox.GCheckBox; import docking.widgets.list.ListPanel; +import generic.theme.GThemeDefaults.Colors; import ghidra.framework.model.DomainFile; /** @@ -52,7 +53,7 @@ class DomainFilesPanel extends JPanel { for (int i = 0; i < fileList.size(); i++) { DomainFile df = fileList.get(i); checkboxes[i] = new GCheckBox(df.getPathname(), true); - checkboxes[i].setBackground(Color.white); + checkboxes[i].setBackground(Colors.BACKGROUND); } // diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginInstallerDialog.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginInstallerDialog.java index 2847172ba2..07dd42def6 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginInstallerDialog.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/PluginInstallerDialog.java @@ -23,6 +23,7 @@ import javax.swing.table.TableColumn; import docking.DialogComponentProvider; import docking.widgets.table.*; +import generic.theme.GColor; import ghidra.app.util.GenericHelpTopics; import ghidra.framework.plugintool.PluginConfigurationModel; import ghidra.framework.plugintool.PluginTool; @@ -38,6 +39,11 @@ import help.HelpService; */ public class PluginInstallerDialog extends DialogComponentProvider { + private static final Color FG_COLOR_HAS_DEPENDENTS = + new GColor("color.fg.plugin.installer.table.has.dependents"); + private static final Color FG_COLOR_HAS_DEPENDENTS_SELECTED = + new GColor("color.fg.plugin.installer.table.has.dependents.selected"); + private PluginTool tool; private PluginConfigurationModel model; private List pluginDescriptions; @@ -253,7 +259,7 @@ public class PluginInstallerDialog extends DialogComponentProvider { if (isSelected) { if (hasDependents) { - renderer.setForeground(Color.pink); + renderer.setForeground(FG_COLOR_HAS_DEPENDENTS_SELECTED); renderer.setFont(boldFont); } else { @@ -264,7 +270,7 @@ public class PluginInstallerDialog extends DialogComponentProvider { else { // set color to red if other plugins depend on this plugin if (hasDependents) { - renderer.setForeground(Color.red); + renderer.setForeground(FG_COLOR_HAS_DEPENDENTS); renderer.setFont(boldFont); } else { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java index cc5c998b2a..19c75a6485 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java @@ -144,6 +144,7 @@ public class GProgressBar extends JPanel { * By default, this property is false. * Some look and feels might not support indeterminate progress bars; * they will ignore this property. + * @param indeterminate true if indeterminate * * @see JProgressBar */ @@ -157,6 +158,7 @@ public class GProgressBar extends JPanel { /** * Show or not show the progress icon (spinning globe) according to * the showIcon param. + * @param showIcon true to show the icon */ public void showProgressIcon(final boolean showIcon) { if (showIcon == showingIcon) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/taskview/ScheduledTaskPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/taskview/ScheduledTaskPanel.java index bd952f9101..d99660a98d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/taskview/ScheduledTaskPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/taskview/ScheduledTaskPanel.java @@ -20,6 +20,7 @@ import java.awt.*; import javax.swing.*; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors; import ghidra.framework.task.gui.GProgressBar; public class ScheduledTaskPanel extends JPanel { @@ -38,13 +39,13 @@ public class ScheduledTaskPanel extends JPanel { layout = new ScheduledElementLayout(); setLayout(layout); label = new GDLabel(labelText); - setBackground(Color.WHITE); + setBackground(Colors.BACKGROUND); add(label); } void addProgressBar() { progressBar = new GProgressBar(null, true, true, false, 12); - progressBar.setBackgroundColor(Color.WHITE); + progressBar.setBackgroundColor(Colors.BACKGROUND); add(progressBar); layout.clearPreferredSize(); invalidate();