diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/CustomToStringCellRenderer.java b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/CustomToStringCellRenderer.java
index e0fadc6477..3a45e45eb6 100644
--- a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/CustomToStringCellRenderer.java
+++ b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/CustomToStringCellRenderer.java
@@ -118,7 +118,7 @@ public class CustomToStringCellRenderer The About Program... dialog displays summary information about a program. The About Program dialog displays summary information about a program.
Installed Processors...
User Agreement
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/About/About_Program_File.htm b/Ghidra/Features/Base/src/main/help/help/topics/About/About_Program_File.htm
index d5e5b12677..fcaa5da665 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/About/About_Program_File.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/About/About_Program_File.htm
@@ -13,7 +13,7 @@
About Program
-
+
To view information about the currently open (active) program
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ClearPlugin/Clear.htm b/Ghidra/Features/Base/src/main/help/help/topics/ClearPlugin/Clear.htm
index c44b8239ec..bf801c6999 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/ClearPlugin/Clear.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/ClearPlugin/Clear.htm
@@ -5,7 +5,6 @@
-
Clear
@@ -183,7 +182,7 @@ with a Cancel button. The Cancel button may be
pressed
to terminate the action.
-
You can undo clearing of code units +
You can undo clearing of code units if it has an undesired effect
The Clear Flow options dialog has check boxes to control diff --git a/Ghidra/Features/Base/src/main/help/help/topics/EclipseIntegration/EclipseIntegration.htm b/Ghidra/Features/Base/src/main/help/help/topics/EclipseIntegration/EclipseIntegration.htm index d7fb178149..87761ebbfa 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/EclipseIntegration/EclipseIntegration.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/EclipseIntegration/EclipseIntegration.htm @@ -2,13 +2,9 @@
- - -The Eclipse installation location and communication ports can be configured in the Front End tool's Eclipse Integration options. If an attempt is made to launch Eclipse from Ghidra and these things are not configured correctly, the user will be taken to Eclipse - Integration options automatically./P> + Integration options automatically. +
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end_Menus.htm b/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end_Menus.htm index 5536640baf..6e7d68a290 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end_Menus.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end_Menus.htm @@ -24,7 +24,7 @@ and restore options show up only in the Ghidra Project Window even though the plugins providing these options can be added to other tools. To bring up the Configure Tool Plugins dialog, select the FileTo view information about a - file, right mouse click on the file in the data tree and choose the About... + file, right mouse click on the file in the data tree and choose the About Program option.
To bring up the Options dialog, select EditOptions...
The Configure Tool dialog allows you to add/remove plugin packages or individual Plugins from a tool. To
display the Configure Tool dialog, select File Configure....This dialog is also displayed when you Configure.This dialog is also displayed when you create a new
tool.
To display the Options dialog, select EditTool Options... from the tool menu.
Once installed, the translation service plugins, like all plugins, can be
found in the File
- Configure... window and must be enabled before they will
+ Configure window and must be enabled before they will
appear in the Data
Translate menu.
This view does not support editing.
+This view does not support editing.
The alignment address specifies what address should appear in column 0. Any address can be specified, but the address will be - normalized to be near the program's miminum address. This enables you to + normalized to be near the program's minimum address. This enables you to view bytes in an offcut manner and to identify patterns in the bytes. Changing the alignment address affects the offset, which is the column that would display the bytes for address 0 if it diff --git a/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html b/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html index ce4dc14231..34c2de01c7 100644 --- a/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html +++ b/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html @@ -802,7 +802,7 @@
- Start Fully Zoomed Out - always start fully zoomed out so that the entire graph can be seen.
-- Start Fully Zoomed In/B> - always start fully zoomed in on the vertex containing +
- Start Fully Zoomed In - always start fully zoomed in on the vertex containing the current location.
- Remember User Settings - keep the zoom level where the user previously left diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java index 559065001e..34a6c01536 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java @@ -27,7 +27,7 @@ import docking.DockingWindowManager; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GHtmlLabel; import docking.widgets.label.GLabel; -import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTable; import pdb.PdbPlugin; @@ -100,8 +100,7 @@ class SymbolFilePanel extends JPanel { } SymbolFileRow getSelectedRow() { - return table.getSelectedRow() != -1 - ? tableModel.getRowObject(table.getSelectedRow()) + return table.getSelectedRow() != -1 ? tableModel.getRowObject(table.getSelectedRow()) : null; } @@ -118,9 +117,8 @@ class SymbolFilePanel extends JPanel { private JPanel buildWelcomePanel() { welcomePanel = new JPanel(); - welcomePanel.add(new GHtmlLabel( - "
Configuration must be set first!")); + welcomePanel.add(new GHtmlLabel(" Configuration must be set first!")); welcomePanel.setPreferredSize(tablePanel.getPreferredSize()); return welcomePanel; @@ -138,7 +136,7 @@ class SymbolFilePanel extends JPanel { isMatchColumn.setMaxWidth(32); isMatchColumn.setMinWidth(32); - // a few extra rows than needed since the table component + // a few extra rows than needed since the table component // will be resized according to the number of warning text // lines at the bottom of the dialog table.setVisibleRowCount(8); diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java index f700469047..adb69f9196 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java @@ -37,7 +37,7 @@ import docking.widgets.label.GHtmlLabel; import docking.widgets.label.GLabel; import docking.widgets.table.GTable; import docking.widgets.textfield.HintTextField; -import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.framework.preferences.Preferences; import ghidra.util.*; import ghidra.util.layout.PairLayout; @@ -112,7 +112,7 @@ class SymbolServerPanel extends JPanel { JScrollPane tableScrollPane = buildTable(); defaultConfigNotice = new JPanel(); GHtmlLabel label = new GHtmlLabel("
Missing / invalid configuration.
" + + Messages.ERROR.toHexString() + "\">
Missing / invalid configuration.
" + "Using default search location:
Program's Import Location
"); label.setHorizontalAlignment(SwingConstants.CENTER); defaultConfigNotice.add(label); diff --git a/Ghidra/Framework/Docking/data/docking.theme.properties b/Ghidra/Framework/Docking/data/docking.theme.properties index 4e60bac34e..aa2b22ce07 100644 --- a/Ghidra/Framework/Docking/data/docking.theme.properties +++ b/Ghidra/Framework/Docking/data/docking.theme.properties @@ -159,14 +159,14 @@ color.fg.dialog.status.error = color.fg.error color.fg.dialog.status.warning = orange color.fg.dialog.status.normal = lightBlue -color.bg.currentline = rgb(40,40,56) // dark bluish gray +color.bg.currentline = #003366 color.bg.textfield.hint.invalid = maroon color.bg.filterfield = color.bg.filtered color.fg.filterfield = darkSlateGray -color.bg.selection = #284028 // greenish +color.bg.selection = #003333 // greenish color.bg.highlight = #404028 // yellowish color.bg.fieldpanel.selection.and.highlight = #344028 // yellow greenish diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ErrLogDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/ErrLogDialog.java index 3309341145..02c8a8ea57 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ErrLogDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ErrLogDialog.java @@ -4,9 +4,9 @@ * 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. diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java index dd3b48a7d0..8a8293fa39 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java @@ -268,9 +268,9 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel { /** * Overrides this method to ensure that the new foreground color is not * a {@link GColorUIResource}. Some Look and Feels will ignore color values that extend - * {@link UIResource}, choosing instead their own custom painting behavior. By not using a + * {@link UIResource}, choosing instead their own custom painting behavior. By not using a * UIResource, we prevent the Look and Feel from overriding this renderer's color value. - * + * * @param fg the new foreground color */ @Override @@ -281,9 +281,9 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel { /** * Overrides this method to ensure that the new background color is not * a {@link GColorUIResource}. Some Look and Feels will ignore color values that extend - * {@link UIResource}, choosing instead their own custom painting behavior. By not using a + * {@link UIResource}, choosing instead their own custom painting behavior. By not using a * UIResource, we prevent the Look and Feel from overriding this renderer's color value. - * + * * @param bg the new background color */ @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/GComponent.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/GComponent.java index 538bd01057..0242cdd149 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/GComponent.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/GComponent.java @@ -39,11 +39,11 @@ public interface GComponent { } /** - * Returns the current HTML rendering 'enable-ment' of this component. - * + * Returns the current HTML rendering enablement of this component. + * * @return boolean, true if HTML rendering is allowed */ - public default boolean getHTMLRenderingEnabled() { + public default boolean isHTMLRenderingEnabled() { Object prop = ((JComponent) this).getClientProperty(HTML_DISABLE_STRING); return prop == null || prop != Boolean.TRUE; } @@ -66,7 +66,7 @@ public interface GComponent { /** * Sets the HTML rendering flag for the specified component. - * + * * @param comp the thing * @param enabled boolean, if true html rendering will be allowed */ diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java index dc69877504..d7e280092e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java @@ -51,13 +51,11 @@ public abstract class AbstractHtmlLabel extends JLabel protected AbstractHtmlLabel() { addPropertyChangeListener(this); - setHTMLRenderingEnabled(false); // disable parent html rendering so we can do our own } protected AbstractHtmlLabel(String text) { super(text); addPropertyChangeListener(this); - setHTMLRenderingEnabled(false); // disable parent html rendering so we can do our own } @Override @@ -82,7 +80,7 @@ public abstract class AbstractHtmlLabel extends JLabel private void updateHtmlView() { String text = getText(); - if (text == null) { + if (text == null || !isHTMLRenderingEnabled()) { putClientProperty(BasicHTML.propertyKey, null); return; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java index ab7150be5a..065e706887 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java @@ -207,7 +207,7 @@ public abstract class AbstractColumnConstraintEditorimplements ColumnConstra * @return an HTML string suitable for a JLabel. */ protected final static String formatStatus(String message, boolean error) { - Color color = error ? Colors.ERROR : Colors.FOREGROUND; + Color color = error ? Colors.Messages.ERROR : Colors.FOREGROUND; String messageWithFont = HTMLUtilities.setFont(message, color, 12); String html = HTMLUtilities.wrapAsHTML(messageWithFont); return html; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java index 20829a5d12..82d129954b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java @@ -56,7 +56,7 @@ import ghidra.util.worker.PriorityWorker; * Class for creating a JTree that supports filtering, threading, and a progress bar. */ -public class GTree extends JPanel implements BusyListener, ThemeListener { +public class GTree extends JPanel implements BusyListener { private static final Color BACKGROUND = new GColor("color.bg.tree"); private AutoScrollTree tree; private GTreeModel model; @@ -93,6 +93,11 @@ public class GTree extends JPanel implements BusyListener, ThemeListener { private JTreeMouseListenerDelegate mouseListenerDelegate; private GTreeDragNDropHandler dragNDropHandler; private boolean isFilteringEnabled = true; + private ThemeListener themeListener = e -> { + if (e.isLookAndFeelChanged()) { + model.fireNodeStructureChanged(getModelRoot()); + } + }; private ThreadLocal threadLocalMonitor = new ThreadLocal<>(); private PriorityWorker worker; @@ -135,7 +140,7 @@ public class GTree extends JPanel implements BusyListener, ThemeListener { uniquePreferenceKey)); filterUpdateManager = new SwingUpdateManager(1000, 30000, () -> updateModelFilter()); - Gui.addThemeListener(this); + Gui.addThemeListener(themeListener); } /** @@ -148,13 +153,6 @@ public class GTree extends JPanel implements BusyListener, ThemeListener { threadLocalMonitor.set(monitor); } - @Override - public void themeChanged(ThemeEvent event) { - if (event.isLookAndFeelChanged()) { - model.fireNodeStructureChanged(getModelRoot()); - } - } - /** * Returns the monitor in associated with the GTree for the calling thread. This method is * designed to be used by slow loading nodes that are loading off the Swing thread. Some @@ -272,6 +270,8 @@ public class GTree extends JPanel implements BusyListener, ThemeListener { realViewRootNode.disposeClones(); } model.dispose(); + + Gui.removeThemeListener(themeListener); } public boolean isDisposed() { @@ -1091,17 +1091,17 @@ public class GTree extends JPanel implements BusyListener, ThemeListener { Consumer consumer) { /* - + If the GTree were to use Java's CompletableStage API, then the code below could be written thusly: - + tree.getNewNode(modelParent, newName) .thenCompose(newModelChild -> { tree.ignoreFilter(newModelChild); return tree.getNewNode(viewParent, newName); )) .thenAccept(consumer); - + */ // ensure we operate on the model node which will always have the given child not the view diff --git a/Ghidra/Framework/Gui/src/main/java/generic/theme/GThemeDefaults.java b/Ghidra/Framework/Gui/src/main/java/generic/theme/GThemeDefaults.java index a3ea36ecae..1da18bd934 100644 --- a/Ghidra/Framework/Gui/src/main/java/generic/theme/GThemeDefaults.java +++ b/Ghidra/Framework/Gui/src/main/java/generic/theme/GThemeDefaults.java @@ -20,8 +20,8 @@ import static generic.theme.SystemThemeIds.*; import java.awt.Color; /** TODO doc how clients should use this in their code, with - * - * + * + * * Colors.BACKGROUND * Colors.Java.BORDER */ @@ -56,7 +56,7 @@ public class GThemeDefaults { public static final GColor BACKGROUND = new GColor("color.bg"); public static final GColor CURSOR = new GColor("color.cursor.focused"); public static final GColor DISABLED = new GColor("color.palette.disabled"); - public static final GColor ERROR = new GColor("color.fg.error"); // TODO replace most uses of this with Messages.ERROR + public static final GColor ERROR = new GColor("color.fg.error"); public static final GColor FOREGROUND = new GColor("color.fg"); public static final GColor FOREGROUND_DISABLED = new GColor("color.fg.disabled"); //@formatter:on @@ -83,9 +83,10 @@ public class GThemeDefaults { public static class Messages { //@formatter:off public static final GColor NORMAL = new GColor("color.fg.messages.normal"); + @SuppressWarnings("hiding") // we know there is another 'ERROR' field in this file public static final GColor ERROR = new GColor("color.fg.messages.error"); public static final GColor HINT = new GColor("color.fg.messages.hint"); - public static final GColor WARNING = new GColor("color.fg.messages.warning"); + public static final GColor WARNING = new GColor("color.fg.messages.warning"); //@formatter:on } @@ -127,7 +128,7 @@ public class GThemeDefaults { * it prevents excess object creation. This method should be used when the desired * palette color is not in that list. Further, this method should only be called once * per use, such as when initializing a constant value. - * + * * @param name the palette entry name * @return the GColor */ diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java b/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java index dba8dcf869..405476b8f0 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.swing.Icon; import javax.swing.JEditorPane; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; @@ -35,6 +36,7 @@ import javax.swing.text.html.HTML.Tag; import generic.jar.ResourceFile; import generic.theme.*; +import generic.theme.GThemeDefaults.Colors; import ghidra.framework.Application; import ghidra.framework.preferences.Preferences; import ghidra.util.Msg; @@ -43,11 +45,11 @@ 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 + * 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 { @@ -73,8 +75,7 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { colorsById.put("h3", new GColor("color.fg.help.selector.h3")); colorsById.put("p.providedbyplugin", new GColor("color.fg.help.selector.p.provided.by.plugin")); - colorsById.put("p.relatedtopic", - new GColor("color.fg.help.selector.p.related.topic")); + colorsById.put("p.relatedtopic", new GColor("color.fg.help.selector.p.related.topic")); colorsById.put("th", new GColor("color.fg.help.selector.th")); colorsById.put("code", new GColor("color.fg.help.selector.code")); colorsById.put("code.path", new GColor("color.fg.help.selector.code.path")); @@ -176,9 +177,9 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { } } - /** + /** * 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 + * 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) { @@ -235,10 +236,10 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { } // - // The item was not found by the ResourceManager (i.e., it is not in a 'resources' + // 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; } @@ -254,7 +255,7 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { } try { - // put the anchor back into the URL + // put the anchor back into the URL return new URL(anchorlessURL, anchor); } catch (MalformedURLException e) { @@ -438,7 +439,7 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { //================================================================================================== // Inner Classes -//================================================================================================== +//================================================================================================== private class GHelpHTMLFactory extends HTMLFactory { @Override @@ -465,31 +466,36 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { } /** - * Overridden to allow us to find images that are defined as constants in places like + * Overridden to allow us to find images that are defined as constants in places like * {@link Icons} */ private class GHelpImageView extends ImageView { + private static final String HELP_SHARED_ARROW = "help/shared/arrow.gif"; + private static final Icon SHARED_ARROW_ICON = new HelpRightArrowIcon(Colors.FOREGROUND); + private static final IconProvider SHARED_ARROW_ICON_PROVIDER = + new IconProvider(SHARED_ARROW_ICON, null); + /* * 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. - * + * 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 + * 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. */ @@ -541,12 +547,22 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { return null; } - String srcString = src.toString(); + // + // This code is looking for the specific referenced image file and then replacing that + // image file with something that can update its content at runtime, based on theme. + // Alternatively, we could have updated all help files to point to a GIcon, which + // handles updating itself when the theme changes. We chose to replace the icon here + // instead of in the source code to prevent changing many files. + // + String srcString = src.toString().trim(); + if (srcString.equals(HELP_SHARED_ARROW)) { + return installImageFromCustomIcon(SHARED_ARROW_ICON_PROVIDER); + } // check if the srcString is a defined theme icon id if (Gui.hasIcon(srcString)) { - // - // Wrap the GIcon inside of an IconProvider, as that class can handle a null URL + // + // Wrap the GIcon inside of an IconProvider, as that class can handle a null URL // returned from GIcon. (This can happen if the GIcon is based on a modified icon.) // GIcon gIcon = new GIcon(srcString); @@ -562,6 +578,19 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { return url; } + private URL installImageFromCustomIcon(IconProvider iconProvider) { + + if (iconProvider == null || iconProvider.isInvalid()) { + return null; + } + + this.image = iconProvider.getImage(); + + // note: this icon is not used to load the image; the 'image' we set is used instead + URL url = iconProvider.getOrCreateUrl(); + return url; + } + private URL installImageFromJavaCode(String srcString) { IconProvider iconProvider = getIconFromJavaCode(srcString); @@ -590,7 +619,7 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { // check below } - // Try the ResourceManager. This will work for images that start with GHelp + // 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; diff --git a/Ghidra/Framework/Help/src/main/java/help/HelpRightArrowIcon.java b/Ghidra/Framework/Help/src/main/java/help/HelpRightArrowIcon.java new file mode 100644 index 0000000000..516190a6b1 --- /dev/null +++ b/Ghidra/Framework/Help/src/main/java/help/HelpRightArrowIcon.java @@ -0,0 +1,154 @@ +/* ### + * 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 help; + +import java.awt.*; +import java.awt.geom.*; + +import javax.swing.Icon; + +/** + * A basic arrow that points to the right, with padding on the sides and above. + */ +public class HelpRightArrowIcon implements Icon { + + private static final int ICON_SIZE = 20; + + private Color color; + private Shape shape; + + public HelpRightArrowIcon(Color color) { + this.color = color; + this.shape = buildShape(); + } + + private Shape buildShape() { + + GeneralPath barPath = new GeneralPath(); + + // + // Construct the arrow in 2 parts: the line and the angle bracket. The arrow will not fill + // the full area. This allows space before and after the arrow. This space serves as + // padding between text inside of html content. The arrow is also closer to the bottom, + // to aligned vertically with text. + // + double height = 10; + double width = 12; + double thickness = 2; + double arrowthickness = 3; + + double top = ICON_SIZE - height; + double cy = top + (height / 2); + double p1x = (ICON_SIZE - width) / 2; + double p1y = cy - (thickness / 2); + barPath.moveTo(p1x, p1y); + + double barlength = width - 2; + double p2x = p1x + barlength; + double p2y = p1y; + barPath.lineTo(p2x, p2y); + + double p3x = p2x; + double p3y = p2y + thickness; + barPath.lineTo(p3x, p3y); + + double p4x = p1x; + double p4y = p3y; + barPath.lineTo(p4x, p4y); + + // back to start of arrow line + barPath.lineTo(p1x, p1y); + barPath.closePath(); + + GeneralPath arrowPath = new GeneralPath(); + + // trailing arrow bar center + p1x = p1x + barlength + arrowthickness; + p1y = cy; + arrowPath.moveTo(p1x, p1y); + + // trailing upper arrow bar point + double trianglewidth = 5; + p2x = p1x - trianglewidth; + p2y = top + 1; + arrowPath.lineTo(p2x, p2y); + + // leading upper arrow bar point + p3x = p2x - arrowthickness; + p3y = p2y; + arrowPath.lineTo(p3x, p3y); + + // leading arrow bar center + p4x = p1x - arrowthickness; + p4y = cy; + arrowPath.lineTo(p4x, p4y); + + // leading lower arrow bar point + double p5x = p3x; + double p5y = ICON_SIZE - 1; + arrowPath.lineTo(p5x, p5y); + + // trailing lower arrow bar point + double p6x = p2x; + double p6y = p5y; + arrowPath.lineTo(p6x, p6y); + + // back to start + double p7x = p1x; + double p7y = p1y; + arrowPath.lineTo(p7x, p7y); + arrowPath.closePath(); + + AffineTransform identity = new AffineTransform(); + Shape barShape = barPath.createTransformedShape(identity); + Area barArea = new Area(barShape); + + Shape arrowShape = arrowPath.createTransformedShape(identity); + Area arrowArea = new Area(arrowShape); + + Area fullArea = new Area(); + fullArea.add(barArea); + fullArea.add(arrowArea); + + return fullArea; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + try { + g2d.translate(x, y); + g2d.setColor(color); + g2d.fill(shape); + } + finally { + g2d.translate(-x, -y); + } + } + + @Override + public int getIconWidth() { + return ICON_SIZE; + } + + @Override + public int getIconHeight() { + return ICON_SIZE; + } +} diff --git a/Ghidra/Framework/Help/src/main/resources/help/shared/arrow.gif b/Ghidra/Framework/Help/src/main/resources/help/shared/arrow.gif deleted file mode 100644 index bcb3db7057..0000000000 Binary files a/Ghidra/Framework/Help/src/main/resources/help/shared/arrow.gif and /dev/null differ diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/gui/ThemeManagerPlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/gui/ThemeManagerPlugin.java index 0e9da322fc..345c82364c 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/gui/ThemeManagerPlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/app/plugin/gui/ThemeManagerPlugin.java @@ -57,7 +57,7 @@ public class ThemeManagerPlugin extends Plugin implements ApplicationLevelOnlyPl .onAction(e -> switchTheme()) .buildAndInstall(tool); - new ActionBuilder("Configure", owner).menuPath("Edit", "Theme", "Configure...") + new ActionBuilder("Configure", owner).menuPath("Edit", "Theme", "Configure") .menuGroup(group, "2") .helpLocation(new HelpLocation("Theming", "Edit_Theme")) .onAction(e -> configure()) diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java index e77753c89d..b12bc2c5ba 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java @@ -993,9 +993,8 @@ public abstract class PluginTool extends AbstractDockingTool { optionsAction.setAddToAllWindows(true); optionsAction.setHelpLocation( new HelpLocation(ToolConstants.FRONT_END_HELP_TOPIC, "Tool Options")); - MenuData menuData = - new MenuData(new String[] { ToolConstants.MENU_EDIT, "&Tool Options..." }, null, - ToolConstants.TOOL_OPTIONS_MENU_GROUP); + MenuData menuData = new MenuData(new String[] { ToolConstants.MENU_EDIT, "&Tool Options" }, + null, ToolConstants.TOOL_OPTIONS_MENU_GROUP); menuData.setMenuSubGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP); optionsAction.setMenuBarData(menuData); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java index 42c0f83605..4c289b57a9 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraTool.java @@ -101,7 +101,8 @@ public class GhidraTool extends PluginTool { @Override public PluginClassManager getPluginClassManager() { if (pluginClassManager == null) { - pluginClassManager = new PluginClassManager(Plugin.class, ApplicationLevelOnlyPlugin.class); + pluginClassManager = + new PluginClassManager(Plugin.class, ApplicationLevelOnlyPlugin.class); } return pluginClassManager; } @@ -206,7 +207,7 @@ public class GhidraTool extends PluginTool { }; configureToolAction.setMenuBarData(new MenuData( - new String[] { ToolConstants.MENU_FILE, "Configure..." }, null, "PrintPost_PreTool")); + new String[] { ToolConstants.MENU_FILE, "Configure" }, null, "PrintPost_PreTool")); configureToolAction.setEnabled(true); addAction(configureToolAction);