mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-01-31 21:41:07 +00:00
GP-1981 added in font support and Icon support
This commit is contained in:
parent
cd4ab3a156
commit
703a7beb8d
@ -61,7 +61,7 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
private static final Icon EXPAND_ICON = Icons.EXPAND_ALL_ICON;
|
||||
private static final Icon COLLAPSE_ICON = Icons.COLLAPSE_ALL_ICON;
|
||||
|
||||
private static ImageIcon REFRESH_ICON = Icons.REFRESH_ICON;
|
||||
private static Icon REFRESH_ICON = Icons.REFRESH_ICON;
|
||||
private static Icon REFRESH_NOT_NEEDED_ICON = ResourceManager.getDisabledIcon(REFRESH_ICON, 60);
|
||||
|
||||
private static final String RECURSE_DEPTH_PROPERTY_NAME = "call.tree.recurse.depth";
|
||||
@ -350,8 +350,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
return true;
|
||||
}
|
||||
};
|
||||
goToSourceAction.setPopupMenuData(
|
||||
new MenuData(new String[] { "Go To Call Source" }, goToMenu));
|
||||
goToSourceAction
|
||||
.setPopupMenuData(new MenuData(new String[] { "Go To Call Source" }, goToMenu));
|
||||
goToSourceAction.setHelpLocation(
|
||||
new HelpLocation(plugin.getName(), "Call_Tree_Context_Action_Goto_Source"));
|
||||
tool.addLocalAction(this, goToSourceAction);
|
||||
@ -369,8 +369,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
new ToolBarData(ResourceManager.loadImage("images/application_double.png"),
|
||||
filterOptionsToolbarGroup, "1"));
|
||||
filterDuplicates.setSelected(true);
|
||||
filterDuplicates.setHelpLocation(
|
||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Filter"));
|
||||
filterDuplicates
|
||||
.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Filter"));
|
||||
tool.addLocalAction(this, filterDuplicates);
|
||||
|
||||
//
|
||||
@ -393,8 +393,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
"<html>Recurse Depth<br><br>Limits the depth to " + "which recursing tree operations" +
|
||||
"<br> will go. Example operations include <b>Expand All</b> and filtering");
|
||||
recurseIcon = new NumberIcon(recurseDepth.get());
|
||||
recurseDepthAction.setToolBarData(
|
||||
new ToolBarData(recurseIcon, filterOptionsToolbarGroup, "2"));
|
||||
recurseDepthAction
|
||||
.setToolBarData(new ToolBarData(recurseIcon, filterOptionsToolbarGroup, "2"));
|
||||
recurseDepthAction.setHelpLocation(
|
||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Recurse_Depth"));
|
||||
|
||||
@ -414,8 +414,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
"Listing to<br>the <b>source</b> location of the call");
|
||||
navigationOutgoingAction.setToolBarData(new ToolBarData(
|
||||
Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON, navigationOptionsToolbarGroup, "1"));
|
||||
navigationOutgoingAction.setHelpLocation(
|
||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Navigation"));
|
||||
navigationOutgoingAction
|
||||
.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Navigation"));
|
||||
tool.addLocalAction(this, navigationOutgoingAction);
|
||||
|
||||
//
|
||||
@ -596,8 +596,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
refreshAction.setEnabled(true);
|
||||
refreshAction.setDescription("<html>Push at any time to refresh the current trees.<br>" +
|
||||
"This is highlighted when the data <i>may</i> be stale.<br>");
|
||||
refreshAction.setHelpLocation(
|
||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Refresh"));
|
||||
refreshAction
|
||||
.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Refresh"));
|
||||
tool.addLocalAction(this, refreshAction);
|
||||
|
||||
//
|
||||
@ -671,8 +671,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||
"Call_Tree_Context_Action_Show_Call_Tree_For_Function"));
|
||||
newCallTree.setPopupMenuData(new MenuData(new String[] { "Show Call Tree For Function" },
|
||||
CallTreePlugin.PROVIDER_ICON, newTreeMenu));
|
||||
newCallTree.setDescription("Show the Function Call Tree window for the function " +
|
||||
"selected in the call tree");
|
||||
newCallTree.setDescription(
|
||||
"Show the Function Call Tree window for the function " + "selected in the call tree");
|
||||
tool.addLocalAction(this, newCallTree);
|
||||
}
|
||||
|
||||
|
@ -341,7 +341,7 @@ class ParseDialog extends DialogComponentProvider {
|
||||
}
|
||||
};
|
||||
saveAction.setEnabled(false);
|
||||
ImageIcon icon = ResourceManager.loadImage("images/disk.png");
|
||||
Icon icon = ResourceManager.loadImage("images/disk.png");
|
||||
String saveGroup = "save";
|
||||
saveAction.setMenuBarData(new MenuData(new String[] { "Save" }, icon, saveGroup));
|
||||
saveAction.setToolBarData(new ToolBarData(icon, saveGroup));
|
||||
@ -371,8 +371,8 @@ class ParseDialog extends DialogComponentProvider {
|
||||
clearAction.setEnabled(true);
|
||||
icon = ResourceManager.loadImage("images/erase16.png");
|
||||
String clearGroup = "clear";
|
||||
clearAction.setMenuBarData(
|
||||
new MenuData(new String[] { "Clear Profile" }, icon, clearGroup));
|
||||
clearAction
|
||||
.setMenuBarData(new MenuData(new String[] { "Clear Profile" }, icon, clearGroup));
|
||||
clearAction.setToolBarData(new ToolBarData(icon, clearGroup));
|
||||
clearAction.setDescription("Clear profile");
|
||||
addAction(clearAction);
|
||||
|
@ -19,7 +19,7 @@ import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
@ -40,7 +40,7 @@ import resources.Icons;
|
||||
*/
|
||||
public class CollapseAllArchivesAction extends DockingAction {
|
||||
|
||||
private ImageIcon collapseIcon = Icons.COLLAPSE_ALL_ICON;
|
||||
private Icon collapseIcon = Icons.COLLAPSE_ALL_ICON;
|
||||
private final DataTypeManagerPlugin plugin;
|
||||
|
||||
public CollapseAllArchivesAction(DataTypeManagerPlugin plugin) {
|
||||
|
@ -32,7 +32,7 @@ import docking.ActionContext;
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.*;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.options.editor.FontPropertyEditor;
|
||||
import docking.options.editor.FontEditor;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import ghidra.framework.options.SaveState;
|
||||
@ -287,7 +287,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter {
|
||||
}
|
||||
|
||||
protected void doSelectFont() {
|
||||
FontPropertyEditor editor = new FontPropertyEditor();
|
||||
FontEditor editor = new FontEditor();
|
||||
editor.setValue(defaultFont);
|
||||
editor.showDialog();
|
||||
defaultFont = (Font) editor.getValue();
|
||||
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.functioncompare.actions;
|
||||
import java.awt.event.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.action.ToolBarData;
|
||||
@ -48,7 +48,7 @@ public class NavigateToFunctionAction extends ToggleDockingAction {
|
||||
|
||||
private GoToService goToService;
|
||||
|
||||
private static final ImageIcon NAV_FUNCTION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON;
|
||||
private static final Icon NAV_FUNCTION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -64,10 +64,9 @@ public class NavigateToFunctionAction extends ToggleDockingAction {
|
||||
setSelected(false);
|
||||
ToolBarData newToolBarData = new ToolBarData(NAV_FUNCTION_ICON);
|
||||
setToolBarData(newToolBarData);
|
||||
setDescription(
|
||||
HTMLUtilities.toHTML("Toggle <b>On</b> means to navigate to whatever " +
|
||||
"function is selected in the comparison panel, when focus changes or" +
|
||||
"a new function is selected."));
|
||||
setDescription(HTMLUtilities.toHTML("Toggle <b>On</b> means to navigate to whatever " +
|
||||
"function is selected in the comparison panel, when focus changes or" +
|
||||
"a new function is selected."));
|
||||
setHelpLocation(
|
||||
new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC, "Navigate_To_Function"));
|
||||
|
||||
|
@ -17,7 +17,7 @@ package ghidra.app.plugin.core.interpreter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.app.plugin.core.console.CodeCompletion;
|
||||
|
||||
@ -38,7 +38,7 @@ public interface InterpreterConnection {
|
||||
*
|
||||
* @return The icon associated with the interpreter. Null if default icon is desired.
|
||||
*/
|
||||
public ImageIcon getIcon();
|
||||
public Icon getIcon();
|
||||
|
||||
/**
|
||||
* Gets a {@link List} of {@link CodeCompletion code completions} for the given command.
|
||||
|
@ -30,7 +30,7 @@ import javax.swing.undo.UndoableEdit;
|
||||
import docking.*;
|
||||
import docking.action.*;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.options.editor.FontPropertyEditor;
|
||||
import docking.options.editor.FontEditor;
|
||||
import docking.widgets.OptionDialog;
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.script.GhidraScriptUtil;
|
||||
@ -516,7 +516,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||
}
|
||||
|
||||
private void doSelectFont() {
|
||||
FontPropertyEditor editor = new FontPropertyEditor();
|
||||
FontEditor editor = new FontEditor();
|
||||
editor.setValue(defaultFont);
|
||||
editor.showDialog();
|
||||
defaultFont = (Font) editor.getValue();
|
||||
|
@ -39,7 +39,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
static final String SCRIPT_STATUS_COLUMN_NAME = "Status";
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
private static final ImageIcon ERROR_IMG = Icons.ERROR_ICON;
|
||||
private static final Icon ERROR_IMG = Icons.ERROR_ICON;
|
||||
|
||||
private GhidraScriptComponentProvider provider;
|
||||
private List<ResourceFile> scriptList = new ArrayList<>();
|
||||
@ -217,8 +217,8 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
Swing.runIfSwingOrRunLater(() -> super.fireTableChanged(e));
|
||||
}
|
||||
|
||||
private class StatusColumn extends AbstractDynamicTableColumn<ResourceFile, ImageIcon, Object> {
|
||||
private Comparator<ImageIcon> comparator = (i1, i2) -> {
|
||||
private class StatusColumn extends AbstractDynamicTableColumn<ResourceFile, Icon, Object> {
|
||||
private Comparator<Icon> comparator = (i1, i2) -> {
|
||||
if (i1 == i2) {
|
||||
return 0;
|
||||
}
|
||||
@ -234,12 +234,19 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
if (i2 == null) {
|
||||
return -1; // empty after icon
|
||||
}
|
||||
String d1 = i1.getDescription();
|
||||
String d2 = i2.getDescription();
|
||||
String d1 = getDescription(i1);
|
||||
String d2 = getDescription(i2);
|
||||
return SystemUtilities.compareTo(d1, d2);
|
||||
};
|
||||
|
||||
private GColumnRenderer<ImageIcon> renderer = new AbstractGColumnRenderer<>() {
|
||||
private String getDescription(Icon icon) {
|
||||
if (icon instanceof ImageIcon imageIcon) {
|
||||
return imageIcon.getDescription();
|
||||
}
|
||||
return icon.getClass().getName();
|
||||
}
|
||||
|
||||
private GColumnRenderer<Icon> renderer = new AbstractGColumnRenderer<>() {
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
||||
@ -269,14 +276,14 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterString(ImageIcon t, Settings settings) {
|
||||
public String getFilterString(Icon t, Settings settings) {
|
||||
// we could use the tooltip text, but it doesn't seem worth it
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public GColumnRenderer<ImageIcon> getColumnRenderer() {
|
||||
public GColumnRenderer<Icon> getColumnRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
@ -286,7 +293,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageIcon getValue(ResourceFile rowObject, Settings settings, Object data,
|
||||
public Icon getValue(ResourceFile rowObject, Settings settings, Object data,
|
||||
ServiceProvider sp) throws IllegalArgumentException {
|
||||
ScriptInfo info = infoManager.getExistingScriptInfo(rowObject);
|
||||
if (info.isCompileErrors() || info.isDuplicate()) {
|
||||
@ -296,7 +303,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<ImageIcon> getComparator() {
|
||||
public Comparator<Icon> getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.symtable;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
@ -231,8 +231,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
case ChangeManager.DOCR_CODE_ADDED:
|
||||
case ChangeManager.DOCR_CODE_REMOVED:
|
||||
if (rec.getNewValue() instanceof Data) {
|
||||
domainObjectWorker.schedule(
|
||||
new CodeAddedRemoveJob(currentProgram, rec.getStart()));
|
||||
domainObjectWorker
|
||||
.schedule(new CodeAddedRemoveJob(currentProgram, rec.getStart()));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -241,16 +241,15 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
// dynamic label symbols. Reference events must be used to check for existence
|
||||
// of a dynamic label symbol.
|
||||
Symbol symbol = (Symbol) rec.getNewValue();
|
||||
domainObjectWorker.schedule(
|
||||
new SymbolAddedJob(currentProgram, symbol));
|
||||
domainObjectWorker.schedule(new SymbolAddedJob(currentProgram, symbol));
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_REMOVED:
|
||||
|
||||
Address removeAddr = rec.getStart();
|
||||
Long symbolID = (Long) rec.getNewValue();
|
||||
domainObjectWorker.schedule(
|
||||
new SymbolRemovedJob(currentProgram, removeAddr, symbolID));
|
||||
domainObjectWorker
|
||||
.schedule(new SymbolRemovedJob(currentProgram, removeAddr, symbolID));
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_RENAMED:
|
||||
@ -294,8 +293,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED:
|
||||
|
||||
Address address = rec.getStart();
|
||||
domainObjectWorker.schedule(
|
||||
new ExternalEntryChangedJob(currentProgram, address));
|
||||
domainObjectWorker
|
||||
.schedule(new ExternalEntryChangedJob(currentProgram, address));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -344,7 +343,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
refProvider.setCurrentSymbol(symProvider.getCurrentSymbol());
|
||||
}
|
||||
};
|
||||
ImageIcon icon = ResourceManager.loadImage("images/table_go.png");
|
||||
Icon icon = ResourceManager.loadImage("images/table_go.png");
|
||||
openRefsAction.setPopupMenuData(
|
||||
new MenuData(new String[] { "Symbol References" }, icon, popupGroup));
|
||||
openRefsAction.setToolBarData(new ToolBarData(icon));
|
||||
@ -467,8 +466,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
};
|
||||
instructionsFromAction.setDescription("Instructions From");
|
||||
instructionsFromAction.setSelected(false);
|
||||
instructionsFromAction.setToolBarData(
|
||||
new ToolBarData(ResourceManager.loadImage("images/I.gif"), null));
|
||||
instructionsFromAction
|
||||
.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/I.gif"), null));
|
||||
|
||||
tool.addLocalAction(refProvider, instructionsFromAction);
|
||||
|
||||
@ -490,8 +489,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||
};
|
||||
dataFromAction.setDescription("Data From");
|
||||
dataFromAction.setSelected(false);
|
||||
dataFromAction.setToolBarData(
|
||||
new ToolBarData(ResourceManager.loadImage("images/D.gif"), null));
|
||||
dataFromAction
|
||||
.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/D.gif"), null));
|
||||
|
||||
tool.addLocalAction(refProvider, dataFromAction);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.plugin.debug;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
@ -73,7 +73,7 @@ public class DbViewerPlugin extends Plugin {
|
||||
};
|
||||
|
||||
refreshAction.setEnabled(false);
|
||||
ImageIcon icon = Icons.REFRESH_ICON;
|
||||
Icon icon = Icons.REFRESH_ICON;
|
||||
refreshAction.setToolBarData(new ToolBarData(icon));
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ import docking.action.builder.ActionBuilder;
|
||||
import docking.theme.gui.ThemeDialog;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.main.FrontEndOnly;
|
||||
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
@ -35,7 +35,7 @@ import ghidra.util.SystemUtilities;
|
||||
"This plugin is available only in the Ghidra Project Window."
|
||||
)
|
||||
//@formatter:on
|
||||
public class ThemeManagerPlugin extends Plugin implements FrontEndOnly {
|
||||
public class ThemeManagerPlugin extends Plugin implements ApplicationLevelOnlyPlugin {
|
||||
|
||||
public ThemeManagerPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.plugins.fsbrowser;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.Icon;
|
||||
|
||||
import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
@ -28,43 +28,43 @@ import resources.ResourceManager;
|
||||
*/
|
||||
public class ImageManager {
|
||||
//@formatter:off
|
||||
public final static ImageIcon COPY = ResourceManager.loadImage("images/page_copy.png");
|
||||
public final static ImageIcon CUT = ResourceManager.loadImage("images/edit-cut.png");
|
||||
public final static ImageIcon DELETE = ResourceManager.loadImage("images/page_delete.png");
|
||||
public final static ImageIcon FONT = ResourceManager.loadImage("images/text_lowercase.png");
|
||||
public final static ImageIcon LOCKED = ResourceManager.loadImage("images/lock.gif");
|
||||
public final static ImageIcon NEW = ResourceManager.loadImage("images/page_add.png");
|
||||
public final static ImageIcon PASTE = ResourceManager.loadImage("images/page_paste.png");
|
||||
public final static ImageIcon REDO = ResourceManager.loadImage("images/redo.png");
|
||||
public final static ImageIcon RENAME = ResourceManager.loadImage("images/textfield_rename.png");
|
||||
public final static ImageIcon REFRESH = Icons.REFRESH_ICON;
|
||||
public final static ImageIcon SAVE = ResourceManager.loadImage("images/disk.png");
|
||||
public final static ImageIcon SAVE_AS = ResourceManager.loadImage("images/disk_save_as.png");
|
||||
public final static ImageIcon UNDO = ResourceManager.loadImage("images/undo.png");
|
||||
public final static ImageIcon UNLOCKED = ResourceManager.loadImage("images/unlock.gif");
|
||||
public final static ImageIcon CLOSE = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door.png");
|
||||
public final static ImageIcon COLLAPSE_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/arrow_in.png");
|
||||
public final static ImageIcon COMPRESS = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/compress.png");
|
||||
public final static ImageIcon CREATE_FIRMWARE = ResourceManager.loadImage("images/media-flash.png");
|
||||
public final static ImageIcon EXPAND_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/arrow_inout.png");
|
||||
public final static ImageIcon EXTRACT = ResourceManager.loadImage("images/package_green.png");
|
||||
public final static ImageIcon INFO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/information.png");
|
||||
public final static ImageIcon OPEN = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door_open.png");
|
||||
public final static ImageIcon OPEN_AS_BINARY = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/controller.png");
|
||||
public final static ImageIcon OPEN_IN_LISTING = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/folder_table.png");
|
||||
public final static ImageIcon OPEN_FILE_SYSTEM = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/folder_brick.png");
|
||||
public final static ImageIcon PHOTO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/photo.png");
|
||||
public final static ImageIcon VIEW_AS_IMAGE = ResourceManager.loadImage("images/oxygen/16x16/games-config-background.png");
|
||||
public final static ImageIcon VIEW_AS_TEXT = ResourceManager.loadImage("images/format-text-bold.png");
|
||||
public final static ImageIcon UNKNOWN = ResourceManager.loadImage("images/help-browser.png");
|
||||
public final static ImageIcon IPOD = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/ipod.png");
|
||||
public final static ImageIcon IPOD_48 = ResourceManager.loadImage("images/oxygen/48x48/multimedia-player-apple-ipod.png");
|
||||
public final static ImageIcon ECLIPSE = ResourceManager.loadImage("images/eclipse.png");
|
||||
public final static ImageIcon JAR = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/page_white_cup.png");
|
||||
public final static ImageIcon KEY = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_key.png");
|
||||
public final static ImageIcon IMPORT = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_get.png");
|
||||
public final static ImageIcon iOS = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/phone.png");
|
||||
public final static ImageIcon OPEN_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_cascade.png");
|
||||
public final static ImageIcon LIST_MOUNTED = ResourceManager.loadImage("images/downArrow.png");
|
||||
public final static Icon COPY = ResourceManager.loadImage("images/page_copy.png");
|
||||
public final static Icon CUT = ResourceManager.loadImage("images/edit-cut.png");
|
||||
public final static Icon DELETE = ResourceManager.loadImage("images/page_delete.png");
|
||||
public final static Icon FONT = ResourceManager.loadImage("images/text_lowercase.png");
|
||||
public final static Icon LOCKED = ResourceManager.loadImage("images/lock.gif");
|
||||
public final static Icon NEW = ResourceManager.loadImage("images/page_add.png");
|
||||
public final static Icon PASTE = ResourceManager.loadImage("images/page_paste.png");
|
||||
public final static Icon REDO = ResourceManager.loadImage("images/redo.png");
|
||||
public final static Icon RENAME = ResourceManager.loadImage("images/textfield_rename.png");
|
||||
public final static Icon REFRESH = Icons.REFRESH_ICON;
|
||||
public final static Icon SAVE = ResourceManager.loadImage("images/disk.png");
|
||||
public final static Icon SAVE_AS = ResourceManager.loadImage("images/disk_save_as.png");
|
||||
public final static Icon UNDO = ResourceManager.loadImage("images/undo.png");
|
||||
public final static Icon UNLOCKED = ResourceManager.loadImage("images/unlock.gif");
|
||||
public final static Icon CLOSE = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door.png");
|
||||
public final static Icon COLLAPSE_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/arrow_in.png");
|
||||
public final static Icon COMPRESS = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/compress.png");
|
||||
public final static Icon CREATE_FIRMWARE = ResourceManager.loadImage("images/media-flash.png");
|
||||
public final static Icon EXPAND_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/arrow_inout.png");
|
||||
public final static Icon EXTRACT = ResourceManager.loadImage("images/package_green.png");
|
||||
public final static Icon INFO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/information.png");
|
||||
public final static Icon OPEN = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door_open.png");
|
||||
public final static Icon OPEN_AS_BINARY = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/controller.png");
|
||||
public final static Icon OPEN_IN_LISTING = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/folder_table.png");
|
||||
public final static Icon OPEN_FILE_SYSTEM = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/folder_brick.png");
|
||||
public final static Icon PHOTO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/photo.png");
|
||||
public final static Icon VIEW_AS_IMAGE = ResourceManager.loadImage("images/oxygen/16x16/games-config-background.png");
|
||||
public final static Icon VIEW_AS_TEXT = ResourceManager.loadImage("images/format-text-bold.png");
|
||||
public final static Icon UNKNOWN = ResourceManager.loadImage("images/help-browser.png");
|
||||
public final static Icon IPOD = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/ipod.png");
|
||||
public final static Icon IPOD_48 = ResourceManager.loadImage("images/oxygen/48x48/multimedia-player-apple-ipod.png");
|
||||
public final static Icon ECLIPSE = ResourceManager.loadImage("images/eclipse.png");
|
||||
public final static Icon JAR = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/page_white_cup.png");
|
||||
public final static Icon KEY = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_key.png");
|
||||
public final static Icon IMPORT = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_get.png");
|
||||
public final static Icon iOS = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/phone.png");
|
||||
public final static Icon OPEN_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_cascade.png");
|
||||
public final static Icon LIST_MOUNTED = ResourceManager.loadImage("images/downArrow.png");
|
||||
//@formatter:on
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ public class InterpreterPanelTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageIcon getIcon() {
|
||||
public Icon getIcon() {
|
||||
return Icons.STOP_ICON;
|
||||
}
|
||||
|
||||
@ -222,8 +222,7 @@ public class InterpreterPanelTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void doSwingMultilinePasteTest(List<String> multiLineTestValues)
|
||||
throws IOException {
|
||||
private void doSwingMultilinePasteTest(List<String> multiLineTestValues) throws IOException {
|
||||
// simulates what happens during a paste when multi-line string with
|
||||
// "\n"s is pasted.
|
||||
runSwingLater(() -> {
|
||||
|
@ -107,13 +107,10 @@ class SymbolServerPanel extends JPanel {
|
||||
JPanel buttonPanel = buildButtonPanel();
|
||||
JScrollPane tableScrollPane = buildTable();
|
||||
defaultConfigNotice = new JPanel();
|
||||
defaultConfigNotice.add(
|
||||
new GHtmlLabel(
|
||||
"<html><center><font color=red><br>" +
|
||||
"Missing / invalid configuration.<br><br>" +
|
||||
"Using default search location:<br>" +
|
||||
"Program's Import Location<br>",
|
||||
SwingConstants.CENTER));
|
||||
defaultConfigNotice.add(new GHtmlLabel(
|
||||
"<html><center><font color=red><br>" + "Missing / invalid configuration.<br><br>" +
|
||||
"Using default search location:<br>" + "Program's Import Location<br>",
|
||||
SwingConstants.CENTER));
|
||||
defaultConfigNotice.setPreferredSize(tableScrollPane.getPreferredSize());
|
||||
|
||||
additionalSearchLocationsPanel = new JPanel();
|
||||
@ -199,55 +196,47 @@ class SymbolServerPanel extends JPanel {
|
||||
}
|
||||
|
||||
private JPanel buildButtonPanel() {
|
||||
refreshSearchLocationsStatusButton = createImageButton(Icons.REFRESH_ICON, "Refresh Status",
|
||||
ButtonPanelFactory.ARROW_SIZE);
|
||||
refreshSearchLocationsStatusButton =
|
||||
createImageButton(Icons.REFRESH_ICON, "Refresh Status", ButtonPanelFactory.ARROW_SIZE);
|
||||
refreshSearchLocationsStatusButton.addActionListener(e -> refreshSearchLocationStatus());
|
||||
DockingWindowManager.getHelpService()
|
||||
.registerHelp(refreshSearchLocationsStatusButton,
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
||||
"SymbolServerConfig Refresh Status"));
|
||||
.registerHelp(refreshSearchLocationsStatusButton, new HelpLocation(
|
||||
PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Refresh Status"));
|
||||
|
||||
moveLocationUpButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_UP_TYPE);
|
||||
moveLocationUpButton.addActionListener(e -> moveLocation(-1));
|
||||
moveLocationUpButton.setToolTipText("Move location up");
|
||||
DockingWindowManager.getHelpService()
|
||||
.registerHelp(moveLocationUpButton,
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
||||
"SymbolServerConfig MoveUpDown"));
|
||||
.registerHelp(moveLocationUpButton, new HelpLocation(
|
||||
PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig MoveUpDown"));
|
||||
|
||||
moveLocationDownButton =
|
||||
ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_DOWN_TYPE);
|
||||
moveLocationDownButton.addActionListener(e -> moveLocation(1));
|
||||
moveLocationDownButton.setToolTipText("Move location down");
|
||||
DockingWindowManager.getHelpService()
|
||||
.registerHelp(moveLocationDownButton,
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
||||
"SymbolServerConfig MoveUpDown"));
|
||||
.registerHelp(moveLocationDownButton, new HelpLocation(
|
||||
PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig MoveUpDown"));
|
||||
|
||||
deleteLocationButton = createImageButton(Icons.DELETE_ICON, "Delete",
|
||||
ButtonPanelFactory.ARROW_SIZE);
|
||||
deleteLocationButton =
|
||||
createImageButton(Icons.DELETE_ICON, "Delete", ButtonPanelFactory.ARROW_SIZE);
|
||||
deleteLocationButton.addActionListener(e -> deleteLocation());
|
||||
DockingWindowManager.getHelpService()
|
||||
.registerHelp(deleteLocationButton,
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
||||
"SymbolServerConfig Delete"));
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Delete"));
|
||||
|
||||
addLocationButton = createImageButton(Icons.ADD_ICON, "Add",
|
||||
ButtonPanelFactory.ARROW_SIZE);
|
||||
addLocationButton = createImageButton(Icons.ADD_ICON, "Add", ButtonPanelFactory.ARROW_SIZE);
|
||||
addLocationButton.addActionListener(e -> addLocation());
|
||||
DockingWindowManager.getHelpService()
|
||||
.registerHelp(addLocationButton,
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
||||
"SymbolServerConfig Add"));
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Add"));
|
||||
|
||||
saveSearchLocationsButton =
|
||||
ButtonPanelFactory.createImageButton(Icons.get("images/disk.png"),
|
||||
"Save Configuration", ButtonPanelFactory.ARROW_SIZE);
|
||||
saveSearchLocationsButton = ButtonPanelFactory.createImageButton(
|
||||
Icons.get("images/disk.png"), "Save Configuration", ButtonPanelFactory.ARROW_SIZE);
|
||||
saveSearchLocationsButton.addActionListener(e -> saveConfig());
|
||||
DockingWindowManager.getHelpService()
|
||||
.registerHelp(saveSearchLocationsButton,
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
||||
"SymbolServerConfig Save"));
|
||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Save"));
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
|
||||
@ -325,8 +314,7 @@ class SymbolServerPanel extends JPanel {
|
||||
}
|
||||
|
||||
if (allowGUIPrompt && isEmptyDirectory(symbolStorageDir)) {
|
||||
if (OptionDialog.showYesNoDialog(this,
|
||||
"Initialize Symbol Storage Directory?",
|
||||
if (OptionDialog.showYesNoDialog(this, "Initialize Symbol Storage Directory?",
|
||||
"<html>Initialize new directory as Microsoft symbol storage directory?") == OptionDialog.YES_OPTION) {
|
||||
try {
|
||||
LocalSymbolStore.create(symbolStorageDir,
|
||||
@ -495,8 +483,8 @@ class SymbolServerPanel extends JPanel {
|
||||
}
|
||||
|
||||
private void addDirectoryLocation() {
|
||||
File dir = FilePromptDialog.chooseDirectory("Enter Path", "Symbol Storage Location: ",
|
||||
null);
|
||||
File dir =
|
||||
FilePromptDialog.chooseDirectory("Enter Path", "Symbol Storage Location: ", null);
|
||||
if (dir == null) {
|
||||
return;
|
||||
}
|
||||
@ -574,7 +562,7 @@ class SymbolServerPanel extends JPanel {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static JButton createImageButton(ImageIcon buttonIcon, String alternateText,
|
||||
private static JButton createImageButton(Icon buttonIcon, String alternateText,
|
||||
Dimension preferredSize) {
|
||||
|
||||
JButton button = ButtonPanelFactory.createButton("");
|
||||
@ -584,7 +572,7 @@ class SymbolServerPanel extends JPanel {
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
static StatusText getSymbolServerWarnings(List<SymbolServer> symbolServers) {
|
||||
Map<String, String> warningsByLocation = new HashMap<>();
|
||||
for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) {
|
||||
@ -592,8 +580,7 @@ class SymbolServerPanel extends JPanel {
|
||||
warningsByLocation.put(ssloc.getLocation(), ssloc.getWarning());
|
||||
}
|
||||
}
|
||||
String warning = symbolServers
|
||||
.stream()
|
||||
String warning = symbolServers.stream()
|
||||
.map(symbolServer -> warningsByLocation.get(symbolServer.getName()))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
|
@ -52,8 +52,8 @@ public class DiffDetailsProvider extends ComponentProviderAdapter {
|
||||
public static final String FILTER_DIFFS_CHECK_BOX = "Filter Diffs Check Box";
|
||||
public static final String DIFF_DETAILS_TEXT_AREA = "Diff Details Text Area";
|
||||
public static final String DIFF_DETAILS_PANEL = "Diff Location Details Panel";
|
||||
public static final ImageIcon ICON = ResourceManager.loadImage("images/xmag.png");
|
||||
public static final ImageIcon REFRESH_ICON = Icons.REFRESH_ICON;
|
||||
public static final Icon ICON = ResourceManager.loadImage("images/xmag.png");
|
||||
public static final Icon REFRESH_ICON = Icons.REFRESH_ICON;
|
||||
public static final String TITLE = "Diff Details";
|
||||
|
||||
private ProgramDiffPlugin plugin;
|
||||
@ -121,8 +121,8 @@ public class DiffDetailsProvider extends ComponentProviderAdapter {
|
||||
refreshDetailsAction.setEnabled(true);
|
||||
|
||||
refreshDetailsAction.setToolBarData(new ToolBarData(REFRESH_ICON, "Diff"));
|
||||
refreshDetailsAction.setHelpLocation(
|
||||
new HelpLocation(HelpTopics.DIFF, "Refresh Diff Details"));
|
||||
refreshDetailsAction
|
||||
.setHelpLocation(new HelpLocation(HelpTopics.DIFF, "Refresh Diff Details"));
|
||||
plugin.getTool().addLocalAction(this, refreshDetailsAction);
|
||||
// plugin.getTool().addLocalAction(this, new DiffIgnoreAllAction(this));
|
||||
}
|
||||
|
@ -43,6 +43,34 @@ color.bg.fieldpanel.selection = color.bg.selection
|
||||
color.bg.fieldpanel.highlight = color.bg.highlight
|
||||
color.bg.fieldpanel.selection-highlight = green
|
||||
|
||||
// Icons file
|
||||
icon.empty = images/EmptyIcon16.gif
|
||||
icon.help = images/help-browser.png
|
||||
icon.add = images/Plus2.png
|
||||
icon.collapse.all = images/collapse_all.png
|
||||
icon.expand.all = images/expand_all.png
|
||||
icon.configure.filter = images/exec.png
|
||||
icon.delete = images/error.png
|
||||
icon.error = images/emblem-important.png
|
||||
icon.navigate.in = images/locationIn.gif
|
||||
icon.navigate.out = images/locationOut.gif
|
||||
icon.notallowed = images/dialog-cancel.png
|
||||
icon.folder.open = images/openSmallFolder.png
|
||||
icon.refresh = images/reload3.png
|
||||
icon.sort.ascending = images/sortascending.png
|
||||
icon.sort.descending = images/process-stop.png
|
||||
icon.stop = images/process-stop.png
|
||||
icon.warning.strong = images/software-update-urgent.png
|
||||
icon.left = images/left.png
|
||||
icon.right = images/right.png
|
||||
icon.left.alt = images/left.alternate.png
|
||||
icon.right.alt = images/right.alternate.png
|
||||
icon.saveas = images/disk.png
|
||||
icon.makeselection = images/text_align_justify.png
|
||||
icon.arrow.up.right = images/viewmagfit.png
|
||||
icon.flag = images/flag.png
|
||||
icon.lock = images/kgpg.png
|
||||
icon.checkmark.green = images/checkmark_green.gif
|
||||
|
||||
|
||||
[Dark Defaults]
|
||||
|
@ -29,7 +29,9 @@ import docking.DockingWindowManager;
|
||||
import docking.widgets.label.GDHtmlLabel;
|
||||
|
||||
/**
|
||||
* Color editor that uses the JColorChooser.
|
||||
* Color editor that is a bit unusual in that its custom component is a button that when pushed,
|
||||
* pops up a dialog for editing the color. Use {@link ColorPropertyEditor} for a more traditional
|
||||
* property editor that returns a direct color editing component.
|
||||
*/
|
||||
public class ColorEditor extends PropertyEditorSupport {
|
||||
|
||||
@ -42,10 +44,6 @@ public class ColorEditor extends PropertyEditorSupport {
|
||||
private Color color;
|
||||
private Color lastUserSelectedColor;
|
||||
|
||||
/**
|
||||
* The default constructor.
|
||||
*
|
||||
*/
|
||||
public ColorEditor() {
|
||||
previewLabel.setOpaque(true);
|
||||
previewLabel.setPreferredSize(new Dimension(100, 20));
|
||||
@ -72,42 +70,16 @@ public class ColorEditor extends PropertyEditorSupport {
|
||||
DockingWindowManager.showDialog(previewLabel, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* A PropertyEditor may chose to make available a full custom Component
|
||||
* that edits its property value. It is the responsibility of the
|
||||
* PropertyEditor to hook itself up to its editor Component itself and
|
||||
* to report property value changes by firing a PropertyChange event.
|
||||
* <P>
|
||||
* The higher-level code that calls getCustomEditor may either embed
|
||||
* the Component in some larger property sheet, or it may put it in
|
||||
* its own individual dialog, or ...
|
||||
*
|
||||
* @return A java.awt.Component that will allow a human to directly
|
||||
* edit the current property value. May be null if this is
|
||||
* not supported.
|
||||
*/
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return previewLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the propertyEditor can provide a custom editor.
|
||||
*
|
||||
* @return True if the propertyEditor can provide a custom editor.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set (or change) the object that is to be edited.
|
||||
* @param value The new target object to be edited. Note that this
|
||||
* object should not be modified by the PropertyEditor, rather
|
||||
* the PropertyEditor should create a new object to hold any
|
||||
* modified value.
|
||||
*/
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
color = (Color) value;
|
||||
@ -130,33 +102,16 @@ public class ColorEditor extends PropertyEditorSupport {
|
||||
previewLabel.setBackground(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value.
|
||||
*/
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true which this editor can paint its property value.
|
||||
*/
|
||||
@Override
|
||||
public boolean isPaintable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint a representation of the value into a given area of screen
|
||||
* real estate. Note that the propertyEditor is responsible for doing
|
||||
* its own clipping so that it fits into the given rectangle.
|
||||
* <p>
|
||||
* If the PropertyEditor doesn't honor paint requests (see isPaintable)
|
||||
* this method should be a silent noop.
|
||||
*
|
||||
* @param gfx Graphics object to paint into.
|
||||
* @param box Rectangle within graphics object into which we should paint.
|
||||
*/
|
||||
@Override
|
||||
public void paintValue(Graphics gfx, Rectangle box) {
|
||||
if (color != null) {
|
||||
|
@ -0,0 +1,57 @@
|
||||
/* ###
|
||||
* 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.options.editor;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.util.Swing;
|
||||
|
||||
/**
|
||||
* Property Editor for Colors. Uses a {@link GhidraColorChooser} as its custom component
|
||||
*/
|
||||
public class ColorPropertyEditor extends PropertyEditorSupport {
|
||||
private GhidraColorChooser colorChooser;
|
||||
|
||||
private void colorChanged() {
|
||||
// run later - allows debugging without hanging amazon aws
|
||||
Swing.runLater(() -> setValue(colorChooser.getColor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
colorChooser = new GhidraColorChooser();
|
||||
colorChooser.getSelectionModel().addChangeListener(e -> colorChanged());
|
||||
return colorChooser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
if (colorChooser != null) {
|
||||
colorChooser.setColor((Color) value);
|
||||
}
|
||||
if (!Objects.equals(value, getValue())) {
|
||||
super.setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -31,7 +30,7 @@ public class EditorInitializer implements ModuleInitializer {
|
||||
public void run() {
|
||||
PropertyEditorManager.registerEditor(String.class, StringEditor.class);
|
||||
PropertyEditorManager.registerEditor(Color.class, ColorEditor.class);
|
||||
PropertyEditorManager.registerEditor(Font.class, FontPropertyEditor.class);
|
||||
PropertyEditorManager.registerEditor(Font.class, FontEditor.class);
|
||||
PropertyEditorManager.registerEditor(Enum.class, EnumEditor.class);
|
||||
PropertyEditorManager.registerEditor(Boolean.class, BooleanEditor.class);
|
||||
PropertyEditorManager.registerEditor(Date.class, DateEditor.class);
|
||||
|
@ -0,0 +1,111 @@
|
||||
/* ###
|
||||
* 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.options.editor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
|
||||
/**
|
||||
* Font property editor that is a bit unusual in that its custom component is a button that when
|
||||
* pushed, pops up a dialog for editing the color. Use {@link FontPropertyEditor} for a more
|
||||
* traditional property editor that returns a direct color editing component.
|
||||
*/
|
||||
|
||||
public class FontEditor extends PropertyEditorSupport {
|
||||
private JButton previewButton;
|
||||
private FontPropertyEditor fontPropertyEditor;
|
||||
|
||||
public FontEditor() {
|
||||
previewButton = new JButton(FontPropertyEditor.SAMPLE_STRING);
|
||||
previewButton.addActionListener(e -> buttonPushed());
|
||||
fontPropertyEditor = new FontPropertyEditor();
|
||||
fontPropertyEditor.addPropertyChangeListener(ev -> fontChanged());
|
||||
}
|
||||
|
||||
private void buttonPushed() {
|
||||
showDialog();
|
||||
previewButton.setFont((Font) getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for directly showing a dialog for editing fonts
|
||||
*/
|
||||
public void showDialog() {
|
||||
EditorDialogProvider provider = new EditorDialogProvider();
|
||||
DockingWindowManager.showDialog(previewButton, provider);
|
||||
previewButton.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object o) {
|
||||
if (Objects.equals(o, getValue())) {
|
||||
return;
|
||||
}
|
||||
Font font = (Font) o;
|
||||
previewButton.setFont(font);
|
||||
fontPropertyEditor.setValue(font);
|
||||
super.setValue(font);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return previewButton;
|
||||
}
|
||||
|
||||
private void fontChanged() {
|
||||
Font font = (Font) fontPropertyEditor.getValue();
|
||||
setValue(font);
|
||||
}
|
||||
|
||||
class EditorDialogProvider extends DialogComponentProvider {
|
||||
private Font originalFont = (Font) getValue();
|
||||
|
||||
EditorDialogProvider() {
|
||||
super("Font Editor", true);
|
||||
addWorkPanel(buildWorkPanel());
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
}
|
||||
|
||||
private JComponent buildWorkPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(fontPropertyEditor.getCustomEditor());
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
setValue(originalFont);
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,74 +16,33 @@
|
||||
package docking.options.editor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.combobox.GComboBox;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
/**
|
||||
* This Bean FontEditor displays a String with the current selected font name,
|
||||
* style and size attributes.
|
||||
* Property Editor for editing {@link Font}s
|
||||
*/
|
||||
public class FontPropertyEditor extends PropertyEditorSupport {
|
||||
private Font font;
|
||||
// private JLabel previewLabel = new GDLabel();
|
||||
private final static String SAMPLE_STRING = "ABCabc \u00a9\u00ab\u00a7\u0429\u05d1\u062c\u4eb9";
|
||||
private JButton previewButton = new JButton(SAMPLE_STRING);
|
||||
public final static String SAMPLE_STRING = "ABCabc \u00a9\u00ab\u00a7\u0429\u05d1\u062c\u4eb9";
|
||||
|
||||
/**
|
||||
* The default constructor.
|
||||
*
|
||||
*/
|
||||
public FontPropertyEditor() {
|
||||
|
||||
previewButton.addActionListener(e -> {
|
||||
// show the editor to get the user value
|
||||
showDialog();
|
||||
|
||||
// now set the new value
|
||||
previewButton.setFont(font);
|
||||
});
|
||||
|
||||
// previewLabel.addMouseListener( new MouseAdapter() {
|
||||
// @Override
|
||||
// public void mouseClicked( MouseEvent evt ) {
|
||||
// // show the editor to get the user value
|
||||
// showDialog();
|
||||
//
|
||||
// // now set the new value
|
||||
// previewLabel.setFont( font );
|
||||
// }
|
||||
// } );
|
||||
}
|
||||
|
||||
public void showDialog() {
|
||||
EditorProvider provider = new EditorProvider(new FontPanel());
|
||||
DockingWindowManager.showDialog(previewButton, provider);
|
||||
previewButton.repaint();
|
||||
}
|
||||
private FontChooserPanel fontChooserPanel;
|
||||
|
||||
@Override
|
||||
public void setValue(Object o) {
|
||||
font = (Font) o;
|
||||
previewButton.setFont(font);
|
||||
|
||||
// set the font values on the widget
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return font;
|
||||
public Component getCustomEditor() {
|
||||
fontChooserPanel = new FontChooserPanel();
|
||||
fontChooserPanel.updateControls((Font) getValue());
|
||||
return fontChooserPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -92,205 +51,204 @@ public class FontPropertyEditor extends PropertyEditorSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return previewButton;
|
||||
public void setValue(Object value) {
|
||||
if (fontChooserPanel != null) {
|
||||
fontChooserPanel.updateControls((Font) value);
|
||||
}
|
||||
if (!Objects.equals(value, getValue())) {
|
||||
super.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
class FontChooserPanel extends JPanel {
|
||||
|
||||
private class FontPanel extends JPanel implements ActionListener {
|
||||
JLabel fontLabel, sizeLabel, styleLabel;
|
||||
JLabel fontStringLabel;
|
||||
JComboBox<FontWrapper> fonts;
|
||||
JComboBox<Integer> sizes;
|
||||
JComboBox<String> styles;
|
||||
int styleChoice;
|
||||
int sizeChoice;
|
||||
private GDLabel previewLabel;
|
||||
private GComboBox<FontWrapper> fontCombo;
|
||||
private GComboBox<Integer> sizeCombo;
|
||||
private GComboBox<String> styleCombo;
|
||||
private ActionListener actionListener = e -> fontChanged();
|
||||
|
||||
FontPanel() {
|
||||
init();
|
||||
public FontChooserPanel() {
|
||||
build();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
this.setLayout(new BorderLayout());
|
||||
public void updateControls(Font font) {
|
||||
if (font == null) {
|
||||
return;
|
||||
}
|
||||
updatePreviewLabel(font);
|
||||
|
||||
JPanel topPanel = new JPanel();
|
||||
JPanel fontPanel = new JPanel();
|
||||
JPanel sizePanel = new JPanel();
|
||||
JPanel stylePanel = new JPanel();
|
||||
JPanel sizeAndStylePanel = new JPanel();
|
||||
fontCombo.removeActionListener(actionListener);
|
||||
sizeCombo.removeActionListener(actionListener);
|
||||
styleCombo.removeActionListener(actionListener);
|
||||
|
||||
topPanel.setLayout(new BorderLayout());
|
||||
fontPanel.setLayout(new GridLayout(2, 1));
|
||||
sizePanel.setLayout(new GridLayout(2, 1));
|
||||
stylePanel.setLayout(new GridLayout(2, 1));
|
||||
sizeAndStylePanel.setLayout(new BorderLayout());
|
||||
FontWrapper fontWrapper = new FontWrapper(font.getName());
|
||||
int styleChoice = font.getStyle();
|
||||
int size = font.getSize();
|
||||
|
||||
topPanel.add(BorderLayout.WEST, fontPanel);
|
||||
sizeAndStylePanel.add(BorderLayout.WEST, sizePanel);
|
||||
sizeAndStylePanel.add(BorderLayout.CENTER, stylePanel);
|
||||
topPanel.add(BorderLayout.CENTER, sizeAndStylePanel);
|
||||
fontCombo.setSelectedItem(fontWrapper);
|
||||
sizeCombo.setSelectedItem(size);
|
||||
styleCombo.setSelectedIndex(styleChoice);
|
||||
|
||||
fontStringLabel = new GDLabel(FontPropertyEditor.SAMPLE_STRING);
|
||||
fontStringLabel.setPreferredSize(new Dimension(350, 50));
|
||||
fontStringLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
fontStringLabel.setFont(font);
|
||||
topPanel.add(BorderLayout.SOUTH, fontStringLabel);
|
||||
fontCombo.addActionListener(actionListener);
|
||||
sizeCombo.addActionListener(actionListener);
|
||||
styleCombo.addActionListener(actionListener);
|
||||
|
||||
add(BorderLayout.NORTH, topPanel);
|
||||
}
|
||||
|
||||
fontLabel = new GDLabel("Fonts");
|
||||
Font newFont = getFont().deriveFont(1);
|
||||
fontLabel.setFont(newFont);
|
||||
fontLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
fontPanel.add(fontLabel);
|
||||
private void build() {
|
||||
setLayout(new BorderLayout());
|
||||
add(buildTopPanel(), BorderLayout.NORTH);
|
||||
add(buildPreviewLabel(), BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
sizeLabel = new GDLabel("Sizes");
|
||||
sizeLabel.setFont(newFont);
|
||||
sizeLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
sizePanel.add(sizeLabel);
|
||||
private Component buildTopPanel() {
|
||||
JPanel panel = new JPanel(new FlowLayout(SwingConstants.CENTER, 10, 0));
|
||||
panel.add(buildFontPanel());
|
||||
panel.add(buildSizePanel());
|
||||
panel.add(buildStylePanel());
|
||||
return panel;
|
||||
}
|
||||
|
||||
styleLabel = new GDLabel("Styles");
|
||||
styleLabel.setFont(newFont);
|
||||
private Component buildPreviewLabel() {
|
||||
previewLabel = new GDLabel(SAMPLE_STRING);
|
||||
previewLabel.setPreferredSize(new Dimension(350, 50));
|
||||
previewLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
previewLabel.setVerticalAlignment(SwingConstants.CENTER);
|
||||
previewLabel.setMinimumSize(new Dimension(300, 50));
|
||||
return previewLabel;
|
||||
}
|
||||
|
||||
private Component buildStylePanel() {
|
||||
JPanel panel = new JPanel(new GridLayout(2, 1));
|
||||
|
||||
GDLabel styleLabel = new GDLabel("Styles");
|
||||
styleLabel.setFont(getFont().deriveFont(1));
|
||||
styleLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
stylePanel.add(styleLabel);
|
||||
panel.add(styleLabel);
|
||||
|
||||
styleCombo =
|
||||
new GComboBox<>(new String[] { "PLAIN", "BOLD", "ITALIC", "BOLD & ITALIC" });
|
||||
styleCombo.setMaximumRowCount(9);
|
||||
styleCombo.addActionListener(actionListener);
|
||||
panel.add(styleCombo);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private Component buildSizePanel() {
|
||||
JPanel panel = new JPanel(new GridLayout(2, 1));
|
||||
|
||||
GDLabel sizeLabel = new GDLabel("Sizes");
|
||||
sizeLabel.setFont(getFont().deriveFont(1));
|
||||
sizeLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
panel.add(sizeLabel);
|
||||
|
||||
sizeCombo =
|
||||
new GComboBox<>(IntStream.rangeClosed(1, 72).boxed().toArray(Integer[]::new));
|
||||
sizeCombo.setMaximumRowCount(9);
|
||||
sizeCombo.setMaximumRowCount(9);
|
||||
sizeCombo.addActionListener(actionListener);
|
||||
panel.add(sizeCombo);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private Component buildFontPanel() {
|
||||
JPanel panel = new JPanel(new GridLayout(2, 1));
|
||||
|
||||
GDLabel fontLabel = new GDLabel("Fonts");
|
||||
fontLabel.setFont(getFont().deriveFont(1));
|
||||
fontLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
panel.add(fontLabel);
|
||||
|
||||
GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
Stream<String> stream = Arrays.stream(gEnv.getAvailableFontFamilyNames());
|
||||
FontWrapper[] array = stream.map(s -> new FontWrapper(s)).toArray(FontWrapper[]::new);
|
||||
Arrays.sort(array);
|
||||
|
||||
String envfonts[] = gEnv.getAvailableFontFamilyNames();
|
||||
List<FontWrapper> list = new ArrayList<>(envfonts.length);
|
||||
for (String envfont : envfonts) {
|
||||
list.add(new FontWrapper(envfont));
|
||||
}
|
||||
Collections.sort(list);
|
||||
fonts = new GComboBox<>(list.toArray(new FontWrapper[envfonts.length]));
|
||||
fonts.setMaximumRowCount(9);
|
||||
FontWrapper fontWrapper = new FontWrapper(font.getName());
|
||||
fontPanel.add(fonts);
|
||||
fonts.setSelectedItem(fontWrapper);
|
||||
fontCombo = new GComboBox<>(array);
|
||||
fontCombo.setMaximumRowCount(9);
|
||||
fontCombo.addActionListener(actionListener);
|
||||
panel.add(fontCombo);
|
||||
|
||||
sizes = new GComboBox<>(IntStream.rangeClosed(1, 72).boxed().toArray(Integer[]::new));
|
||||
sizes.setMaximumRowCount(9);
|
||||
sizePanel.add(sizes);
|
||||
sizeChoice = font.getSize();
|
||||
sizes.setSelectedItem(sizeChoice);
|
||||
sizes.setMaximumRowCount(9);
|
||||
|
||||
styles = new GComboBox<>(new String[] { "PLAIN", "BOLD", "ITALIC", "BOLD & ITALIC" });
|
||||
styles.setMaximumRowCount(9);
|
||||
stylePanel.add(styles);
|
||||
styleChoice = font.getStyle();
|
||||
styles.setSelectedIndex(styleChoice);
|
||||
fonts.addActionListener(this);
|
||||
styles.addActionListener(this);
|
||||
sizes.addActionListener(this);
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
// get values of panels
|
||||
// set the editors new font
|
||||
Object list = event.getSource();
|
||||
private void fontChanged() {
|
||||
FontWrapper fontWrapper = (FontWrapper) fontCombo.getSelectedItem();
|
||||
String fontNameChoice = fontWrapper.getFontName();
|
||||
int styleChoice = styleCombo.getSelectedIndex();
|
||||
int sizeChoice = (Integer) sizeCombo.getSelectedItem();
|
||||
Font font = new Font(fontNameChoice, styleChoice, sizeChoice);
|
||||
updatePreviewLabel(font);
|
||||
// allows debugging without hanging amazon aws
|
||||
Swing.runLater(() -> setValue(font));
|
||||
}
|
||||
|
||||
String fontNameChoice = font.getName();
|
||||
if (list == fonts) {
|
||||
FontWrapper fontWrapper = (FontWrapper) fonts.getSelectedItem();
|
||||
fontNameChoice = fontWrapper.getFontName();
|
||||
}
|
||||
else if (list == styles) {
|
||||
styleChoice = styles.getSelectedIndex();
|
||||
}
|
||||
else {
|
||||
sizeChoice = (Integer) sizes.getSelectedItem();
|
||||
}
|
||||
|
||||
font = new Font(fontNameChoice, styleChoice, sizeChoice);
|
||||
fontStringLabel.setFont(font);
|
||||
FontMetrics fm = fontStringLabel.getFontMetrics(font);
|
||||
private void updatePreviewLabel(Font font) {
|
||||
previewLabel.setFont(font);
|
||||
FontMetrics fm = previewLabel.getFontMetrics(font);
|
||||
int height = fm.getHeight();
|
||||
Dimension d = fontStringLabel.getSize();
|
||||
Dimension d = previewLabel.getSize();
|
||||
if (d.height < height) {
|
||||
d = new Dimension(d.width, height);
|
||||
fontStringLabel.setPreferredSize(d);
|
||||
previewLabel.setPreferredSize(d);
|
||||
}
|
||||
fontStringLabel.invalidate();
|
||||
previewLabel.invalidate();
|
||||
|
||||
setValue(font);
|
||||
FontPropertyEditor.this.firePropertyChange();
|
||||
}
|
||||
|
||||
// A wrapper class created so that the names of fonts are comparable ignoring case
|
||||
private class FontWrapper implements Comparable<FontWrapper> {
|
||||
private final String fontName;
|
||||
|
||||
private FontWrapper(String fontName) {
|
||||
this.fontName = fontName;
|
||||
}
|
||||
|
||||
private String getFontName() {
|
||||
return fontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FontWrapper otherWrapper = (FontWrapper) obj;
|
||||
return fontName.toLowerCase().equals(otherWrapper.fontName.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result =
|
||||
prime * result + ((fontName == null) ? 0 : fontName.toLowerCase().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FontWrapper otherWrapper) {
|
||||
return fontName.compareToIgnoreCase(otherWrapper.fontName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EditorProvider extends DialogComponentProvider {
|
||||
private Font originalFont = font;
|
||||
|
||||
EditorProvider(JPanel contentPanel) {
|
||||
super("Font Editor", true);
|
||||
|
||||
addWorkPanel(contentPanel);
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
font = originalFont;
|
||||
super.cancelCallback();
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper class created so that the names of fonts are comparable ignoring case
|
||||
private class FontWrapper implements Comparable<FontWrapper> {
|
||||
private final String fontName;
|
||||
|
||||
private FontWrapper(String fontName) {
|
||||
this.fontName = fontName;
|
||||
}
|
||||
|
||||
private String getFontName() {
|
||||
return fontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FontWrapper otherWrapper = (FontWrapper) obj;
|
||||
return fontName.toLowerCase().equals(otherWrapper.fontName.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((fontName == null) ? 0 : fontName.toLowerCase().hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FontWrapper otherWrapper) {
|
||||
return fontName.compareToIgnoreCase(otherWrapper.fontName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,249 @@
|
||||
/* ###
|
||||
* 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.options.editor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.theme.gui.ProtectedIcon;
|
||||
import docking.widgets.*;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.list.GListCellRenderer;
|
||||
import resources.ResourceManager;
|
||||
import resources.icons.ScaledImageIcon;
|
||||
import resources.icons.UrlImageIcon;
|
||||
|
||||
public class IconPropertyEditor extends PropertyEditorSupport {
|
||||
private IconChooserPanel iconChooserPanel;
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
iconChooserPanel = new IconChooserPanel();
|
||||
return iconChooserPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
if (iconChooserPanel != null) {
|
||||
iconChooserPanel.setSelectedIcon((Icon) value);
|
||||
}
|
||||
doSetValue(value);
|
||||
}
|
||||
|
||||
private void doSetValue(Object value) {
|
||||
if (!Objects.equals(value, getValue())) {
|
||||
super.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private String iconToString(Icon icon) {
|
||||
if (icon instanceof UrlImageIcon urlIcon) {
|
||||
return urlIcon.getOriginalPath();
|
||||
}
|
||||
return "<Default>";
|
||||
}
|
||||
|
||||
class IconChooserPanel extends JPanel {
|
||||
|
||||
private GDLabel previewLabel;
|
||||
private DropDownSelectionTextField<Icon> dropDown;
|
||||
private IconDropDownDataModel dataModel;
|
||||
DropDownSelectionChoiceListener<Icon> choiceListener = t -> iconChanged(t);
|
||||
|
||||
public IconChooserPanel() {
|
||||
build();
|
||||
}
|
||||
|
||||
public void setSelectedIcon(Icon icon) {
|
||||
if (icon == null) {
|
||||
return;
|
||||
}
|
||||
if (!(icon instanceof UrlImageIcon)) {
|
||||
icon = new ProtectedIcon(icon);
|
||||
}
|
||||
updateDropDownDataModel(icon);
|
||||
updatePreviewLabel(icon);
|
||||
|
||||
// iconTextField.addActionListener(listener);
|
||||
|
||||
}
|
||||
|
||||
private void updateDropDownDataModel(Icon icon) {
|
||||
Set<Icon> icons = ResourceManager.getLoadedUrlIcons();
|
||||
icons.add(icon);
|
||||
dataModel.setData(new ArrayList<>(icons));
|
||||
dropDown.setSelectedValue(icon);
|
||||
}
|
||||
|
||||
private void build() {
|
||||
setLayout(new BorderLayout());
|
||||
add(buildTopPanel(), BorderLayout.NORTH);
|
||||
add(buildPreviewLabel(), BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private Component buildTopPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
dataModel = new IconDropDownDataModel();
|
||||
dropDown = new DropDownSelectionTextField<>(dataModel) {
|
||||
protected List<Icon> getMatchingData(String searchText) {
|
||||
if (searchText.isBlank()) {
|
||||
return ((IconDropDownDataModel) dataModel).getData();
|
||||
}
|
||||
return super.getMatchingData(searchText);
|
||||
}
|
||||
};
|
||||
// dropDown.setConsumeEnterKeyPress(false);
|
||||
// dropDown.addActionListener(e -> iconChanged());
|
||||
dropDown.addDropDownSelectionChoiceListener(choiceListener);
|
||||
// dropDown.addCellEditorListener(new CellEditorListener() {
|
||||
//
|
||||
// @Override
|
||||
// public void editingStopped(ChangeEvent e) {
|
||||
// Msg.debug(this, "Stopped");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void editingCanceled(ChangeEvent e) {
|
||||
// Msg.debug(this, "Cancelled");
|
||||
//
|
||||
// }
|
||||
// });
|
||||
panel.add(dropDown, BorderLayout.CENTER);
|
||||
// JButton browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE);
|
||||
// panel.add(browseButton, BorderLayout.EAST);
|
||||
// browseButton.addActionListener(e -> browse());
|
||||
// iconTextField.addActionListener(listener);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
// private void iconChanged() {
|
||||
// Icon icon = dropDown.getSelectedValue();
|
||||
// Msg.debug(this, "action listener: icon changed " + icon);
|
||||
// dropDown.getSelectedValue();
|
||||
// }
|
||||
|
||||
private void iconChanged(Icon icon) {
|
||||
boolean isDropDownWindowShowing = dropDown.isMatchingListShowing();
|
||||
if (!isDropDownWindowShowing) {
|
||||
updatePreviewLabel(icon);
|
||||
doSetValue(icon);
|
||||
}
|
||||
}
|
||||
|
||||
private void browse() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
private Component buildPreviewLabel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
|
||||
previewLabel = new GDLabel("");
|
||||
previewLabel.setIcon(ResourceManager.getDefaultIcon());
|
||||
// previewLabel.setPreferredSize(new Dimension(350, 50));
|
||||
previewLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
previewLabel.setVerticalAlignment(SwingConstants.CENTER);
|
||||
// previewLabel.setMinimumSize(new Dimension(300, 50));
|
||||
panel.add(previewLabel, BorderLayout.CENTER);
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void updatePreviewLabel(Icon icon) {
|
||||
previewLabel.setIcon(icon);
|
||||
int height = icon.getIconHeight();
|
||||
int width = icon.getIconWidth();
|
||||
Dimension d = previewLabel.getSize();
|
||||
height = Math.max(d.height, height);
|
||||
width = Math.max(d.width, width);
|
||||
previewLabel.setPreferredSize(new Dimension(width, height));
|
||||
previewLabel.invalidate();
|
||||
iconChooserPanel.validate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class IconDropDownDataModel extends DefaultDropDownSelectionDataModel<Icon> {
|
||||
IconListCellRender renderer = new IconListCellRender();
|
||||
|
||||
public IconDropDownDataModel() {
|
||||
super(Collections.emptyList(), IconPropertyEditor.this::iconToString);
|
||||
}
|
||||
|
||||
List<Icon> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void setData(List<Icon> icons) {
|
||||
Collections.sort(icons, comparator);
|
||||
data = icons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Icon> getMatchingData(String searchText) {
|
||||
if (searchText.isBlank()) {
|
||||
return data;
|
||||
}
|
||||
searchText = searchText.toLowerCase();
|
||||
List<Icon> results = new ArrayList<>();
|
||||
for (Icon icon : data) {
|
||||
String name = iconToString(icon);
|
||||
if (name.toLowerCase().contains(searchText)) {
|
||||
results.add(icon);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListCellRenderer<Icon> getListRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class IconListCellRender extends GListCellRenderer<Icon> {
|
||||
@Override
|
||||
protected String getItemText(Icon icon) {
|
||||
return iconToString(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends Icon> list, Icon icon,
|
||||
int index, boolean isSelected, boolean hasFocus) {
|
||||
JLabel label = (JLabel) super.getListCellRendererComponent(list, icon, index,
|
||||
isSelected, hasFocus);
|
||||
|
||||
if (icon.getIconWidth() != 16 || icon.getIconHeight() != 16) {
|
||||
icon = new ScaledImageIcon(icon, 16, 16);
|
||||
}
|
||||
label.setIcon(icon);
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -21,7 +21,10 @@ import java.io.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import ghidra.util.WebColors;
|
||||
import resources.icons.UrlImageIcon;
|
||||
|
||||
public class FileGTheme extends GTheme {
|
||||
public static final String FILE_PREFIX = "File:";
|
||||
@ -117,7 +120,15 @@ public class FileGTheme extends GTheme {
|
||||
if (iconValue.getReferenceId() != null) {
|
||||
return iconValue.toExternalId(iconValue.getReferenceId());
|
||||
}
|
||||
return iconValue.getRawValue();
|
||||
Icon icon = iconValue.getRawValue();
|
||||
return iconToString(icon);
|
||||
}
|
||||
|
||||
public static String iconToString(Icon icon) {
|
||||
if (icon instanceof UrlImageIcon urlIcon) {
|
||||
return urlIcon.getOriginalPath();
|
||||
}
|
||||
return "<UNKNOWN>";
|
||||
}
|
||||
|
||||
private String getValueOutput(FontValue fontValue) {
|
||||
@ -125,10 +136,14 @@ public class FileGTheme extends GTheme {
|
||||
return fontValue.toExternalId(fontValue.getReferenceId());
|
||||
}
|
||||
Font font = fontValue.getRawValue();
|
||||
return fontToString(font);
|
||||
}
|
||||
|
||||
public static String fontToString(Font font) {
|
||||
return String.format("%s-%s-%s", font.getName(), getStyleString(font), font.getSize());
|
||||
}
|
||||
|
||||
private String getStyleString(Font font) {
|
||||
private static String getStyleString(Font font) {
|
||||
boolean bold = font.isBold();
|
||||
boolean italic = font.isItalic();
|
||||
if (bold && italic) {
|
||||
|
@ -1,323 +0,0 @@
|
||||
/* ###
|
||||
* 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.theme;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.font.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.text.AttributedCharacterIterator.Attribute;
|
||||
import java.text.CharacterIterator;
|
||||
import java.util.*;
|
||||
|
||||
public class GFont extends Font implements Refreshable {
|
||||
|
||||
private String id;
|
||||
private Font delegate;
|
||||
|
||||
public GFont(String id) {
|
||||
super("Courier", Font.PLAIN, 12);
|
||||
this.id = id;
|
||||
delegate = Gui.getRawFont(id);
|
||||
if (delegate == null) {
|
||||
delegate = new Font("Courier", Font.PLAIN, 12);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEquivalent(Font font) {
|
||||
return delegate.equals(font);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getTransform() {
|
||||
return delegate.getTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
Font font = Gui.getRawFont(id);
|
||||
if (font != null) {
|
||||
delegate = font;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFamily() {
|
||||
return delegate.getFamily();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFamily(Locale l) {
|
||||
return delegate.getFamily(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPSName() {
|
||||
return delegate.getPSName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontName() {
|
||||
return delegate.getFontName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontName(Locale l) {
|
||||
return delegate.getFontName(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStyle() {
|
||||
|
||||
return delegate.getStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return delegate.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSize2D() {
|
||||
return delegate.getSize2D();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlain() {
|
||||
return delegate.isPlain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
return delegate.isBold();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItalic() {
|
||||
return delegate.isItalic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransformed() {
|
||||
return delegate.isTransformed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLayoutAttributes() {
|
||||
return delegate.hasLayoutAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
GFont other = (GFont) obj;
|
||||
return Objects.equals(id, other.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumGlyphs() {
|
||||
return delegate.getNumGlyphs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMissingGlyphCode() {
|
||||
return delegate.getMissingGlyphCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getBaselineFor(char c) {
|
||||
return delegate.getBaselineFor(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TextAttribute, ?> getAttributes() {
|
||||
return delegate.getAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attribute[] getAvailableAttributes() {
|
||||
return delegate.getAvailableAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font deriveFont(int newStyle, float newSize) {
|
||||
return delegate.deriveFont(newStyle, newSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font deriveFont(int newStyle, AffineTransform trans) {
|
||||
return delegate.deriveFont(newStyle, trans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font deriveFont(float newSize) {
|
||||
return delegate.deriveFont(newSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font deriveFont(AffineTransform trans) {
|
||||
return delegate.deriveFont(trans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font deriveFont(int newStyle) {
|
||||
return delegate.deriveFont(newStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font deriveFont(Map<? extends Attribute, ?> attributes) {
|
||||
return delegate.deriveFont(attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDisplay(char c) {
|
||||
return delegate.canDisplay(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDisplay(int codePoint) {
|
||||
return delegate.canDisplay(codePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canDisplayUpTo(String str) {
|
||||
return delegate.canDisplayUpTo(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canDisplayUpTo(char[] text, int start, int limit) {
|
||||
return delegate.canDisplayUpTo(text, start, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
|
||||
return delegate.canDisplayUpTo(iter, start, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItalicAngle() {
|
||||
return delegate.getItalicAngle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUniformLineMetrics() {
|
||||
return delegate.hasUniformLineMetrics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineMetrics getLineMetrics(String str, FontRenderContext frc) {
|
||||
return delegate.getLineMetrics(str, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineMetrics getLineMetrics(String str, int beginIndex, int limit,
|
||||
FontRenderContext frc) {
|
||||
return delegate.getLineMetrics(str, beginIndex, limit, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit,
|
||||
FontRenderContext frc) {
|
||||
return delegate.getLineMetrics(chars, beginIndex, limit, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit,
|
||||
FontRenderContext frc) {
|
||||
return delegate.getLineMetrics(ci, beginIndex, limit, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getStringBounds(String str, FontRenderContext frc) {
|
||||
return delegate.getStringBounds(str, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getStringBounds(String str, int beginIndex, int limit,
|
||||
FontRenderContext frc) {
|
||||
return delegate.getStringBounds(str, beginIndex, limit, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit,
|
||||
FontRenderContext frc) {
|
||||
return delegate.getStringBounds(chars, beginIndex, limit, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit,
|
||||
FontRenderContext frc) {
|
||||
return delegate.getStringBounds(ci, beginIndex, limit, frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
|
||||
return delegate.getMaxCharBounds(frc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphVector createGlyphVector(FontRenderContext frc, String str) {
|
||||
return delegate.createGlyphVector(frc, str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) {
|
||||
return delegate.createGlyphVector(frc, chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator ci) {
|
||||
return delegate.createGlyphVector(frc, ci);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes) {
|
||||
return delegate.createGlyphVector(frc, glyphCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] text, int start, int limit,
|
||||
int flags) {
|
||||
return delegate.layoutGlyphVector(frc, text, start, limit, flags);
|
||||
}
|
||||
}
|
@ -20,21 +20,31 @@ import java.awt.Graphics;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import resources.ResourceManager;
|
||||
import docking.theme.Refreshable;
|
||||
import ghidra.util.datastruct.WeakStore;
|
||||
|
||||
public class GIcon implements Icon, Refreshable {
|
||||
private static WeakStore<GIcon> inUseIcons = new WeakStore<>();
|
||||
|
||||
private String id;
|
||||
private Icon delegate;
|
||||
|
||||
public GIcon(String id) {
|
||||
this.id = id;
|
||||
delegate = Gui.getRawIcon(id);
|
||||
if (delegate == null) {
|
||||
delegate = ResourceManager.getDefaultIcon();
|
||||
public static void refreshAll() {
|
||||
for (GIcon gIcon : inUseIcons.getValues()) {
|
||||
gIcon.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public GIcon(String id) {
|
||||
this(id, true);
|
||||
}
|
||||
|
||||
public GIcon(String id, boolean validate) {
|
||||
this.id = id;
|
||||
delegate = Gui.getRawIcon(id, validate);
|
||||
inUseIcons.add(this);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@ -56,7 +66,7 @@ public class GIcon implements Icon, Refreshable {
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
Icon icon = Gui.getRawIcon(id);
|
||||
Icon icon = Gui.getRawIcon(id, false);
|
||||
if (icon != null) {
|
||||
delegate = icon;
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
/* ###
|
||||
* 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.theme;
|
||||
|
||||
import javax.swing.plaf.UIResource;
|
||||
|
||||
public class GIconUIResource extends GIcon implements UIResource {
|
||||
|
||||
public GIconUIResource(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
/**
|
||||
* Class to store all the configurable appearance properties (Colors, Fonts, Icons, Look and Feel)
|
||||
* in an application.
|
||||
@ -124,10 +126,10 @@ public class GTheme extends GThemeValueMap {
|
||||
/**
|
||||
* Sets the icon for the given id
|
||||
* @param id the id to associate with the given IconPath
|
||||
* @param iconPath the path of the icon to assign to the given id
|
||||
* @param icon the icon to assign to the given id
|
||||
*/
|
||||
public void setIcon(String id, String iconPath) {
|
||||
addIconPath(new IconValue(id, null, iconPath));
|
||||
public void setIcon(String id, Icon icon) {
|
||||
addIcon(new IconValue(id, icon));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,7 +138,7 @@ public class GTheme extends GThemeValueMap {
|
||||
* @param refId the id of an indirect Icon lookup for the given id.
|
||||
*/
|
||||
public void setIconRef(String id, String refId) {
|
||||
addIconPath(new IconValue(id, refId, null));
|
||||
addIcon(new IconValue(id, refId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,7 +41,7 @@ public class GThemeValueMap {
|
||||
}
|
||||
}
|
||||
|
||||
public void addIconPath(IconValue value) {
|
||||
public void addIcon(IconValue value) {
|
||||
if (value != null) {
|
||||
iconMap.put(value.getId(), value);
|
||||
}
|
||||
@ -62,7 +62,7 @@ public class GThemeValueMap {
|
||||
public void load(GThemeValueMap valueMap) {
|
||||
valueMap.colorMap.values().forEach(v -> addColor(v));
|
||||
valueMap.fontMap.values().forEach(v -> addFont(v));
|
||||
valueMap.iconMap.values().forEach(v -> addIconPath(v));
|
||||
valueMap.iconMap.values().forEach(v -> addIcon(v));
|
||||
|
||||
}
|
||||
|
||||
@ -83,11 +83,11 @@ public class GThemeValueMap {
|
||||
}
|
||||
|
||||
public boolean containsFont(String id) {
|
||||
return colorMap.containsKey(id);
|
||||
return fontMap.containsKey(id);
|
||||
}
|
||||
|
||||
public boolean containsIconPath(String id) {
|
||||
return colorMap.containsKey(id);
|
||||
public boolean containsIcon(String id) {
|
||||
return iconMap.containsKey(id);
|
||||
}
|
||||
|
||||
public Object size() {
|
||||
@ -122,9 +122,14 @@ public class GThemeValueMap {
|
||||
}
|
||||
for (IconValue icon : iconMap.values()) {
|
||||
if (!icon.equals(base.getIcon(icon.getId()))) {
|
||||
map.addIconPath(icon);
|
||||
map.addIcon(icon);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void removeFont(String id) {
|
||||
fontMap.remove(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||
|
||||
// TODO doc what this concept is
|
||||
public class Gui {
|
||||
|
||||
public static final String THEME_DIR = "themes";
|
||||
public static final String BACKGROUND_KEY = "color.bg.text";
|
||||
|
||||
private static final String THEME_PREFFERENCE_KEY = "Theme";
|
||||
@ -53,8 +53,7 @@ public class Gui {
|
||||
private static ThemePropertiesLoader themePropertiesLoader = new ThemePropertiesLoader();
|
||||
|
||||
private static Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
||||
|
||||
private static JPanel jPanel;
|
||||
private static Map<String, GIconUIResource> gIconMap = new HashMap<>();
|
||||
|
||||
static void setPropertiesLoader(ThemePropertiesLoader loader) {
|
||||
themePropertiesLoader = loader;
|
||||
@ -178,12 +177,15 @@ public class Gui {
|
||||
return color.brighter();
|
||||
}
|
||||
|
||||
public static GFont getFont(String id) {
|
||||
return new GFont(id);
|
||||
}
|
||||
public static Font getFont(String id) {
|
||||
FontValue font = currentValues.getFont(id);
|
||||
if (font == null) {
|
||||
Throwable t = getFilteredTrace();
|
||||
|
||||
public static GIcon getIcon(String id) {
|
||||
return new GIcon(id);
|
||||
Msg.error(Gui.class, "No font value registered for: " + id, t);
|
||||
return null;
|
||||
}
|
||||
return font.get(currentValues);
|
||||
}
|
||||
|
||||
public static void saveThemeToPreferences(GTheme theme) {
|
||||
@ -227,27 +229,16 @@ public class Gui {
|
||||
return color.get(currentValues);
|
||||
}
|
||||
|
||||
static Font getRawFont(String id) {
|
||||
FontValue font = currentValues.getFont(id);
|
||||
if (font == null) {
|
||||
Throwable t = getFilteredTrace();
|
||||
|
||||
Msg.error(Gui.class, "No font value registered for: " + id, t);
|
||||
return null;
|
||||
}
|
||||
return font.get(currentValues);
|
||||
}
|
||||
|
||||
public static Icon getRawIcon(String id) {
|
||||
public static Icon getRawIcon(String id, boolean validate) {
|
||||
IconValue icon = currentValues.getIcon(id);
|
||||
if (icon == null) {
|
||||
Throwable t = getFilteredTrace();
|
||||
|
||||
Msg.error(Gui.class, "No color value registered for: " + id, t);
|
||||
return null;
|
||||
if (validate) {
|
||||
Throwable t = getFilteredTrace();
|
||||
Msg.error(Gui.class, "No color value registered for: " + id, t);
|
||||
}
|
||||
return ResourceManager.getDefaultIcon();
|
||||
}
|
||||
String iconPath = icon.get(currentValues);
|
||||
return ResourceManager.loadImage(iconPath);
|
||||
return icon.get(currentValues);
|
||||
}
|
||||
|
||||
private static Throwable getFilteredTrace() {
|
||||
@ -270,6 +261,7 @@ public class Gui {
|
||||
map.load(activeTheme);
|
||||
currentValues = map;
|
||||
GColor.refreshAll();
|
||||
GIcon.refreshAll();
|
||||
repaintAll();
|
||||
}
|
||||
|
||||
@ -296,10 +288,14 @@ public class Gui {
|
||||
|
||||
private static Collection<GTheme> loadThemesFromFiles() {
|
||||
List<File> fileList = new ArrayList<>();
|
||||
FileFilter themeFileFilter = file -> file.getName().endsWith(GTheme.FILE_EXTENSION);
|
||||
|
||||
File dir = Application.getUserSettingsDirectory();
|
||||
FileFilter themeFileFilter = file -> file.getName().endsWith(GTheme.FILE_EXTENSION);
|
||||
fileList.addAll(Arrays.asList(dir.listFiles(themeFileFilter)));
|
||||
File themeDir = new File(dir, THEME_DIR);
|
||||
File[] files = themeDir.listFiles(themeFileFilter);
|
||||
if (files != null) {
|
||||
fileList.addAll(Arrays.asList(files));
|
||||
}
|
||||
|
||||
List<GTheme> list = new ArrayList<>();
|
||||
for (File file : fileList) {
|
||||
@ -351,16 +347,55 @@ public class Gui {
|
||||
return new DefaultTheme();
|
||||
}
|
||||
|
||||
public static void setFont(FontValue newValue) {
|
||||
currentValues.addFont(newValue);
|
||||
// all fonts are direct (there is no GFont), so to we need to update the
|
||||
// UiDefaults for java fonts. Ghidra fonts are expected to be "on the fly" (they
|
||||
// call Gui.getFont(id) for every use.
|
||||
String id = newValue.getId();
|
||||
if (javaDefaults.containsFont(id)) {
|
||||
UIManager.getDefaults().put(id, newValue.get(currentValues));
|
||||
updateUIs();
|
||||
}
|
||||
else {
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setColor(String id, Color color) {
|
||||
setColor(new ColorValue(id, color));
|
||||
}
|
||||
|
||||
public static void setColor(ColorValue colorValue) {
|
||||
currentValues.addColor(colorValue);
|
||||
// all colors use indirection via GColor, so to update all we need to do is refresh GColors
|
||||
// and repaint
|
||||
GColor.refreshAll();
|
||||
repaintAll();
|
||||
}
|
||||
|
||||
public static void setIcon(String id, Icon icon) {
|
||||
setIcon(new IconValue(id, icon));
|
||||
}
|
||||
|
||||
public static void setIcon(IconValue newValue) {
|
||||
currentValues.addIcon(newValue);
|
||||
|
||||
// Icons are a mixed bag. Java Icons are direct and Ghidra Icons are indirect (to support static use)
|
||||
// Mainly because Nimbus is buggy and can't handle non-nimbus Icons, so we can't wrap them
|
||||
// So need to update UiDefaults for java icons. For Ghidra Icons, it is sufficient to refrech
|
||||
// GIcons and repaint
|
||||
String id = newValue.getId();
|
||||
if (javaDefaults.containsIcon(id)) {
|
||||
UIManager.getDefaults().put(id, newValue.get(currentValues));
|
||||
updateUIs();
|
||||
}
|
||||
else {
|
||||
GIcon.refreshAll();
|
||||
repaintAll();
|
||||
}
|
||||
}
|
||||
|
||||
private static void repaintAll() {
|
||||
for (Window window : Window.getWindows()) {
|
||||
window.repaint();
|
||||
@ -368,6 +403,7 @@ public class Gui {
|
||||
}
|
||||
|
||||
public static GColorUIResource getGColorUiResource(String id) {
|
||||
|
||||
GColorUIResource gColor = gColorMap.get(id);
|
||||
if (gColor == null) {
|
||||
gColor = new GColorUIResource(id);
|
||||
@ -376,6 +412,16 @@ public class Gui {
|
||||
return gColor;
|
||||
}
|
||||
|
||||
public static GIconUIResource getGIconUiResource(String id) {
|
||||
|
||||
GIconUIResource gIcon = gIconMap.get(id);
|
||||
if (gIcon == null) {
|
||||
gIcon = new GIconUIResource(id);
|
||||
gIconMap.put(id, gIcon);
|
||||
}
|
||||
return gIcon;
|
||||
}
|
||||
|
||||
public static void setJavaDefaults(GThemeValueMap map) {
|
||||
javaDefaults = map;
|
||||
buildCurrentValues();
|
||||
@ -417,4 +463,5 @@ public class Gui {
|
||||
}
|
||||
return currentDefaults;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,17 +15,24 @@
|
||||
*/
|
||||
package docking.theme;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import javax.swing.Icon;
|
||||
|
||||
public class IconValue extends ThemeValue<String> {
|
||||
import ghidra.util.Msg;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class IconValue extends ThemeValue<Icon> {
|
||||
static final String ICON_ID_PREFIX = "icon.";
|
||||
|
||||
public static final String LAST_RESORT_DEFAULT = "images/bomb.gif";
|
||||
|
||||
private static final String EXTERNAL_PREFIX = "[icon]";
|
||||
|
||||
public IconValue(String id, String refId, String iconPath) {
|
||||
super(id, refId, iconPath);
|
||||
public IconValue(String id, Icon icon) {
|
||||
super(id, null, icon);
|
||||
}
|
||||
|
||||
public IconValue(String id, String refId) {
|
||||
super(id, refId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -34,10 +41,10 @@ public class IconValue extends ThemeValue<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUnresolvedReferenceValue(String id) {
|
||||
protected Icon getUnresolvedReferenceValue(String id) {
|
||||
Msg.warn(this,
|
||||
"Could not resolve indirect icon path for" + id + ", using last resort default");
|
||||
return LAST_RESORT_DEFAULT;
|
||||
return ResourceManager.getDefaultIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,7 +73,7 @@ public class IconValue extends ThemeValue<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int compareValues(String v1, String v2) {
|
||||
return v1.compareTo(v2);
|
||||
protected int compareValues(Icon v1, Icon v2) {
|
||||
return v1.toString().compareTo(v2.toString());
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,15 @@ import java.awt.Font;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
|
||||
import org.apache.commons.collections4.map.HashedMap;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.WebColors;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class ThemePropertyFileReader {
|
||||
|
||||
@ -112,7 +116,7 @@ public class ThemePropertyFileReader {
|
||||
valueMap.addFont(parseFontProperty(key, value, lineNumber));
|
||||
}
|
||||
else if (IconValue.isIconKey(key)) {
|
||||
valueMap.addIconPath(parseIconProperty(key, value));
|
||||
valueMap.addIcon(parseIconProperty(key, value));
|
||||
}
|
||||
else {
|
||||
error(lineNumber, "Can't process property: " + key + " = " + value);
|
||||
@ -122,9 +126,10 @@ public class ThemePropertyFileReader {
|
||||
|
||||
private IconValue parseIconProperty(String key, String value) {
|
||||
if (IconValue.isIconKey(value)) {
|
||||
return new IconValue(key, value, null);
|
||||
return new IconValue(key, value);
|
||||
}
|
||||
return new IconValue(key, null, value);
|
||||
Icon icon = ResourceManager.loadImage(value);
|
||||
return new IconValue(key, icon);
|
||||
}
|
||||
|
||||
private FontValue parseFontProperty(String key, String value, int lineNumber) {
|
||||
@ -135,7 +140,7 @@ public class ThemePropertyFileReader {
|
||||
if (font == null) {
|
||||
error(lineNumber, "Could not parse Color: " + value);
|
||||
}
|
||||
return font == null ? null : new FontValue(key, font);
|
||||
return font == null ? null : new FontValue(key, new FontUIResource(font));
|
||||
}
|
||||
|
||||
private ColorValue parseColorProperty(String key, String value, int lineNumber) {
|
||||
|
@ -50,6 +50,7 @@ public class ThemeReader extends ThemePropertyFileReader {
|
||||
// processValues expects only colors, fonts, and icons
|
||||
themeSection.remove(GTheme.THEME_NAME_KEY);
|
||||
themeSection.remove(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
||||
themeSection.remove(GTheme.THEME_USE_DARK_DEFAULTS);
|
||||
|
||||
processValues(theme, themeSection);
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
import docking.options.editor.ColorPropertyEditor;
|
||||
import docking.theme.*;
|
||||
|
||||
/**
|
||||
* Editor for Theme colors
|
||||
*/
|
||||
public class ColorValueEditor extends ThemeValueEditor<Color> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param listener the {@link PropertyChangeListener} to be notified when changes are made
|
||||
*/
|
||||
public ColorValueEditor(PropertyChangeListener listener) {
|
||||
super("Color", listener, new ColorPropertyEditor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getRawValue(String id) {
|
||||
return Gui.getRawColor(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThemeValue<Color> createNewThemeValue(String id, Color color) {
|
||||
return new ColorValue(id, color);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
|
||||
import docking.options.editor.FontPropertyEditor;
|
||||
import docking.theme.*;
|
||||
|
||||
/**
|
||||
* Editor for Theme fonts
|
||||
*/
|
||||
public class FontValueEditor extends ThemeValueEditor<Font> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param listener the {@link PropertyChangeListener} to be notified when changes are made
|
||||
*/
|
||||
public FontValueEditor(PropertyChangeListener listener) {
|
||||
super("Font", listener, new FontPropertyEditor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Font getRawValue(String id) {
|
||||
return Gui.getFont(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThemeValue<Font> createNewThemeValue(String id, Font font) {
|
||||
// We need user changed values to be UIResources, otherwise the next time they change
|
||||
// the value, it won't be honored because setting UIDefaults only affects components
|
||||
// that have current UIResource fonts (So that programatic settings won't be overridden)
|
||||
if (!(font instanceof UIResource)) {
|
||||
font = new FontUIResource(font);
|
||||
}
|
||||
return new FontValue(id, font);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import docking.options.editor.IconPropertyEditor;
|
||||
import docking.theme.*;
|
||||
|
||||
/**
|
||||
* Editor for Theme fonts
|
||||
*/
|
||||
public class IconValueEditor extends ThemeValueEditor<Icon> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param listener the {@link PropertyChangeListener} to be notified when changes are made
|
||||
*/
|
||||
public IconValueEditor(PropertyChangeListener listener) {
|
||||
super("Icon", listener, new IconPropertyEditor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Icon getRawValue(String id) {
|
||||
return Gui.getRawIcon(id, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThemeValue<Icon> createNewThemeValue(String id, Icon icon) {
|
||||
return new IconValue(id, icon);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class ProtectedIcon implements Icon {
|
||||
Icon bomb = ResourceManager.getDefaultIcon();
|
||||
Icon delegate;
|
||||
boolean isError = false;
|
||||
|
||||
public ProtectedIcon(Icon delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean hasError() {
|
||||
return isError;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintIcon(Component c, Graphics g, int x, int y) {
|
||||
try {
|
||||
delegate.paintIcon(c, g, x, y);
|
||||
}
|
||||
catch (Exception e) {
|
||||
bomb.paintIcon(c, g, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return delegate.getIconWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return delegate.getIconHeight();
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.options.editor.GhidraColorChooser;
|
||||
import docking.theme.ColorValue;
|
||||
import docking.theme.Gui;
|
||||
|
||||
public class ThemeColorEditorDialog extends DialogComponentProvider {
|
||||
|
||||
private ColorValue startingColorValue;
|
||||
private ColorValue currentColorValue;
|
||||
|
||||
private ThemeDialog themeDialog;
|
||||
private GhidraColorChooser colorChooser;
|
||||
private ChangeListener colorChangeListener = e -> colorChanged();
|
||||
|
||||
public ThemeColorEditorDialog(ThemeDialog themeDialog) {
|
||||
super("Theme Color Editor", false);
|
||||
this.themeDialog = themeDialog;
|
||||
addWorkPanel(buildColorPanel());
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
}
|
||||
|
||||
public void editColor(ColorValue colorValue) {
|
||||
this.startingColorValue = colorValue;
|
||||
this.currentColorValue = colorValue;
|
||||
|
||||
setTitle("Edit Color For: " + colorValue.getId());
|
||||
Color color = Gui.getRawColor(startingColorValue.getId());
|
||||
colorChooser.getSelectionModel().removeChangeListener(colorChangeListener);
|
||||
colorChooser.setColor(color);
|
||||
colorChooser.getSelectionModel().addChangeListener(colorChangeListener);
|
||||
|
||||
if (!isShowing()) {
|
||||
DockingWindowManager.showDialog(themeDialog.getComponent(), this);
|
||||
}
|
||||
}
|
||||
|
||||
private JComponent buildColorPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
colorChooser = new GhidraColorChooser();
|
||||
panel.add(colorChooser);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
currentColorValue = null;
|
||||
startingColorValue = null;
|
||||
close();
|
||||
themeDialog.colorEditorClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
restoreOriginalColor();
|
||||
currentColorValue = null;
|
||||
startingColorValue = null;
|
||||
close();
|
||||
themeDialog.colorEditorClosed();
|
||||
}
|
||||
|
||||
private void restoreOriginalColor() {
|
||||
themeDialog.colorChanged(currentColorValue, startingColorValue);
|
||||
currentColorValue = startingColorValue;
|
||||
}
|
||||
|
||||
private void colorChanged() {
|
||||
Color newColor = colorChooser.getColor();
|
||||
ColorValue newColorValue = new ColorValue(startingColorValue.getId(), newColor);
|
||||
themeDialog.colorChanged(currentColorValue, newColorValue);
|
||||
currentColorValue = newColorValue;
|
||||
}
|
||||
|
||||
}
|
@ -69,7 +69,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Users";
|
||||
return "Colors";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,7 +181,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||
ResolvedColor resolved = (ResolvedColor) data.getValue();
|
||||
|
||||
String text = getValueText(resolved);
|
||||
Color color = resolved == null ? GThemeDefaults.Colors.BACKGROUND : resolved.color;
|
||||
Color color = resolved == null ? GThemeDefaults.Colors.BACKGROUND : resolved.color();
|
||||
label.setText(text);
|
||||
label.setIcon(new SwatchIcon(color, label.getForeground()));
|
||||
label.setOpaque(true);
|
||||
@ -192,10 +192,10 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||
if (resolvedColor == null) {
|
||||
return "<No Value>";
|
||||
}
|
||||
if (resolvedColor.refId != null) {
|
||||
return resolvedColor.refId;
|
||||
if (resolvedColor.refId() != null) {
|
||||
return resolvedColor.refId();
|
||||
}
|
||||
Color color = resolvedColor.color;
|
||||
Color color = resolvedColor.color();
|
||||
String text = WebColors.toString(color, false);
|
||||
String name = WebColors.toWebColorName(color);
|
||||
if (name != null) {
|
||||
@ -239,15 +239,5 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||
}
|
||||
}
|
||||
|
||||
class ResolvedColor {
|
||||
String id;
|
||||
String refId;
|
||||
Color color;
|
||||
|
||||
ResolvedColor(String id, String refId, Color color) {
|
||||
this.id = id;
|
||||
this.refId = refId;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
record ResolvedColor(String id, String refId, Color color) {/**/}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package docking.theme.gui;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
@ -41,12 +42,16 @@ import docking.widgets.table.GTable;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||
import resources.Icons;
|
||||
|
||||
public class ThemeDialog extends DialogComponentProvider {
|
||||
private static ThemeDialog INSTANCE;
|
||||
private ThemeColorTableModel colorTableModel;
|
||||
private ThemeColorEditorDialog dialog;
|
||||
private ThemeFontTableModel fontTableModel;
|
||||
private ThemeIconTableModel iconTableModel;
|
||||
|
||||
private ColorValueEditor colorEditor = new ColorValueEditor(this::colorValueChanged);
|
||||
private FontValueEditor fontEditor = new FontValueEditor(this::fontValueChanged);
|
||||
private IconValueEditor iconEditor = new IconValueEditor(this::iconValueChanged);
|
||||
|
||||
// stores the original value for ids whose value has changed
|
||||
private GThemeValueMap changedValuesMap = new GThemeValueMap();
|
||||
@ -70,22 +75,22 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
}
|
||||
|
||||
private void createActions() {
|
||||
DockingAction importAction = new ActionBuilder("Import Theme", getTitle())
|
||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
||||
.onAction(e -> importTheme())
|
||||
.build();
|
||||
DockingAction importAction =
|
||||
new ActionBuilder("Import Theme", getTitle()).toolBarIcon(new GIcon("icon.navigate.in"))
|
||||
.onAction(e -> importTheme())
|
||||
.build();
|
||||
addAction(importAction);
|
||||
|
||||
DockingAction exportAction = new ActionBuilder("Export Theme", getTitle())
|
||||
.toolBarIcon(Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON)
|
||||
.toolBarIcon(new GIcon("icon.navigate.out"))
|
||||
.onAction(e -> exportTheme())
|
||||
.build();
|
||||
addAction(exportAction);
|
||||
|
||||
DockingAction reloadDefaultsAction =
|
||||
new ActionBuilder("Reload Ghidra Defaults", getTitle()).toolBarIcon(Icons.REFRESH_ICON)
|
||||
.onAction(e -> reloadDefaultsCallback())
|
||||
.build();
|
||||
DockingAction reloadDefaultsAction = new ActionBuilder("Reload Ghidra Defaults", getTitle())
|
||||
.toolBarIcon(new GIcon("icon.refresh"))
|
||||
.onAction(e -> reloadDefaultsCallback())
|
||||
.build();
|
||||
addAction(reloadDefaultsAction);
|
||||
}
|
||||
|
||||
@ -144,6 +149,8 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
private void reset() {
|
||||
changedValuesMap.clear();
|
||||
colorTableModel.reloadAll();
|
||||
fontTableModel.reloadAll();
|
||||
iconTableModel.reloadAll();
|
||||
updateButtons();
|
||||
updateCombo();
|
||||
}
|
||||
@ -211,8 +218,12 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
|
||||
private File getSaveFile(String themeName) {
|
||||
File dir = Application.getUserSettingsDirectory();
|
||||
File themeDir = new File(dir, Gui.THEME_DIR);
|
||||
if (!themeDir.exists()) {
|
||||
themeDir.mkdir();
|
||||
}
|
||||
String cleanedName = themeName.replaceAll(" ", "_") + GTheme.FILE_EXTENSION;
|
||||
return new File(dir, cleanedName);
|
||||
return new File(themeDir, cleanedName);
|
||||
}
|
||||
|
||||
private void importTheme() {
|
||||
@ -252,15 +263,18 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
private void themeComboChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||
String themeName = (String) e.getItem();
|
||||
if (hasChanges()) {
|
||||
Msg.debug(this, "has changes");
|
||||
}
|
||||
|
||||
Swing.runLater(() -> {
|
||||
GTheme theme = Gui.getTheme(themeName);
|
||||
Gui.setTheme(theme);
|
||||
if (theme.getLookAndFeelType() == LafType.GTK) {
|
||||
setStatusText(
|
||||
"Warning - GTK does not support changing it's component colors. You can still change Ghidra colors.",
|
||||
"Warning - Themes using the GTK LookAndFeel do not support changing java component colors, fonts or icons. You can still change Ghidra values.",
|
||||
MessageType.ERROR, true);
|
||||
}
|
||||
else if (theme.getLookAndFeelType() == LafType.NIMBUS) {
|
||||
setStatusText(
|
||||
"Warning - Themes using the Nimbus LookAndFeel do not support changing java component fonts or icons. You can still change Ghidra values.",
|
||||
MessageType.ERROR, true);
|
||||
}
|
||||
else {
|
||||
@ -268,6 +282,8 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
}
|
||||
changedValuesMap.clear();
|
||||
colorTableModel.reloadAll();
|
||||
fontTableModel.reloadAll();
|
||||
iconTableModel.reloadAll();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -277,14 +293,21 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
}
|
||||
|
||||
protected void editColor(ColorValue value) {
|
||||
if (dialog == null) {
|
||||
dialog = new ThemeColorEditorDialog(this);
|
||||
}
|
||||
dialog.editColor(value);
|
||||
colorEditor.editValue(value);
|
||||
}
|
||||
|
||||
void colorChanged(ColorValue oldValue, ColorValue newValue) {
|
||||
updateChanagedValueMap(oldValue, newValue);
|
||||
protected void editFont(FontValue value) {
|
||||
fontEditor.editValue(value);
|
||||
}
|
||||
|
||||
protected void editIcon(IconValue value) {
|
||||
iconEditor.editValue(value);
|
||||
}
|
||||
|
||||
void colorValueChanged(PropertyChangeEvent event) {
|
||||
ColorValue oldValue = (ColorValue) event.getOldValue();
|
||||
ColorValue newValue = (ColorValue) event.getNewValue();
|
||||
updateChangedValueMap(oldValue, newValue);
|
||||
// run later - don't rock the boat in the middle of a listener callback
|
||||
Swing.runLater(() -> {
|
||||
Gui.setColor(newValue);
|
||||
@ -292,7 +315,29 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private void updateChanagedValueMap(ColorValue oldValue, ColorValue newValue) {
|
||||
void fontValueChanged(PropertyChangeEvent event) {
|
||||
FontValue oldValue = (FontValue) event.getOldValue();
|
||||
FontValue newValue = (FontValue) event.getNewValue();
|
||||
updateChangedValueMap(oldValue, newValue);
|
||||
// run later - don't rock the boat in the middle of a listener callback
|
||||
Swing.runLater(() -> {
|
||||
Gui.setFont(newValue);
|
||||
fontTableModel.reloadCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
void iconValueChanged(PropertyChangeEvent event) {
|
||||
IconValue oldValue = (IconValue) event.getOldValue();
|
||||
IconValue newValue = (IconValue) event.getNewValue();
|
||||
updateChangedValueMap(oldValue, newValue);
|
||||
// run later - don't rock the boat in the middle of a listener callback
|
||||
Swing.runLater(() -> {
|
||||
Gui.setIcon(newValue);
|
||||
iconTableModel.reloadCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateChangedValueMap(ColorValue oldValue, ColorValue newValue) {
|
||||
ColorValue originalValue = changedValuesMap.getColor(oldValue.getId());
|
||||
if (originalValue == null) {
|
||||
changedValuesMap.addColor(oldValue);
|
||||
@ -304,16 +349,36 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
private void updateChangedValueMap(FontValue oldValue, FontValue newValue) {
|
||||
FontValue originalValue = changedValuesMap.getFont(oldValue.getId());
|
||||
if (originalValue == null) {
|
||||
changedValuesMap.addFont(oldValue);
|
||||
}
|
||||
else if (originalValue.equals(newValue)) {
|
||||
// if restoring the original color, remove it from the map of changes
|
||||
changedValuesMap.removeFont(oldValue.getId());
|
||||
}
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
private void updateChangedValueMap(IconValue oldValue, IconValue newValue) {
|
||||
IconValue originalValue = changedValuesMap.getIcon(oldValue.getId());
|
||||
if (originalValue == null) {
|
||||
changedValuesMap.addIcon(oldValue);
|
||||
}
|
||||
else if (originalValue.equals(newValue)) {
|
||||
// if restoring the original color, remove it from the map of changes
|
||||
changedValuesMap.removeFont(oldValue.getId());
|
||||
}
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
private void updateButtons() {
|
||||
boolean hasChanges = hasChanges();
|
||||
saveButton.setEnabled(hasChanges);
|
||||
restoreButton.setEnabled(hasChanges);
|
||||
}
|
||||
|
||||
void colorEditorClosed() {
|
||||
dialog = null;
|
||||
}
|
||||
|
||||
private JComponent createMainPanel() {
|
||||
JPanel panel = new JPanel();
|
||||
|
||||
@ -362,9 +427,89 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
private Component buildTabedTables() {
|
||||
JTabbedPane tabbedPane = new JTabbedPane();
|
||||
tabbedPane.add("Colors", buildColorTable());
|
||||
tabbedPane.add("Fonts", buildFontTable());
|
||||
tabbedPane.add("Icons", buildIconTable());
|
||||
return tabbedPane;
|
||||
}
|
||||
|
||||
private JComponent buildFontTable() {
|
||||
fontTableModel = new ThemeFontTableModel();
|
||||
GFilterTable<FontValue> filterTable = new GFilterTable<>(fontTableModel);
|
||||
GTable table = filterTable.getTable();
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
table.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
FontValue fontValue = filterTable.getSelectedRowObject();
|
||||
if (fontValue != null) {
|
||||
editFont(fontValue);
|
||||
}
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
table.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
FontValue value = filterTable.getItemAt(e.getPoint());
|
||||
|
||||
int col = filterTable.getColumn(e.getPoint());
|
||||
TableColumn column = table.getColumnModel().getColumn(col);
|
||||
Object identifier = column.getIdentifier();
|
||||
if ("Current Font".equals(identifier) || "Id".equals(identifier)) {
|
||||
editFont(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return filterTable;
|
||||
|
||||
}
|
||||
|
||||
private JComponent buildIconTable() {
|
||||
iconTableModel = new ThemeIconTableModel();
|
||||
GFilterTable<IconValue> filterTable = new GFilterTable<>(iconTableModel);
|
||||
GTable table = filterTable.getTable();
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
table.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
IconValue iconValue = filterTable.getSelectedRowObject();
|
||||
if (iconValue != null) {
|
||||
editIcon(iconValue);
|
||||
}
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
table.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
IconValue value = filterTable.getItemAt(e.getPoint());
|
||||
|
||||
int col = filterTable.getColumn(e.getPoint());
|
||||
TableColumn column = table.getColumnModel().getColumn(col);
|
||||
Object identifier = column.getIdentifier();
|
||||
if ("Current Icon".equals(identifier) || "Id".equals(identifier)) {
|
||||
editIcon(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return filterTable;
|
||||
|
||||
}
|
||||
|
||||
private JComponent buildColorTable() {
|
||||
colorTableModel = new ThemeColorTableModel();
|
||||
|
||||
@ -390,8 +535,6 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
ColorValue value = filterTable.getItemAt(e.getPoint());
|
||||
Object cellValue = filterTable.getCellValue(e.getPoint());
|
||||
// editColor(value);
|
||||
|
||||
int col = filterTable.getColumn(e.getPoint());
|
||||
TableColumn column = table.getColumnModel().getColumn(col);
|
||||
@ -433,5 +576,4 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||
DockingWindowManager.showDialog(INSTANCE);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,204 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import docking.theme.*;
|
||||
import docking.widgets.table.*;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.framework.plugintool.ServiceProviderStub;
|
||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
|
||||
public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Object> {
|
||||
private List<FontValue> fonts;
|
||||
private GThemeValueMap currentValues;
|
||||
private GThemeValueMap themeValues;
|
||||
private GThemeValueMap defaultValues;
|
||||
|
||||
public ThemeFontTableModel() {
|
||||
super(new ServiceProviderStub());
|
||||
load();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
currentValues = Gui.getAllValues();
|
||||
fonts = currentValues.getFonts();
|
||||
themeValues = new GThemeValueMap(currentValues);
|
||||
defaultValues = Gui.getDefaults();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Fonts";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FontValue> getModelData() {
|
||||
return fonts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableColumnDescriptor<FontValue> createTableColumnDescriptor() {
|
||||
TableColumnDescriptor<FontValue> descriptor = new TableColumnDescriptor<>();
|
||||
descriptor.addVisibleColumn(new IdColumn());
|
||||
descriptor.addVisibleColumn(new FontValueColumn("Current Font", () -> currentValues));
|
||||
descriptor.addVisibleColumn(new FontValueColumn("Theme Font", () -> themeValues));
|
||||
descriptor.addVisibleColumn(new FontValueColumn("Default Font", () -> defaultValues));
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDataSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
class IdColumn extends AbstractDynamicTableColumn<FontValue, String, Object> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(FontValue fontValue, Settings settings, Object data,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
return fontValue.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPreferredWidth() {
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
class FontValueColumn extends AbstractDynamicTableColumn<FontValue, ResolvedFont, Object> {
|
||||
private ThemeFontRenderer renderer;
|
||||
private String name;
|
||||
private Supplier<GThemeValueMap> valueSupplier;
|
||||
|
||||
FontValueColumn(String name, Supplier<GThemeValueMap> supplier) {
|
||||
this.name = name;
|
||||
this.valueSupplier = supplier;
|
||||
renderer = new ThemeFontRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedFont getValue(FontValue fontValue, Settings settings, Object data,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
GThemeValueMap valueMap = valueSupplier.get();
|
||||
String id = fontValue.getId();
|
||||
FontValue value = valueMap.getFont(id);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
Font font = value.get(valueMap);
|
||||
return new ResolvedFont(id, value.getReferenceId(), font);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GColumnRenderer<ResolvedFont> getColumnRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public Comparator<ResolvedFont> getComparator() {
|
||||
return (v1, v2) -> {
|
||||
if (v1 == null && v2 == null) {
|
||||
return 0;
|
||||
}
|
||||
if (v1 == null) {
|
||||
return 1;
|
||||
}
|
||||
if (v2 == null) {
|
||||
return -1;
|
||||
}
|
||||
return v1.font().toString().compareTo(v2.font().toString());
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPreferredWidth() {
|
||||
return 300;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ThemeFontRenderer extends AbstractGColumnRenderer<ResolvedFont> {
|
||||
|
||||
public ThemeFontRenderer() {
|
||||
setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
||||
ResolvedFont resolved = (ResolvedFont) data.getValue();
|
||||
|
||||
String text = getValueText(resolved);
|
||||
label.setText(text);
|
||||
label.setOpaque(true);
|
||||
return label;
|
||||
}
|
||||
|
||||
private String getValueText(ResolvedFont resolvedFont) {
|
||||
if (resolvedFont == null) {
|
||||
return "<No Value>";
|
||||
}
|
||||
Font font = resolvedFont.font();
|
||||
String fontString = FileGTheme.fontToString(font);
|
||||
|
||||
if (resolvedFont.refId() != null) {
|
||||
return resolvedFont.refId() + " [" + fontString + "]";
|
||||
}
|
||||
return fontString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterString(ResolvedFont fontValue, Settings settings) {
|
||||
return getValueText(fontValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record ResolvedFont(String id, String refId, Font font) {/**/}
|
||||
|
||||
public void reloadCurrent() {
|
||||
|
||||
currentValues = Gui.getAllValues();
|
||||
fonts = currentValues.getFonts();
|
||||
fireTableDataChanged();
|
||||
|
||||
}
|
||||
|
||||
public void reloadAll() {
|
||||
load();
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.theme.*;
|
||||
import docking.widgets.table.*;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.framework.plugintool.ServiceProviderStub;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
import resources.icons.*;
|
||||
|
||||
public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Object> {
|
||||
private List<IconValue> icons;
|
||||
private GThemeValueMap currentValues;
|
||||
private GThemeValueMap themeValues;
|
||||
private GThemeValueMap defaultValues;
|
||||
|
||||
public ThemeIconTableModel() {
|
||||
super(new ServiceProviderStub());
|
||||
load();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
Msg.debug(this, "loading");
|
||||
currentValues = Gui.getAllValues();
|
||||
icons = currentValues.getIcons();
|
||||
themeValues = new GThemeValueMap(currentValues);
|
||||
defaultValues = Gui.getDefaults();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Fonts";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IconValue> getModelData() {
|
||||
return icons;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableColumnDescriptor<IconValue> createTableColumnDescriptor() {
|
||||
TableColumnDescriptor<IconValue> descriptor = new TableColumnDescriptor<>();
|
||||
descriptor.addVisibleColumn(new IdColumn());
|
||||
descriptor.addVisibleColumn(new IconValueColumn("Current Icon", () -> currentValues));
|
||||
descriptor.addVisibleColumn(new IconValueColumn("Theme Icon", () -> themeValues));
|
||||
descriptor.addVisibleColumn(new IconValueColumn("Default Icon", () -> defaultValues));
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDataSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
class IdColumn extends AbstractDynamicTableColumn<IconValue, String, Object> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(IconValue iconValue, Settings settings, Object data,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
return iconValue.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPreferredWidth() {
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
class IconValueColumn extends AbstractDynamicTableColumn<IconValue, ResolvedIcon, Object> {
|
||||
private ThemeIconRenderer renderer;
|
||||
private String name;
|
||||
private Supplier<GThemeValueMap> valueSupplier;
|
||||
|
||||
IconValueColumn(String name, Supplier<GThemeValueMap> supplier) {
|
||||
this.name = name;
|
||||
this.valueSupplier = supplier;
|
||||
renderer = new ThemeIconRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedIcon getValue(IconValue iconValue, Settings settings, Object data,
|
||||
ServiceProvider provider) throws IllegalArgumentException {
|
||||
GThemeValueMap valueMap = valueSupplier.get();
|
||||
String id = iconValue.getId();
|
||||
IconValue value = valueMap.getIcon(id);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
Icon icon = value.get(valueMap);
|
||||
return new ResolvedIcon(id, value.getReferenceId(), icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GColumnRenderer<ResolvedIcon> getColumnRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public Comparator<ResolvedIcon> getComparator() {
|
||||
return (v1, v2) -> {
|
||||
if (v1 == null && v2 == null) {
|
||||
return 0;
|
||||
}
|
||||
if (v1 == null) {
|
||||
return 1;
|
||||
}
|
||||
if (v2 == null) {
|
||||
return -1;
|
||||
}
|
||||
return v1.icon().toString().compareTo(v2.icon().toString());
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPreferredWidth() {
|
||||
return 300;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ThemeIconRenderer extends AbstractGColumnRenderer<ResolvedIcon> {
|
||||
|
||||
public ThemeIconRenderer() {
|
||||
setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||
Component comp = super.getTableCellRendererComponent(data);
|
||||
JLabel label = (JLabel) comp;
|
||||
ResolvedIcon resolved = (ResolvedIcon) data.getValue();
|
||||
|
||||
String text = getValueText(resolved);
|
||||
Icon icon = prepareIcon(resolved.icon());
|
||||
label.setIcon(icon);
|
||||
label.setText(text);
|
||||
label.setOpaque(true);
|
||||
return label;
|
||||
}
|
||||
|
||||
private Icon prepareIcon(Icon icon) {
|
||||
if (!(icon instanceof LazyImageIcon)) {
|
||||
icon = new ProtectedIcon(icon);
|
||||
}
|
||||
if (icon.getIconWidth() != 16 && icon.getIconHeight() != 16) {
|
||||
icon = new ScaledImageIcon(icon, 16, 16);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
private String getValueText(ResolvedIcon resolvedIcon) {
|
||||
if (resolvedIcon == null) {
|
||||
return "<No Value>";
|
||||
}
|
||||
Icon icon = resolvedIcon.icon();
|
||||
String sizeString = "[" + icon.getIconWidth() + "x" + icon.getIconHeight() + "] ";
|
||||
String iconString = "<Internal>";
|
||||
if (icon instanceof UrlImageIcon urlIcon) {
|
||||
iconString = urlIcon.getOriginalPath();
|
||||
}
|
||||
else if (icon instanceof ImageIcon imageIcon) {
|
||||
String description = imageIcon.getDescription();
|
||||
if (description != null) {
|
||||
iconString = "[" + description + "]";
|
||||
}
|
||||
}
|
||||
if (resolvedIcon.refId() != null) {
|
||||
iconString = resolvedIcon.refId() + " [" + iconString + "]";
|
||||
}
|
||||
return sizeString + iconString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterString(ResolvedIcon iconValue, Settings settings) {
|
||||
return getValueText(iconValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record ResolvedIcon(String id, String refId, Icon icon) {/**/}
|
||||
|
||||
public void reloadCurrent() {
|
||||
|
||||
currentValues = Gui.getAllValues();
|
||||
icons = currentValues.getIcons();
|
||||
fireTableDataChanged();
|
||||
|
||||
}
|
||||
|
||||
public void reloadAll() {
|
||||
load();
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/* ###
|
||||
* 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.theme.gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.beans.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.theme.ThemeValue;
|
||||
|
||||
/**
|
||||
* Base class for Theme properties (Colors, Fonts, and Icons)
|
||||
*
|
||||
* @param <T> the base property (Color, Font, or Icon)
|
||||
*/
|
||||
public abstract class ThemeValueEditor<T> {
|
||||
private PropertyChangeListener clientListener;
|
||||
protected ThemeValue<T> currentThemeValue;
|
||||
private EditorDialog dialog;
|
||||
private String typeName;
|
||||
private PropertyEditor editor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param typeName the name of the type (Used in the dialog title)
|
||||
* @param listener the {@link PropertyChangeListener} to be notified for changes
|
||||
* @param editor the standard property editor for the type
|
||||
*/
|
||||
protected ThemeValueEditor(String typeName, PropertyChangeListener listener,
|
||||
PropertyEditor editor) {
|
||||
this.typeName = typeName;
|
||||
this.clientListener = listener;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the ThemeValue by invoking the appropriate dialog for editing the type
|
||||
* @param themeValue the value to be edited
|
||||
*/
|
||||
public void editValue(ThemeValue<T> themeValue) {
|
||||
this.currentThemeValue = themeValue;
|
||||
T value = getRawValue(themeValue.getId());
|
||||
if (dialog == null) {
|
||||
dialog = new EditorDialog(value);
|
||||
DockingWindowManager.showDialog(dialog);
|
||||
}
|
||||
else {
|
||||
dialog.setValue(value);
|
||||
dialog.toFront();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual value (Color, Font, or Icon)
|
||||
* @param id the theme property id for the value
|
||||
* @return the current stored value for the id
|
||||
*/
|
||||
protected abstract T getRawValue(String id);
|
||||
|
||||
/**
|
||||
* Factory method for creating the ThemeValue of the correct type.
|
||||
* @param id the id for theme property
|
||||
* @param newValue the new value for the underlying type (Color, Font, or Icon)
|
||||
* @return the new ThemeValue for the type
|
||||
*/
|
||||
protected abstract ThemeValue<T> createNewThemeValue(String id, T newValue);
|
||||
|
||||
private void valueChanged(T newValue) {
|
||||
ThemeValue<T> oldValue = currentThemeValue;
|
||||
String id = oldValue.getId();
|
||||
PropertyChangeEvent event =
|
||||
new PropertyChangeEvent(this, id, oldValue, createNewThemeValue(id, newValue));
|
||||
clientListener.propertyChange(event);
|
||||
}
|
||||
|
||||
class EditorDialog extends DialogComponentProvider {
|
||||
private PropertyChangeListener internalListener = ev -> editorChanged();
|
||||
private T originalValue;
|
||||
|
||||
protected EditorDialog(T initialValue) {
|
||||
super("Edit " + typeName + ": " + currentThemeValue.getId(), false, false, true, false);
|
||||
this.originalValue = initialValue;
|
||||
addWorkPanel(buildWorkPanel(initialValue));
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
setRememberSize(false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void editorChanged() {
|
||||
valueChanged((T) editor.getValue());
|
||||
}
|
||||
|
||||
JComponent buildWorkPanel(T initialValue) {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10));
|
||||
panel.add(editor.getCustomEditor(), BorderLayout.CENTER);
|
||||
|
||||
editor.setValue(initialValue);
|
||||
editor.addPropertyChangeListener(internalListener);
|
||||
return panel;
|
||||
}
|
||||
|
||||
void setValue(T value) {
|
||||
originalValue = value;
|
||||
editor.removePropertyChangeListener(internalListener);
|
||||
editor.setValue(value);
|
||||
editor.addPropertyChangeListener(internalListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
close();
|
||||
dialog = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
valueChanged(originalValue);
|
||||
close();
|
||||
dialog = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -85,16 +85,16 @@ public class LookAndFeelInstaller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs GColors into the UIDefaults. Subclasses my override this if they need to install
|
||||
* GColors in a different way.
|
||||
* Installs Colors, Fonts, and Icons into the UIDefaults. Subclasses my override this if they need to install
|
||||
* UI properties in a different way.
|
||||
*/
|
||||
protected void installJavaDefaults() {
|
||||
GThemeValueMap javaDefaults = extractJavaDefaults();
|
||||
Gui.setJavaDefaults(javaDefaults);
|
||||
installIndirectValues(javaDefaults);
|
||||
installPropertiesBackIntoUiDefaults(javaDefaults);
|
||||
}
|
||||
|
||||
private void installIndirectValues(GThemeValueMap javaDefaults) {
|
||||
private void installPropertiesBackIntoUiDefaults(GThemeValueMap javaDefaults) {
|
||||
UIDefaults defaults = UIManager.getDefaults();
|
||||
for (ColorValue colorValue : javaDefaults.getColors()) {
|
||||
String id = colorValue.getId();
|
||||
@ -103,25 +103,43 @@ public class LookAndFeelInstaller {
|
||||
}
|
||||
for (FontValue fontValue : javaDefaults.getFonts()) {
|
||||
String id = fontValue.getId();
|
||||
GFont gFont = new GFont(id);
|
||||
if (!gFont.equals(fontValue.getRawValue())) {
|
||||
// only update if we have changed the default java color
|
||||
defaults.put(id, gFont);
|
||||
}
|
||||
//Note: fonts don't support indirect values, so there is no GFont object
|
||||
Font font = Gui.getFont(id);
|
||||
defaults.put(id, font);
|
||||
}
|
||||
// for (IconValue iconValue : javaDefaults.getIcons()) {
|
||||
// String id = iconValue.getId();
|
||||
// GIconUIResource gIcon = Gui.getGIconUiResource(id);
|
||||
// defaults.put(id, gIcon);
|
||||
// }
|
||||
}
|
||||
|
||||
protected GThemeValueMap extractJavaDefaults() {
|
||||
return extractJavaDefaults(UIManager.getDefaults());
|
||||
}
|
||||
|
||||
protected static GThemeValueMap extractJavaDefaults(UIDefaults defaults) {
|
||||
GThemeValueMap values = new GThemeValueMap();
|
||||
// for now, just doing color properties.
|
||||
List<String> ids =
|
||||
LookAndFeelUtils.getLookAndFeelIdsForType(UIManager.getDefaults(), Color.class);
|
||||
List<String> ids = LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Color.class);
|
||||
for (String id : ids) {
|
||||
// only use standard java colors here to avoid weird issues (such as GColor not
|
||||
// resolving or ColorUIResource not being honored. Later we will go back
|
||||
// and fix up the java defaults to use standard java color indirection
|
||||
values.addColor(new ColorValue(id, getNormalizedColor(UIManager.getColor(id))));
|
||||
}
|
||||
ids = LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Font.class);
|
||||
for (String id : ids) {
|
||||
values.addFont(new FontValue(id, UIManager.getFont(id)));
|
||||
}
|
||||
ids = LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Icon.class);
|
||||
for (String id : ids) {
|
||||
Icon icon = UIManager.getIcon(id);
|
||||
Msg.debug(LookAndFeelInstaller.class,
|
||||
"adding " + id + " icon class = " + icon.getClass().getName());
|
||||
values.addIcon(new IconValue(id, icon));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@ -271,9 +289,13 @@ public class LookAndFeelInstaller {
|
||||
String id = colorValue.getId();
|
||||
defaults.put(id, null);
|
||||
}
|
||||
// for (FontValue fontValue : javaDefaults.getFonts()) {
|
||||
// String id = fontValue.getId();
|
||||
// defaults.put(id, null);
|
||||
// }
|
||||
for (FontValue fontValue : javaDefaults.getFonts()) {
|
||||
String id = fontValue.getId();
|
||||
defaults.put(id, null);
|
||||
}
|
||||
for (IconValue iconValue : javaDefaults.getIcons()) {
|
||||
String id = iconValue.getId();
|
||||
defaults.put(id, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,7 @@
|
||||
*/
|
||||
package docking.theme.laf;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
@ -24,6 +23,7 @@ import javax.swing.plaf.nimbus.NimbusLookAndFeel;
|
||||
|
||||
import docking.theme.*;
|
||||
import ghidra.docking.util.LookAndFeelUtils;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class NimbusLookAndFeelInstaller extends LookAndFeelInstaller {
|
||||
|
||||
@ -71,13 +71,37 @@ public class NimbusLookAndFeelInstaller extends LookAndFeelInstaller {
|
||||
ColorValue value = new ColorValue(id, color);
|
||||
javaDefaults.addColor(value);
|
||||
}
|
||||
List<String> fontIds = LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Font.class);
|
||||
for (String id : fontIds) {
|
||||
Font font = defaults.getFont(id);
|
||||
FontValue value = new FontValue(id, font);
|
||||
javaDefaults.addFont(value);
|
||||
}
|
||||
List<String> iconIds = LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Icon.class);
|
||||
Msg.debug(LookAndFeelInstaller.class, "Icons found: " + iconIds.size());
|
||||
for (String id : iconIds) {
|
||||
Icon icon = defaults.getIcon(id);
|
||||
javaDefaults.addIcon(new IconValue(id, icon));
|
||||
}
|
||||
|
||||
Gui.setJavaDefaults(javaDefaults);
|
||||
for (String id : colorIds) {
|
||||
defaults.put(id, Gui.getGColorUiResource(id));
|
||||
}
|
||||
// for (String id : iconIds) {
|
||||
// GIconUIResource icon = Gui.getGIconUiResource(id);
|
||||
// if (icon.getId().equals("Menu.arrowIcon")) {
|
||||
// defaults.put(id, new IconWrappedImageIcon(Gui.getRawIcon(id, false)));
|
||||
// }
|
||||
// else {
|
||||
// defaults.put(id, Gui.getGIconUiResource(id));
|
||||
// }
|
||||
// }
|
||||
|
||||
// javaDefaults.addColor(new ColorValue("Label.textForground", "Label.foreground"));
|
||||
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
||||
GColor.refreshAll();
|
||||
GIcon.refreshAll();
|
||||
return defaults;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ public class WrappingLookAndFeel extends LookAndFeel {
|
||||
}
|
||||
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
||||
GColor.refreshAll();
|
||||
GIcon.refreshAll();
|
||||
return defaults;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import javax.swing.ImageIcon;
|
||||
|
||||
import generic.Images;
|
||||
import resources.ResourceManager;
|
||||
import resources.icons.UnresolvedIcon;
|
||||
|
||||
/**
|
||||
* Container class for an icon and its location. If the location is
|
||||
@ -76,7 +77,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||
// is it absolute, or in resources by the given path?
|
||||
baseIcon = ResourceManager.loadImage(iconLocation);
|
||||
|
||||
if (baseIcon == ResourceManager.getDefaultIcon()) {
|
||||
if (baseIcon instanceof UnresolvedIcon) {
|
||||
// ...must not be, look for it in our 'special' locations
|
||||
baseIcon = loadFromKnownImageResources(iconLocation);
|
||||
}
|
||||
@ -143,8 +144,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||
return image;
|
||||
}
|
||||
|
||||
return ResourceManager.getScaledIcon(unscaledIcon, SMALL_ICON_SIZE,
|
||||
SMALL_ICON_SIZE);
|
||||
return ResourceManager.getScaledIcon(unscaledIcon, SMALL_ICON_SIZE, SMALL_ICON_SIZE);
|
||||
}
|
||||
|
||||
private ImageIcon getLargeIcon(ImageIcon unscaledIcon) {
|
||||
@ -167,12 +167,11 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||
|
||||
// O.K., we will scale the icon. However, if it is the default icon, we know we have
|
||||
// a 'large' version of that.
|
||||
if (unscaledIcon == ResourceManager.getDefaultIcon()) {
|
||||
if (unscaledIcon instanceof UnresolvedIcon) {
|
||||
return ResourceManager.loadImage(Images.BIG_BOMB);
|
||||
}
|
||||
|
||||
return ResourceManager.getScaledIcon(unscaledIcon, LARGE_ICON_SIZE,
|
||||
LARGE_ICON_SIZE);
|
||||
return ResourceManager.getScaledIcon(unscaledIcon, LARGE_ICON_SIZE, LARGE_ICON_SIZE);
|
||||
}
|
||||
|
||||
private ImageIcon findCompatibleImageForSize(String imagePath, int desiredSize) {
|
||||
@ -191,11 +190,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||
name += location.substring(dotIndex);
|
||||
}
|
||||
|
||||
ImageIcon image = getImageIcon(name);
|
||||
if (image != null) {
|
||||
return image;
|
||||
}
|
||||
return null;
|
||||
return getImageIcon(name);
|
||||
}
|
||||
|
||||
private String stripSizeOffName(String name) {
|
||||
@ -218,11 +213,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||
|
||||
private ImageIcon getImageIcon(String name) {
|
||||
ImageIcon image = ResourceManager.loadImage(name);
|
||||
ImageIcon defaultIcon = ResourceManager.getDefaultIcon();
|
||||
if (image == defaultIcon) {
|
||||
if (!name.startsWith("images")) {
|
||||
return getImageIcon("images/" + name);
|
||||
}
|
||||
if (image instanceof UnresolvedIcon) {
|
||||
return null;
|
||||
}
|
||||
return image;
|
||||
@ -289,16 +280,8 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||
* @param name name of the icon
|
||||
*/
|
||||
private ImageIcon loadFromKnownImageResources(String name) {
|
||||
// first look in special location for tool icons
|
||||
String filename = "defaultTools/images/" + name;
|
||||
ImageIcon image = ResourceManager.loadImage(filename);
|
||||
|
||||
// if we can't find the icon in the special tool icon location, then look in general images.
|
||||
if (image == ResourceManager.getDefaultIcon()) {
|
||||
filename = "images/" + name;
|
||||
image = ResourceManager.loadImage(filename);
|
||||
}
|
||||
return image;
|
||||
return ResourceManager.loadImage(filename);
|
||||
}
|
||||
|
||||
private void checkAnimated(ImageIcon imgIcon) {
|
||||
|
@ -27,7 +27,7 @@ public class DefaultDropDownSelectionDataModel<T> implements DropDownTextFieldDa
|
||||
|
||||
protected List<T> data;
|
||||
|
||||
private Comparator<Object> comparator;
|
||||
protected Comparator<Object> comparator;
|
||||
private DataToStringConverter<T> searchConverter;
|
||||
private DataToStringConverter<T> descriptionConverter;
|
||||
private ListCellRenderer<T> renderer =
|
||||
|
@ -115,8 +115,8 @@ public class ColumnFilterArchiveDialog<R> extends DialogComponentProvider {
|
||||
|
||||
private JComponent buildFilterList() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEmptyBorder(19, 0, 0, 5), "Filter Names"));
|
||||
panel.setBorder(BorderFactory
|
||||
.createTitledBorder(BorderFactory.createEmptyBorder(19, 0, 0, 5), "Filter Names"));
|
||||
|
||||
jList = new JList<>();
|
||||
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
@ -136,22 +136,22 @@ public class ColumnFilterArchiveDialog<R> extends DialogComponentProvider {
|
||||
}
|
||||
|
||||
private JComponent buildActionPanel() {
|
||||
ImageIcon icon = Icons.DELETE_ICON;
|
||||
Icon icon = Icons.DELETE_ICON;
|
||||
|
||||
removeSelectedFiltersButton = new JButton("Remove", icon);
|
||||
removeSelectedFiltersButton.setEnabled(false);
|
||||
removeSelectedFiltersButton.addActionListener(e -> removeSelectedFilter());
|
||||
|
||||
JPanel buttonPanel = new JPanel(new BorderLayout());
|
||||
buttonPanel.add(removeSelectedFiltersButton, BorderLayout.EAST);
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(removeSelectedFiltersButton, BorderLayout.EAST);
|
||||
|
||||
return buttonPanel;
|
||||
return panel;
|
||||
}
|
||||
|
||||
private Component buildPreviewPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEmptyBorder(19, 0, 26, 5), "Preview"));
|
||||
panel.setBorder(BorderFactory
|
||||
.createTitledBorder(BorderFactory.createEmptyBorder(19, 0, 26, 5), "Preview"));
|
||||
|
||||
previewLabel = new GDHtmlLabel();
|
||||
previewLabel.setVerticalAlignment(SwingConstants.TOP);
|
||||
|
@ -93,7 +93,7 @@ public class ConstraintFilterPanel extends JPanel {
|
||||
|
||||
private Component buildButtonPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
ImageIcon icon = Icons.DELETE_ICON;
|
||||
Icon icon = Icons.DELETE_ICON;
|
||||
|
||||
JButton button = new EmptyBorderButton(icon);
|
||||
button.setToolTipText("Delete entry");
|
||||
|
@ -488,7 +488,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||
mainContentPanel.add(progressBarPanel, BorderLayout.CENTER);
|
||||
mainContentPanel.add(progressPanel, BorderLayout.EAST);
|
||||
|
||||
ImageIcon icon = Icons.STOP_ICON;
|
||||
Icon icon = Icons.STOP_ICON;
|
||||
cancelButton = new EmptyBorderButton(icon);
|
||||
|
||||
cancelButton.setName("CANCEL_TASK");
|
||||
|
@ -23,72 +23,74 @@ import java.net.URL;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import docking.theme.GIcon;
|
||||
import ghidra.util.Msg;
|
||||
import resources.icons.*;
|
||||
import resources.icons.RotateIcon;
|
||||
import resources.icons.TranslateIcon;
|
||||
|
||||
/**
|
||||
* A class to get generic icons for standard actions. All methods in this class return an
|
||||
* A class to get generic icons for standard actions. All methods in this class return an
|
||||
* icon that is 16x16 unless the method name ends in another size.'
|
||||
*/
|
||||
public class Icons {
|
||||
|
||||
public static final ImageIcon EMPTY_ICON = get("images/EmptyIcon16.gif");
|
||||
public static final Icon EMPTY_ICON = new GIcon("icon.empty");
|
||||
|
||||
public static final ImageIcon HELP_ICON = get("images/help-browser.png");
|
||||
public static final Icon HELP_ICON = new GIcon("icon.help");
|
||||
|
||||
public static final ImageIcon ADD_ICON = get("images/Plus2.png");
|
||||
public static final Icon ADD_ICON = new GIcon("icon.add");
|
||||
|
||||
public static final ImageIcon COLLAPSE_ALL_ICON = get("images/collapse_all.png");
|
||||
public static final ImageIcon EXPAND_ALL_ICON = get("images/expand_all.png");
|
||||
public static final Icon COLLAPSE_ALL_ICON = new GIcon("icon.collapse.all");
|
||||
public static final Icon EXPAND_ALL_ICON = new GIcon("icon.expand.all");
|
||||
|
||||
public static final ImageIcon CONFIGURE_FILTER_ICON = get("images/exec.png");
|
||||
public static final ImageIcon DELETE_ICON = get("images/error.png");
|
||||
public static final ImageIcon ERROR_ICON = get("images/emblem-important.png");
|
||||
public static final Icon CONFIGURE_FILTER_ICON = new GIcon("icon.configure.filter");
|
||||
public static final Icon DELETE_ICON = new GIcon("icon.delete");
|
||||
public static final Icon ERROR_ICON = new GIcon("icon.error");
|
||||
|
||||
public static final ImageIcon NAVIGATE_ON_INCOMING_EVENT_ICON = get("images/locationIn.gif");
|
||||
public static final ImageIcon NAVIGATE_ON_OUTGOING_EVENT_ICON = get("images/locationOut.gif");
|
||||
public static final Icon NAVIGATE_ON_INCOMING_EVENT_ICON = new GIcon("icon.navigate.in");
|
||||
public static final Icon NAVIGATE_ON_OUTGOING_EVENT_ICON = new GIcon("icon.navigate.out");
|
||||
|
||||
public static final ImageIcon NOT_ALLOWED_ICON = get("images/no.png");
|
||||
public static final ImageIcon OPEN_FOLDER_ICON = get("images/openSmallFolder.png");
|
||||
public static final ImageIcon REFRESH_ICON = get("images/reload3.png");
|
||||
public static final Icon NOT_ALLOWED_ICON = new GIcon("icon.notallowed");
|
||||
public static final Icon OPEN_FOLDER_ICON = new GIcon("icon.folder.open");
|
||||
public static final Icon REFRESH_ICON = new GIcon("icon.refresh");
|
||||
|
||||
public static final ImageIcon SORT_ASCENDING_ICON = get("images/sortascending.png");
|
||||
public static final ImageIcon SORT_DESCENDING_ICON = get("images/sortdescending.png");
|
||||
public static final Icon SORT_ASCENDING_ICON = new GIcon("icon.sort.ascending");
|
||||
public static final Icon SORT_DESCENDING_ICON = new GIcon("icon.sort.descending");
|
||||
|
||||
public static final ImageIcon STOP_ICON = get("images/process-stop.png");
|
||||
public static final ImageIcon STRONG_WARNING_ICON = get("images/software-update-urgent.png");
|
||||
public static final Icon STOP_ICON = new GIcon("icon.stop");
|
||||
public static final Icon STRONG_WARNING_ICON = new GIcon("icon.warning.strong");
|
||||
|
||||
public static final ImageIcon LEFT_ICON = get("images/left.png");
|
||||
public static final ImageIcon RIGHT_ICON = get("images/right.png");
|
||||
public static final Icon LEFT_ICON = new GIcon("icon.left");
|
||||
public static final Icon RIGHT_ICON = new GIcon("icon.right");
|
||||
|
||||
/** An version of the LEFT_ICON with a different color */
|
||||
public static final ImageIcon LEFT_ALTERNATE_ICON = get("images/left.alternate.png");
|
||||
public static final Icon LEFT_ALTERNATE_ICON = new GIcon("icon.left.alt");
|
||||
|
||||
/** An version of the RIGHT_ICON with a different color */
|
||||
public static final ImageIcon RIGHT_ALTERNATE_ICON = get("images/right.alternate.png");
|
||||
public static final Icon RIGHT_ALTERNATE_ICON = new GIcon("icon.right.alt");
|
||||
|
||||
public static final ImageIcon SAVE_AS =
|
||||
ResourceManager.getImageIcon(new DotDotDotIcon(get("images/Disk.png")));
|
||||
public static final Icon SAVE_AS =
|
||||
ResourceManager.getImageIcon(new DotDotDotIcon(new GIcon("icon.saveas")));
|
||||
|
||||
public static final ImageIcon MAKE_SELECTION_ICON = get("images/text_align_justify.png");
|
||||
public static final Icon MAKE_SELECTION_ICON = new GIcon("icon.makeselection");
|
||||
|
||||
// Not necessarily re-usable, but this is needed for the help system; these should
|
||||
// Not necessarily re-usable, but this is needed for the help system; these should
|
||||
// probably be moved to the client that uses them, while updating the
|
||||
// help system to use them there.
|
||||
public static final ImageIcon ARROW_DOWN_RIGHT_ICON =
|
||||
ResourceManager.getImageIcon(new RotateIcon(get("images/viewmagfit.png"), 90));
|
||||
public static final ImageIcon ARROW_UP_LEFT_ICON =
|
||||
ResourceManager.getImageIcon(new RotateIcon(get("images/viewmagfit.png"), 275));
|
||||
public static final ImageIcon FILTER_NOT_ACCEPTED_ICON =
|
||||
ResourceManager.getImageIcon(new MultiIcon(get("images/flag.png"), new TranslateIcon(
|
||||
ResourceManager.loadImage("images/dialog-cancel.png", 10, 10), 6, 6)));
|
||||
public static final ImageIcon APPLY_BLOCKED_MATCH_ICON =
|
||||
ResourceManager.getImageIcon(new MultiIcon(get("images/kgpg.png"), new TranslateIcon(
|
||||
ResourceManager.loadImage("images/checkmark_green.gif", 12, 12), 4, 0)));
|
||||
public static final Icon ARROW_DOWN_RIGHT_ICON =
|
||||
ResourceManager.getImageIcon(new RotateIcon(new GIcon("icon.arrow.up.right"), 90));
|
||||
public static final Icon ARROW_UP_LEFT_ICON =
|
||||
ResourceManager.getImageIcon(new RotateIcon(new GIcon("icon.arrow.up.right"), 275));
|
||||
public static final Icon FILTER_NOT_ACCEPTED_ICON =
|
||||
ResourceManager.getImageIcon(new MultiIcon(new GIcon("icon.flag"),
|
||||
new TranslateIcon(ResourceManager.loadImage("icon.notallowed", 10, 10), 6, 6)));
|
||||
public static final Icon APPLY_BLOCKED_MATCH_ICON =
|
||||
ResourceManager.getImageIcon(new MultiIcon(new GIcon("icon.lock"),
|
||||
new TranslateIcon(ResourceManager.loadImage("icon.checkmark.green", 12, 12), 4, 0)));
|
||||
|
||||
/**
|
||||
* Returns true if the given string is a Java code snippet that references this class
|
||||
*
|
||||
*
|
||||
* @param snippet the string to check
|
||||
* @return true if the given string is a Java code snippet that references this class
|
||||
*/
|
||||
@ -97,9 +99,9 @@ public class Icons {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link IconProvider} for the given string value, which is usually the 'src'
|
||||
* attribute of an IMG tag
|
||||
*
|
||||
* Returns an {@link IconProvider} for the given string value, which is usually the 'src'
|
||||
* attribute of an IMG tag
|
||||
*
|
||||
* @param snippet the snippet
|
||||
* @return the icon provider
|
||||
*/
|
||||
@ -123,12 +125,12 @@ public class Icons {
|
||||
* Gets the icon for the given icon path. 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.
|
||||
* <P>
|
||||
* For example, an icon named foo.png would typically be stored in the module at
|
||||
* For example, an icon named foo.png would typically be stored in the module at
|
||||
* "{modulePath}/src/main/resources/image/foo.png". To reference that icon, use the path
|
||||
* "images/foo.png", since "{modulePath}/src/main/resources" is in the classpath.
|
||||
*
|
||||
*
|
||||
* @param iconPath the icon path (relative to the classpath)
|
||||
* @return The icon referenced by that path.
|
||||
* @return The icon referenced by that path.
|
||||
*/
|
||||
public static ImageIcon get(String iconPath) {
|
||||
return ResourceManager.loadImage(iconPath);
|
||||
@ -139,14 +141,14 @@ public class Icons {
|
||||
* 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.
|
||||
* <P>
|
||||
* For example, an icon named foo.png would typically be stored in the module at
|
||||
* For example, an icon named foo.png would typically be stored in the module at
|
||||
* "{modulePath}/src/main/resources/image/foo.png". To reference that icon, use the path
|
||||
* "images/foo.png", since "{modulePath}/src/main/resources" is in the classpath.
|
||||
*
|
||||
*
|
||||
* @param iconPath the icon path (relative to the classpath)
|
||||
* @param width the desired width after scaling
|
||||
* @param height the desired height after scaling
|
||||
* @return The icon referenced by that path.
|
||||
* @return The icon referenced by that path.
|
||||
*/
|
||||
public static ImageIcon get(String iconPath, int width, int height) {
|
||||
return ResourceManager.loadImage(iconPath, width, height);
|
||||
@ -181,10 +183,6 @@ public class Icons {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (icon instanceof UrlImageIcon) {
|
||||
return ((UrlImageIcon) icon).getUrl();
|
||||
}
|
||||
|
||||
// Note: we embed the icon's URL in its description
|
||||
String description = icon.getDescription();
|
||||
if (description == null) {
|
@ -22,10 +22,13 @@ import java.awt.Font;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class GThemeTest extends AbstractGenericTest {
|
||||
|
||||
@ -34,6 +37,8 @@ public class GThemeTest extends AbstractGenericTest {
|
||||
private static final Color COLOR_WITH_ALPHA = new Color(10, 20, 30, 40);
|
||||
private static final String ICON_PATH_1 = "images/arrow.png";
|
||||
private static final String ICON_PATH_2 = "images/disk.png";
|
||||
private static final Icon ICON1 = ResourceManager.loadImage(ICON_PATH_1);
|
||||
private static final Icon ICON2 = ResourceManager.loadImage(ICON_PATH_2);
|
||||
|
||||
private GTheme theme;
|
||||
|
||||
@ -64,8 +69,8 @@ public class GThemeTest extends AbstractGenericTest {
|
||||
|
||||
@Test
|
||||
public void testSetIconPath() {
|
||||
theme.setIcon("icon.a.1", ICON_PATH_1);
|
||||
assertEquals(ICON_PATH_1, theme.getIcon("icon.a.1").get(null));
|
||||
theme.setIcon("icon.a.1", ICON1);
|
||||
assertEquals(ICON1, theme.getIcon("icon.a.1").get(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -84,10 +89,10 @@ public class GThemeTest extends AbstractGenericTest {
|
||||
theme.setFont("x.y.z", COURIER);
|
||||
theme.setFontRef("x.y.z.1", "x.y.z");
|
||||
|
||||
theme.setIcon("icon.a.1", ICON_PATH_1);
|
||||
theme.setIcon("icon.a.2", ICON_PATH_2);
|
||||
theme.setIcon("icon.a.1", ICON1);
|
||||
theme.setIcon("icon.a.2", ICON2);
|
||||
theme.setIconRef("icon.a.3", "icon.a.1");
|
||||
theme.setIcon("t.u.v", ICON_PATH_1);
|
||||
theme.setIcon("t.u.v", ICON1);
|
||||
theme.setIconRef("t.u.v.1", "t.u.v");
|
||||
|
||||
File file = createTempFile("themeTest.theme");
|
||||
|
@ -473,6 +473,27 @@ public class ResourceManager {
|
||||
return getScaledIcon(loadImage, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to load an icon from the given path. Returns the icon or null if no icon was
|
||||
* found from the given path.
|
||||
* <p>
|
||||
*
|
||||
* @param path the icon to load, e.g., "images/home.gif"
|
||||
* @return the ImageIcon if it exists or null
|
||||
*/
|
||||
public static ImageIcon findIcon(String path) {
|
||||
|
||||
// use the wrapper so that images are not loaded until they are needed
|
||||
ImageIcon icon = iconMap.get(path);
|
||||
if (icon == null) {
|
||||
icon = doLoadIcon(path);
|
||||
if (icon != null) {
|
||||
iconMap.put(path, icon);
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the image specified by filename; returns the default bomb icon
|
||||
* if problems occur trying to load the file.
|
||||
@ -483,13 +504,27 @@ public class ResourceManager {
|
||||
public static ImageIcon loadImage(String filename) {
|
||||
ImageIcon icon = iconMap.get(filename);
|
||||
if (icon == null) {
|
||||
icon = doLoadIcon(filename, ResourceManager.getDefaultIcon());
|
||||
icon = doLoadIcon(filename);
|
||||
if (icon == null) {
|
||||
icon = new UnresolvedIcon(filename, getDefaultIcon());
|
||||
}
|
||||
iconMap.put(filename, icon);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
private static ImageIcon doLoadIcon(String filename, ImageIcon defaultIcon) {
|
||||
public static Set<Icon> getLoadedUrlIcons() {
|
||||
Set<Icon> icons = new HashSet<>();
|
||||
for (Icon icon : iconMap.values()) {
|
||||
if (icon instanceof UrlImageIcon) {
|
||||
icons.add(icon);
|
||||
}
|
||||
}
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
private static ImageIcon doLoadIcon(String filename) {
|
||||
// if only the name of an icon is given, but not a path, check to see if it is
|
||||
// a resource that lives under our "images/" folder
|
||||
if (!filename.contains("/")) {
|
||||
@ -516,7 +551,7 @@ public class ResourceManager {
|
||||
}
|
||||
}
|
||||
|
||||
return defaultIcon;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,29 @@
|
||||
/* ###
|
||||
* 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 resources.icons;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
/**
|
||||
* Icon class for when we can't find an icon for a path
|
||||
*/
|
||||
public class UnresolvedIcon extends DerivedImageIcon {
|
||||
|
||||
public UnresolvedIcon(String path, ImageIcon icon) {
|
||||
super("Unresolved: " + path, icon.getImage());
|
||||
}
|
||||
|
||||
}
|
@ -30,6 +30,7 @@ import ghidra.util.Msg;
|
||||
* {@link LazyImageIcon} that is created from a URL to an icon file.
|
||||
*/
|
||||
public class UrlImageIcon extends LazyImageIcon {
|
||||
private String originalPath;
|
||||
private URL imageUrl;
|
||||
|
||||
/**
|
||||
@ -38,14 +39,27 @@ public class UrlImageIcon extends LazyImageIcon {
|
||||
* @param url the {@link URL} to an icon resource file
|
||||
*/
|
||||
public UrlImageIcon(String path, URL url) {
|
||||
super(path);
|
||||
super(url.toExternalForm());
|
||||
this.originalPath = Objects.requireNonNull(path);
|
||||
this.imageUrl = Objects.requireNonNull(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL that was used to create this icon
|
||||
* @return the URL that was used to create this icon
|
||||
*/
|
||||
public URL getUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original path that was used to generate the URL (e.g. images/foo.png)
|
||||
* @return the original path that was used to generate the URL (e.g. images/foo.png)
|
||||
*/
|
||||
public String getOriginalPath() {
|
||||
return originalPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImageIcon createImageIcon() {
|
||||
String name = getFilename();
|
||||
|
@ -254,7 +254,7 @@ public class GProgressBar extends JPanel {
|
||||
activeProgressPanel.add(imageLabel, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
ImageIcon icon = Icons.STOP_ICON;
|
||||
Icon icon = Icons.STOP_ICON;
|
||||
cancelButton = new EmptyBorderButton(icon);
|
||||
|
||||
cancelButton.setName("CANCEL_TASK");
|
||||
|
Loading…
Reference in New Issue
Block a user