mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-1981 added in font support and Icon support
This commit is contained in:
parent
cd4ab3a156
commit
703a7beb8d
56 changed files with 2129 additions and 1060 deletions
|
@ -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 EXPAND_ICON = Icons.EXPAND_ALL_ICON;
|
||||||
private static final Icon COLLAPSE_ICON = Icons.COLLAPSE_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 Icon REFRESH_NOT_NEEDED_ICON = ResourceManager.getDisabledIcon(REFRESH_ICON, 60);
|
||||||
|
|
||||||
private static final String RECURSE_DEPTH_PROPERTY_NAME = "call.tree.recurse.depth";
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
goToSourceAction.setPopupMenuData(
|
goToSourceAction
|
||||||
new MenuData(new String[] { "Go To Call Source" }, goToMenu));
|
.setPopupMenuData(new MenuData(new String[] { "Go To Call Source" }, goToMenu));
|
||||||
goToSourceAction.setHelpLocation(
|
goToSourceAction.setHelpLocation(
|
||||||
new HelpLocation(plugin.getName(), "Call_Tree_Context_Action_Goto_Source"));
|
new HelpLocation(plugin.getName(), "Call_Tree_Context_Action_Goto_Source"));
|
||||||
tool.addLocalAction(this, goToSourceAction);
|
tool.addLocalAction(this, goToSourceAction);
|
||||||
|
@ -369,8 +369,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||||
new ToolBarData(ResourceManager.loadImage("images/application_double.png"),
|
new ToolBarData(ResourceManager.loadImage("images/application_double.png"),
|
||||||
filterOptionsToolbarGroup, "1"));
|
filterOptionsToolbarGroup, "1"));
|
||||||
filterDuplicates.setSelected(true);
|
filterDuplicates.setSelected(true);
|
||||||
filterDuplicates.setHelpLocation(
|
filterDuplicates
|
||||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Filter"));
|
.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Filter"));
|
||||||
tool.addLocalAction(this, filterDuplicates);
|
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" +
|
"<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");
|
"<br> will go. Example operations include <b>Expand All</b> and filtering");
|
||||||
recurseIcon = new NumberIcon(recurseDepth.get());
|
recurseIcon = new NumberIcon(recurseDepth.get());
|
||||||
recurseDepthAction.setToolBarData(
|
recurseDepthAction
|
||||||
new ToolBarData(recurseIcon, filterOptionsToolbarGroup, "2"));
|
.setToolBarData(new ToolBarData(recurseIcon, filterOptionsToolbarGroup, "2"));
|
||||||
recurseDepthAction.setHelpLocation(
|
recurseDepthAction.setHelpLocation(
|
||||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Recurse_Depth"));
|
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");
|
"Listing to<br>the <b>source</b> location of the call");
|
||||||
navigationOutgoingAction.setToolBarData(new ToolBarData(
|
navigationOutgoingAction.setToolBarData(new ToolBarData(
|
||||||
Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON, navigationOptionsToolbarGroup, "1"));
|
Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON, navigationOptionsToolbarGroup, "1"));
|
||||||
navigationOutgoingAction.setHelpLocation(
|
navigationOutgoingAction
|
||||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Navigation"));
|
.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Navigation"));
|
||||||
tool.addLocalAction(this, navigationOutgoingAction);
|
tool.addLocalAction(this, navigationOutgoingAction);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -596,8 +596,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||||
refreshAction.setEnabled(true);
|
refreshAction.setEnabled(true);
|
||||||
refreshAction.setDescription("<html>Push at any time to refresh the current trees.<br>" +
|
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>");
|
"This is highlighted when the data <i>may</i> be stale.<br>");
|
||||||
refreshAction.setHelpLocation(
|
refreshAction
|
||||||
new HelpLocation(plugin.getName(), "Call_Tree_Action_Refresh"));
|
.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Refresh"));
|
||||||
tool.addLocalAction(this, refreshAction);
|
tool.addLocalAction(this, refreshAction);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -671,8 +671,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||||
"Call_Tree_Context_Action_Show_Call_Tree_For_Function"));
|
"Call_Tree_Context_Action_Show_Call_Tree_For_Function"));
|
||||||
newCallTree.setPopupMenuData(new MenuData(new String[] { "Show Call Tree For Function" },
|
newCallTree.setPopupMenuData(new MenuData(new String[] { "Show Call Tree For Function" },
|
||||||
CallTreePlugin.PROVIDER_ICON, newTreeMenu));
|
CallTreePlugin.PROVIDER_ICON, newTreeMenu));
|
||||||
newCallTree.setDescription("Show the Function Call Tree window for the function " +
|
newCallTree.setDescription(
|
||||||
"selected in the call tree");
|
"Show the Function Call Tree window for the function " + "selected in the call tree");
|
||||||
tool.addLocalAction(this, newCallTree);
|
tool.addLocalAction(this, newCallTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@ class ParseDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
saveAction.setEnabled(false);
|
saveAction.setEnabled(false);
|
||||||
ImageIcon icon = ResourceManager.loadImage("images/disk.png");
|
Icon icon = ResourceManager.loadImage("images/disk.png");
|
||||||
String saveGroup = "save";
|
String saveGroup = "save";
|
||||||
saveAction.setMenuBarData(new MenuData(new String[] { "Save" }, icon, saveGroup));
|
saveAction.setMenuBarData(new MenuData(new String[] { "Save" }, icon, saveGroup));
|
||||||
saveAction.setToolBarData(new ToolBarData(icon, saveGroup));
|
saveAction.setToolBarData(new ToolBarData(icon, saveGroup));
|
||||||
|
@ -371,8 +371,8 @@ class ParseDialog extends DialogComponentProvider {
|
||||||
clearAction.setEnabled(true);
|
clearAction.setEnabled(true);
|
||||||
icon = ResourceManager.loadImage("images/erase16.png");
|
icon = ResourceManager.loadImage("images/erase16.png");
|
||||||
String clearGroup = "clear";
|
String clearGroup = "clear";
|
||||||
clearAction.setMenuBarData(
|
clearAction
|
||||||
new MenuData(new String[] { "Clear Profile" }, icon, clearGroup));
|
.setMenuBarData(new MenuData(new String[] { "Clear Profile" }, icon, clearGroup));
|
||||||
clearAction.setToolBarData(new ToolBarData(icon, clearGroup));
|
clearAction.setToolBarData(new ToolBarData(icon, clearGroup));
|
||||||
clearAction.setDescription("Clear profile");
|
clearAction.setDescription("Clear profile");
|
||||||
addAction(clearAction);
|
addAction(clearAction);
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.awt.event.InputEvent;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.tree.TreePath;
|
import javax.swing.tree.TreePath;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
|
@ -40,7 +40,7 @@ import resources.Icons;
|
||||||
*/
|
*/
|
||||||
public class CollapseAllArchivesAction extends DockingAction {
|
public class CollapseAllArchivesAction extends DockingAction {
|
||||||
|
|
||||||
private ImageIcon collapseIcon = Icons.COLLAPSE_ALL_ICON;
|
private Icon collapseIcon = Icons.COLLAPSE_ALL_ICON;
|
||||||
private final DataTypeManagerPlugin plugin;
|
private final DataTypeManagerPlugin plugin;
|
||||||
|
|
||||||
public CollapseAllArchivesAction(DataTypeManagerPlugin plugin) {
|
public CollapseAllArchivesAction(DataTypeManagerPlugin plugin) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ import docking.ActionContext;
|
||||||
import docking.ComponentProvider;
|
import docking.ComponentProvider;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.actions.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.options.editor.FontPropertyEditor;
|
import docking.options.editor.FontEditor;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.filechooser.GhidraFileChooser;
|
import docking.widgets.filechooser.GhidraFileChooser;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
|
@ -287,7 +287,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doSelectFont() {
|
protected void doSelectFont() {
|
||||||
FontPropertyEditor editor = new FontPropertyEditor();
|
FontEditor editor = new FontEditor();
|
||||||
editor.setValue(defaultFont);
|
editor.setValue(defaultFont);
|
||||||
editor.showDialog();
|
editor.showDialog();
|
||||||
defaultFont = (Font) editor.getValue();
|
defaultFont = (Font) editor.getValue();
|
||||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.functioncompare.actions;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import docking.action.ToggleDockingAction;
|
import docking.action.ToggleDockingAction;
|
||||||
import docking.action.ToolBarData;
|
import docking.action.ToolBarData;
|
||||||
|
@ -48,7 +48,7 @@ public class NavigateToFunctionAction extends ToggleDockingAction {
|
||||||
|
|
||||||
private GoToService goToService;
|
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
|
* Constructor
|
||||||
|
@ -64,10 +64,9 @@ public class NavigateToFunctionAction extends ToggleDockingAction {
|
||||||
setSelected(false);
|
setSelected(false);
|
||||||
ToolBarData newToolBarData = new ToolBarData(NAV_FUNCTION_ICON);
|
ToolBarData newToolBarData = new ToolBarData(NAV_FUNCTION_ICON);
|
||||||
setToolBarData(newToolBarData);
|
setToolBarData(newToolBarData);
|
||||||
setDescription(
|
setDescription(HTMLUtilities.toHTML("Toggle <b>On</b> means to navigate to whatever " +
|
||||||
HTMLUtilities.toHTML("Toggle <b>On</b> means to navigate to whatever " +
|
"function is selected in the comparison panel, when focus changes or" +
|
||||||
"function is selected in the comparison panel, when focus changes or" +
|
"a new function is selected."));
|
||||||
"a new function is selected."));
|
|
||||||
setHelpLocation(
|
setHelpLocation(
|
||||||
new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC, "Navigate_To_Function"));
|
new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC, "Navigate_To_Function"));
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ package ghidra.app.plugin.core.interpreter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.console.CodeCompletion;
|
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.
|
* @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.
|
* 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.*;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.actions.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.options.editor.FontPropertyEditor;
|
import docking.options.editor.FontEditor;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.app.script.GhidraScriptUtil;
|
import ghidra.app.script.GhidraScriptUtil;
|
||||||
|
@ -516,7 +516,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doSelectFont() {
|
private void doSelectFont() {
|
||||||
FontPropertyEditor editor = new FontPropertyEditor();
|
FontEditor editor = new FontEditor();
|
||||||
editor.setValue(defaultFont);
|
editor.setValue(defaultFont);
|
||||||
editor.showDialog();
|
editor.showDialog();
|
||||||
defaultFont = (Font) editor.getValue();
|
defaultFont = (Font) editor.getValue();
|
||||||
|
|
|
@ -39,7 +39,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
static final String SCRIPT_STATUS_COLUMN_NAME = "Status";
|
static final String SCRIPT_STATUS_COLUMN_NAME = "Status";
|
||||||
|
|
||||||
private static final String EMPTY_STRING = "";
|
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 GhidraScriptComponentProvider provider;
|
||||||
private List<ResourceFile> scriptList = new ArrayList<>();
|
private List<ResourceFile> scriptList = new ArrayList<>();
|
||||||
|
@ -217,8 +217,8 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
Swing.runIfSwingOrRunLater(() -> super.fireTableChanged(e));
|
Swing.runIfSwingOrRunLater(() -> super.fireTableChanged(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StatusColumn extends AbstractDynamicTableColumn<ResourceFile, ImageIcon, Object> {
|
private class StatusColumn extends AbstractDynamicTableColumn<ResourceFile, Icon, Object> {
|
||||||
private Comparator<ImageIcon> comparator = (i1, i2) -> {
|
private Comparator<Icon> comparator = (i1, i2) -> {
|
||||||
if (i1 == i2) {
|
if (i1 == i2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -234,12 +234,19 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
if (i2 == null) {
|
if (i2 == null) {
|
||||||
return -1; // empty after icon
|
return -1; // empty after icon
|
||||||
}
|
}
|
||||||
String d1 = i1.getDescription();
|
String d1 = getDescription(i1);
|
||||||
String d2 = i2.getDescription();
|
String d2 = getDescription(i2);
|
||||||
return SystemUtilities.compareTo(d1, d2);
|
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
|
@Override
|
||||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
||||||
|
@ -269,14 +276,14 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// we could use the tooltip text, but it doesn't seem worth it
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GColumnRenderer<ImageIcon> getColumnRenderer() {
|
public GColumnRenderer<Icon> getColumnRenderer() {
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +293,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageIcon getValue(ResourceFile rowObject, Settings settings, Object data,
|
public Icon getValue(ResourceFile rowObject, Settings settings, Object data,
|
||||||
ServiceProvider sp) throws IllegalArgumentException {
|
ServiceProvider sp) throws IllegalArgumentException {
|
||||||
ScriptInfo info = infoManager.getExistingScriptInfo(rowObject);
|
ScriptInfo info = infoManager.getExistingScriptInfo(rowObject);
|
||||||
if (info.isCompileErrors() || info.isDuplicate()) {
|
if (info.isCompileErrors() || info.isDuplicate()) {
|
||||||
|
@ -296,7 +303,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Comparator<ImageIcon> getComparator() {
|
public Comparator<Icon> getComparator() {
|
||||||
return comparator;
|
return comparator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.symtable;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
@ -231,8 +231,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
case ChangeManager.DOCR_CODE_ADDED:
|
case ChangeManager.DOCR_CODE_ADDED:
|
||||||
case ChangeManager.DOCR_CODE_REMOVED:
|
case ChangeManager.DOCR_CODE_REMOVED:
|
||||||
if (rec.getNewValue() instanceof Data) {
|
if (rec.getNewValue() instanceof Data) {
|
||||||
domainObjectWorker.schedule(
|
domainObjectWorker
|
||||||
new CodeAddedRemoveJob(currentProgram, rec.getStart()));
|
.schedule(new CodeAddedRemoveJob(currentProgram, rec.getStart()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -241,16 +241,15 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
// dynamic label symbols. Reference events must be used to check for existence
|
// dynamic label symbols. Reference events must be used to check for existence
|
||||||
// of a dynamic label symbol.
|
// of a dynamic label symbol.
|
||||||
Symbol symbol = (Symbol) rec.getNewValue();
|
Symbol symbol = (Symbol) rec.getNewValue();
|
||||||
domainObjectWorker.schedule(
|
domainObjectWorker.schedule(new SymbolAddedJob(currentProgram, symbol));
|
||||||
new SymbolAddedJob(currentProgram, symbol));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_REMOVED:
|
case ChangeManager.DOCR_SYMBOL_REMOVED:
|
||||||
|
|
||||||
Address removeAddr = rec.getStart();
|
Address removeAddr = rec.getStart();
|
||||||
Long symbolID = (Long) rec.getNewValue();
|
Long symbolID = (Long) rec.getNewValue();
|
||||||
domainObjectWorker.schedule(
|
domainObjectWorker
|
||||||
new SymbolRemovedJob(currentProgram, removeAddr, symbolID));
|
.schedule(new SymbolRemovedJob(currentProgram, removeAddr, symbolID));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChangeManager.DOCR_SYMBOL_RENAMED:
|
case ChangeManager.DOCR_SYMBOL_RENAMED:
|
||||||
|
@ -294,8 +293,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED:
|
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED:
|
||||||
|
|
||||||
Address address = rec.getStart();
|
Address address = rec.getStart();
|
||||||
domainObjectWorker.schedule(
|
domainObjectWorker
|
||||||
new ExternalEntryChangedJob(currentProgram, address));
|
.schedule(new ExternalEntryChangedJob(currentProgram, address));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +343,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
refProvider.setCurrentSymbol(symProvider.getCurrentSymbol());
|
refProvider.setCurrentSymbol(symProvider.getCurrentSymbol());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ImageIcon icon = ResourceManager.loadImage("images/table_go.png");
|
Icon icon = ResourceManager.loadImage("images/table_go.png");
|
||||||
openRefsAction.setPopupMenuData(
|
openRefsAction.setPopupMenuData(
|
||||||
new MenuData(new String[] { "Symbol References" }, icon, popupGroup));
|
new MenuData(new String[] { "Symbol References" }, icon, popupGroup));
|
||||||
openRefsAction.setToolBarData(new ToolBarData(icon));
|
openRefsAction.setToolBarData(new ToolBarData(icon));
|
||||||
|
@ -467,8 +466,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
};
|
};
|
||||||
instructionsFromAction.setDescription("Instructions From");
|
instructionsFromAction.setDescription("Instructions From");
|
||||||
instructionsFromAction.setSelected(false);
|
instructionsFromAction.setSelected(false);
|
||||||
instructionsFromAction.setToolBarData(
|
instructionsFromAction
|
||||||
new ToolBarData(ResourceManager.loadImage("images/I.gif"), null));
|
.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/I.gif"), null));
|
||||||
|
|
||||||
tool.addLocalAction(refProvider, instructionsFromAction);
|
tool.addLocalAction(refProvider, instructionsFromAction);
|
||||||
|
|
||||||
|
@ -490,8 +489,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
};
|
};
|
||||||
dataFromAction.setDescription("Data From");
|
dataFromAction.setDescription("Data From");
|
||||||
dataFromAction.setSelected(false);
|
dataFromAction.setSelected(false);
|
||||||
dataFromAction.setToolBarData(
|
dataFromAction
|
||||||
new ToolBarData(ResourceManager.loadImage("images/D.gif"), null));
|
.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/D.gif"), null));
|
||||||
|
|
||||||
tool.addLocalAction(refProvider, dataFromAction);
|
tool.addLocalAction(refProvider, dataFromAction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.debug;
|
package ghidra.app.plugin.debug;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
|
@ -73,7 +73,7 @@ public class DbViewerPlugin extends Plugin {
|
||||||
};
|
};
|
||||||
|
|
||||||
refreshAction.setEnabled(false);
|
refreshAction.setEnabled(false);
|
||||||
ImageIcon icon = Icons.REFRESH_ICON;
|
Icon icon = Icons.REFRESH_ICON;
|
||||||
refreshAction.setToolBarData(new ToolBarData(icon));
|
refreshAction.setToolBarData(new ToolBarData(icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import docking.action.builder.ActionBuilder;
|
||||||
import docking.theme.gui.ThemeDialog;
|
import docking.theme.gui.ThemeDialog;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.framework.main.FrontEndOnly;
|
import ghidra.framework.main.ApplicationLevelOnlyPlugin;
|
||||||
import ghidra.framework.main.FrontEndTool;
|
import ghidra.framework.main.FrontEndTool;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
@ -35,7 +35,7 @@ import ghidra.util.SystemUtilities;
|
||||||
"This plugin is available only in the Ghidra Project Window."
|
"This plugin is available only in the Ghidra Project Window."
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class ThemeManagerPlugin extends Plugin implements FrontEndOnly {
|
public class ThemeManagerPlugin extends Plugin implements ApplicationLevelOnlyPlugin {
|
||||||
|
|
||||||
public ThemeManagerPlugin(PluginTool tool) {
|
public ThemeManagerPlugin(PluginTool tool) {
|
||||||
super(tool);
|
super(tool);
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.plugins.fsbrowser;
|
package ghidra.plugins.fsbrowser;
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import resources.Icons;
|
import resources.Icons;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
@ -28,43 +28,43 @@ import resources.ResourceManager;
|
||||||
*/
|
*/
|
||||||
public class ImageManager {
|
public class ImageManager {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
public final static ImageIcon COPY = ResourceManager.loadImage("images/page_copy.png");
|
public final static Icon COPY = ResourceManager.loadImage("images/page_copy.png");
|
||||||
public final static ImageIcon CUT = ResourceManager.loadImage("images/edit-cut.png");
|
public final static Icon CUT = ResourceManager.loadImage("images/edit-cut.png");
|
||||||
public final static ImageIcon DELETE = ResourceManager.loadImage("images/page_delete.png");
|
public final static Icon DELETE = ResourceManager.loadImage("images/page_delete.png");
|
||||||
public final static ImageIcon FONT = ResourceManager.loadImage("images/text_lowercase.png");
|
public final static Icon FONT = ResourceManager.loadImage("images/text_lowercase.png");
|
||||||
public final static ImageIcon LOCKED = ResourceManager.loadImage("images/lock.gif");
|
public final static Icon LOCKED = ResourceManager.loadImage("images/lock.gif");
|
||||||
public final static ImageIcon NEW = ResourceManager.loadImage("images/page_add.png");
|
public final static Icon NEW = ResourceManager.loadImage("images/page_add.png");
|
||||||
public final static ImageIcon PASTE = ResourceManager.loadImage("images/page_paste.png");
|
public final static Icon PASTE = ResourceManager.loadImage("images/page_paste.png");
|
||||||
public final static ImageIcon REDO = ResourceManager.loadImage("images/redo.png");
|
public final static Icon REDO = ResourceManager.loadImage("images/redo.png");
|
||||||
public final static ImageIcon RENAME = ResourceManager.loadImage("images/textfield_rename.png");
|
public final static Icon RENAME = ResourceManager.loadImage("images/textfield_rename.png");
|
||||||
public final static ImageIcon REFRESH = Icons.REFRESH_ICON;
|
public final static Icon REFRESH = Icons.REFRESH_ICON;
|
||||||
public final static ImageIcon SAVE = ResourceManager.loadImage("images/disk.png");
|
public final static Icon SAVE = ResourceManager.loadImage("images/disk.png");
|
||||||
public final static ImageIcon SAVE_AS = ResourceManager.loadImage("images/disk_save_as.png");
|
public final static Icon SAVE_AS = ResourceManager.loadImage("images/disk_save_as.png");
|
||||||
public final static ImageIcon UNDO = ResourceManager.loadImage("images/undo.png");
|
public final static Icon UNDO = ResourceManager.loadImage("images/undo.png");
|
||||||
public final static ImageIcon UNLOCKED = ResourceManager.loadImage("images/unlock.gif");
|
public final static Icon UNLOCKED = ResourceManager.loadImage("images/unlock.gif");
|
||||||
public final static ImageIcon CLOSE = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door.png");
|
public final static Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon EXTRACT = ResourceManager.loadImage("images/package_green.png");
|
||||||
public final static ImageIcon INFO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/information.png");
|
public final static Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon VIEW_AS_TEXT = ResourceManager.loadImage("images/format-text-bold.png");
|
||||||
public final static ImageIcon UNKNOWN = ResourceManager.loadImage("images/help-browser.png");
|
public final static Icon UNKNOWN = ResourceManager.loadImage("images/help-browser.png");
|
||||||
public final static ImageIcon IPOD = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/ipod.png");
|
public final static Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 Icon 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 LIST_MOUNTED = ResourceManager.loadImage("images/downArrow.png");
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ public class InterpreterPanelTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageIcon getIcon() {
|
public Icon getIcon() {
|
||||||
return Icons.STOP_ICON;
|
return Icons.STOP_ICON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,8 +222,7 @@ public class InterpreterPanelTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doSwingMultilinePasteTest(List<String> multiLineTestValues)
|
private void doSwingMultilinePasteTest(List<String> multiLineTestValues) throws IOException {
|
||||||
throws IOException {
|
|
||||||
// simulates what happens during a paste when multi-line string with
|
// simulates what happens during a paste when multi-line string with
|
||||||
// "\n"s is pasted.
|
// "\n"s is pasted.
|
||||||
runSwingLater(() -> {
|
runSwingLater(() -> {
|
||||||
|
|
|
@ -107,13 +107,10 @@ class SymbolServerPanel extends JPanel {
|
||||||
JPanel buttonPanel = buildButtonPanel();
|
JPanel buttonPanel = buildButtonPanel();
|
||||||
JScrollPane tableScrollPane = buildTable();
|
JScrollPane tableScrollPane = buildTable();
|
||||||
defaultConfigNotice = new JPanel();
|
defaultConfigNotice = new JPanel();
|
||||||
defaultConfigNotice.add(
|
defaultConfigNotice.add(new GHtmlLabel(
|
||||||
new GHtmlLabel(
|
"<html><center><font color=red><br>" + "Missing / invalid configuration.<br><br>" +
|
||||||
"<html><center><font color=red><br>" +
|
"Using default search location:<br>" + "Program's Import Location<br>",
|
||||||
"Missing / invalid configuration.<br><br>" +
|
SwingConstants.CENTER));
|
||||||
"Using default search location:<br>" +
|
|
||||||
"Program's Import Location<br>",
|
|
||||||
SwingConstants.CENTER));
|
|
||||||
defaultConfigNotice.setPreferredSize(tableScrollPane.getPreferredSize());
|
defaultConfigNotice.setPreferredSize(tableScrollPane.getPreferredSize());
|
||||||
|
|
||||||
additionalSearchLocationsPanel = new JPanel();
|
additionalSearchLocationsPanel = new JPanel();
|
||||||
|
@ -199,55 +196,47 @@ class SymbolServerPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private JPanel buildButtonPanel() {
|
private JPanel buildButtonPanel() {
|
||||||
refreshSearchLocationsStatusButton = createImageButton(Icons.REFRESH_ICON, "Refresh Status",
|
refreshSearchLocationsStatusButton =
|
||||||
ButtonPanelFactory.ARROW_SIZE);
|
createImageButton(Icons.REFRESH_ICON, "Refresh Status", ButtonPanelFactory.ARROW_SIZE);
|
||||||
refreshSearchLocationsStatusButton.addActionListener(e -> refreshSearchLocationStatus());
|
refreshSearchLocationsStatusButton.addActionListener(e -> refreshSearchLocationStatus());
|
||||||
DockingWindowManager.getHelpService()
|
DockingWindowManager.getHelpService()
|
||||||
.registerHelp(refreshSearchLocationsStatusButton,
|
.registerHelp(refreshSearchLocationsStatusButton, new HelpLocation(
|
||||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Refresh Status"));
|
||||||
"SymbolServerConfig Refresh Status"));
|
|
||||||
|
|
||||||
moveLocationUpButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_UP_TYPE);
|
moveLocationUpButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_UP_TYPE);
|
||||||
moveLocationUpButton.addActionListener(e -> moveLocation(-1));
|
moveLocationUpButton.addActionListener(e -> moveLocation(-1));
|
||||||
moveLocationUpButton.setToolTipText("Move location up");
|
moveLocationUpButton.setToolTipText("Move location up");
|
||||||
DockingWindowManager.getHelpService()
|
DockingWindowManager.getHelpService()
|
||||||
.registerHelp(moveLocationUpButton,
|
.registerHelp(moveLocationUpButton, new HelpLocation(
|
||||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig MoveUpDown"));
|
||||||
"SymbolServerConfig MoveUpDown"));
|
|
||||||
|
|
||||||
moveLocationDownButton =
|
moveLocationDownButton =
|
||||||
ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_DOWN_TYPE);
|
ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_DOWN_TYPE);
|
||||||
moveLocationDownButton.addActionListener(e -> moveLocation(1));
|
moveLocationDownButton.addActionListener(e -> moveLocation(1));
|
||||||
moveLocationDownButton.setToolTipText("Move location down");
|
moveLocationDownButton.setToolTipText("Move location down");
|
||||||
DockingWindowManager.getHelpService()
|
DockingWindowManager.getHelpService()
|
||||||
.registerHelp(moveLocationDownButton,
|
.registerHelp(moveLocationDownButton, new HelpLocation(
|
||||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig MoveUpDown"));
|
||||||
"SymbolServerConfig MoveUpDown"));
|
|
||||||
|
|
||||||
deleteLocationButton = createImageButton(Icons.DELETE_ICON, "Delete",
|
deleteLocationButton =
|
||||||
ButtonPanelFactory.ARROW_SIZE);
|
createImageButton(Icons.DELETE_ICON, "Delete", ButtonPanelFactory.ARROW_SIZE);
|
||||||
deleteLocationButton.addActionListener(e -> deleteLocation());
|
deleteLocationButton.addActionListener(e -> deleteLocation());
|
||||||
DockingWindowManager.getHelpService()
|
DockingWindowManager.getHelpService()
|
||||||
.registerHelp(deleteLocationButton,
|
.registerHelp(deleteLocationButton,
|
||||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Delete"));
|
||||||
"SymbolServerConfig Delete"));
|
|
||||||
|
|
||||||
addLocationButton = createImageButton(Icons.ADD_ICON, "Add",
|
addLocationButton = createImageButton(Icons.ADD_ICON, "Add", ButtonPanelFactory.ARROW_SIZE);
|
||||||
ButtonPanelFactory.ARROW_SIZE);
|
|
||||||
addLocationButton.addActionListener(e -> addLocation());
|
addLocationButton.addActionListener(e -> addLocation());
|
||||||
DockingWindowManager.getHelpService()
|
DockingWindowManager.getHelpService()
|
||||||
.registerHelp(addLocationButton,
|
.registerHelp(addLocationButton,
|
||||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Add"));
|
||||||
"SymbolServerConfig Add"));
|
|
||||||
|
|
||||||
saveSearchLocationsButton =
|
saveSearchLocationsButton = ButtonPanelFactory.createImageButton(
|
||||||
ButtonPanelFactory.createImageButton(Icons.get("images/disk.png"),
|
Icons.get("images/disk.png"), "Save Configuration", ButtonPanelFactory.ARROW_SIZE);
|
||||||
"Save Configuration", ButtonPanelFactory.ARROW_SIZE);
|
|
||||||
saveSearchLocationsButton.addActionListener(e -> saveConfig());
|
saveSearchLocationsButton.addActionListener(e -> saveConfig());
|
||||||
DockingWindowManager.getHelpService()
|
DockingWindowManager.getHelpService()
|
||||||
.registerHelp(saveSearchLocationsButton,
|
.registerHelp(saveSearchLocationsButton,
|
||||||
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC,
|
new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Save"));
|
||||||
"SymbolServerConfig Save"));
|
|
||||||
|
|
||||||
JPanel buttonPanel = new JPanel();
|
JPanel buttonPanel = new JPanel();
|
||||||
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
|
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
|
||||||
|
@ -325,8 +314,7 @@ class SymbolServerPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowGUIPrompt && isEmptyDirectory(symbolStorageDir)) {
|
if (allowGUIPrompt && isEmptyDirectory(symbolStorageDir)) {
|
||||||
if (OptionDialog.showYesNoDialog(this,
|
if (OptionDialog.showYesNoDialog(this, "Initialize Symbol Storage Directory?",
|
||||||
"Initialize Symbol Storage Directory?",
|
|
||||||
"<html>Initialize new directory as Microsoft symbol storage directory?") == OptionDialog.YES_OPTION) {
|
"<html>Initialize new directory as Microsoft symbol storage directory?") == OptionDialog.YES_OPTION) {
|
||||||
try {
|
try {
|
||||||
LocalSymbolStore.create(symbolStorageDir,
|
LocalSymbolStore.create(symbolStorageDir,
|
||||||
|
@ -495,8 +483,8 @@ class SymbolServerPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDirectoryLocation() {
|
private void addDirectoryLocation() {
|
||||||
File dir = FilePromptDialog.chooseDirectory("Enter Path", "Symbol Storage Location: ",
|
File dir =
|
||||||
null);
|
FilePromptDialog.chooseDirectory("Enter Path", "Symbol Storage Location: ", null);
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -574,7 +562,7 @@ class SymbolServerPanel extends JPanel {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JButton createImageButton(ImageIcon buttonIcon, String alternateText,
|
private static JButton createImageButton(Icon buttonIcon, String alternateText,
|
||||||
Dimension preferredSize) {
|
Dimension preferredSize) {
|
||||||
|
|
||||||
JButton button = ButtonPanelFactory.createButton("");
|
JButton button = ButtonPanelFactory.createButton("");
|
||||||
|
@ -584,7 +572,7 @@ class SymbolServerPanel extends JPanel {
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
static StatusText getSymbolServerWarnings(List<SymbolServer> symbolServers) {
|
static StatusText getSymbolServerWarnings(List<SymbolServer> symbolServers) {
|
||||||
Map<String, String> warningsByLocation = new HashMap<>();
|
Map<String, String> warningsByLocation = new HashMap<>();
|
||||||
for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) {
|
for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) {
|
||||||
|
@ -592,8 +580,7 @@ class SymbolServerPanel extends JPanel {
|
||||||
warningsByLocation.put(ssloc.getLocation(), ssloc.getWarning());
|
warningsByLocation.put(ssloc.getLocation(), ssloc.getWarning());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String warning = symbolServers
|
String warning = symbolServers.stream()
|
||||||
.stream()
|
|
||||||
.map(symbolServer -> warningsByLocation.get(symbolServer.getName()))
|
.map(symbolServer -> warningsByLocation.get(symbolServer.getName()))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.distinct()
|
.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 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_TEXT_AREA = "Diff Details Text Area";
|
||||||
public static final String DIFF_DETAILS_PANEL = "Diff Location Details Panel";
|
public static final String DIFF_DETAILS_PANEL = "Diff Location Details Panel";
|
||||||
public static final ImageIcon ICON = ResourceManager.loadImage("images/xmag.png");
|
public static final Icon ICON = ResourceManager.loadImage("images/xmag.png");
|
||||||
public static final ImageIcon REFRESH_ICON = Icons.REFRESH_ICON;
|
public static final Icon REFRESH_ICON = Icons.REFRESH_ICON;
|
||||||
public static final String TITLE = "Diff Details";
|
public static final String TITLE = "Diff Details";
|
||||||
|
|
||||||
private ProgramDiffPlugin plugin;
|
private ProgramDiffPlugin plugin;
|
||||||
|
@ -121,8 +121,8 @@ public class DiffDetailsProvider extends ComponentProviderAdapter {
|
||||||
refreshDetailsAction.setEnabled(true);
|
refreshDetailsAction.setEnabled(true);
|
||||||
|
|
||||||
refreshDetailsAction.setToolBarData(new ToolBarData(REFRESH_ICON, "Diff"));
|
refreshDetailsAction.setToolBarData(new ToolBarData(REFRESH_ICON, "Diff"));
|
||||||
refreshDetailsAction.setHelpLocation(
|
refreshDetailsAction
|
||||||
new HelpLocation(HelpTopics.DIFF, "Refresh Diff Details"));
|
.setHelpLocation(new HelpLocation(HelpTopics.DIFF, "Refresh Diff Details"));
|
||||||
plugin.getTool().addLocalAction(this, refreshDetailsAction);
|
plugin.getTool().addLocalAction(this, refreshDetailsAction);
|
||||||
// plugin.getTool().addLocalAction(this, new DiffIgnoreAllAction(this));
|
// 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.highlight = color.bg.highlight
|
||||||
color.bg.fieldpanel.selection-highlight = green
|
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]
|
[Dark Defaults]
|
||||||
|
|
|
@ -29,7 +29,9 @@ import docking.DockingWindowManager;
|
||||||
import docking.widgets.label.GDHtmlLabel;
|
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 {
|
public class ColorEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
|
@ -42,10 +44,6 @@ public class ColorEditor extends PropertyEditorSupport {
|
||||||
private Color color;
|
private Color color;
|
||||||
private Color lastUserSelectedColor;
|
private Color lastUserSelectedColor;
|
||||||
|
|
||||||
/**
|
|
||||||
* The default constructor.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public ColorEditor() {
|
public ColorEditor() {
|
||||||
previewLabel.setOpaque(true);
|
previewLabel.setOpaque(true);
|
||||||
previewLabel.setPreferredSize(new Dimension(100, 20));
|
previewLabel.setPreferredSize(new Dimension(100, 20));
|
||||||
|
@ -72,42 +70,16 @@ public class ColorEditor extends PropertyEditorSupport {
|
||||||
DockingWindowManager.showDialog(previewLabel, provider);
|
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
|
@Override
|
||||||
public Component getCustomEditor() {
|
public Component getCustomEditor() {
|
||||||
return previewLabel;
|
return previewLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the propertyEditor can provide a custom editor.
|
|
||||||
*
|
|
||||||
* @return True if the propertyEditor can provide a custom editor.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsCustomEditor() {
|
public boolean supportsCustomEditor() {
|
||||||
return true;
|
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
|
@Override
|
||||||
public void setValue(Object value) {
|
public void setValue(Object value) {
|
||||||
color = (Color) value;
|
color = (Color) value;
|
||||||
|
@ -130,33 +102,16 @@ public class ColorEditor extends PropertyEditorSupport {
|
||||||
previewLabel.setBackground(color);
|
previewLabel.setBackground(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true which this editor can paint its property value.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPaintable() {
|
public boolean isPaintable() {
|
||||||
return false;
|
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
|
@Override
|
||||||
public void paintValue(Graphics gfx, Rectangle box) {
|
public void paintValue(Graphics gfx, Rectangle box) {
|
||||||
if (color != null) {
|
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
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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() {
|
public void run() {
|
||||||
PropertyEditorManager.registerEditor(String.class, StringEditor.class);
|
PropertyEditorManager.registerEditor(String.class, StringEditor.class);
|
||||||
PropertyEditorManager.registerEditor(Color.class, ColorEditor.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(Enum.class, EnumEditor.class);
|
||||||
PropertyEditorManager.registerEditor(Boolean.class, BooleanEditor.class);
|
PropertyEditorManager.registerEditor(Boolean.class, BooleanEditor.class);
|
||||||
PropertyEditorManager.registerEditor(Date.class, DateEditor.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;
|
package docking.options.editor;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.beans.PropertyEditorSupport;
|
import java.beans.PropertyEditorSupport;
|
||||||
import java.util.ArrayList;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Objects;
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.IntStream;
|
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.combobox.GComboBox;
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
|
import ghidra.util.Swing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Bean FontEditor displays a String with the current selected font name,
|
* Property Editor for editing {@link Font}s
|
||||||
* style and size attributes.
|
|
||||||
*/
|
*/
|
||||||
public class FontPropertyEditor extends PropertyEditorSupport {
|
public class FontPropertyEditor extends PropertyEditorSupport {
|
||||||
private Font font;
|
public final static String SAMPLE_STRING = "ABCabc \u00a9\u00ab\u00a7\u0429\u05d1\u062c\u4eb9";
|
||||||
// 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);
|
|
||||||
|
|
||||||
/**
|
private FontChooserPanel fontChooserPanel;
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Object o) {
|
public Component getCustomEditor() {
|
||||||
font = (Font) o;
|
fontChooserPanel = new FontChooserPanel();
|
||||||
previewButton.setFont(font);
|
fontChooserPanel.updateControls((Font) getValue());
|
||||||
|
return fontChooserPanel;
|
||||||
// set the font values on the widget
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValue() {
|
|
||||||
return font;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -92,205 +51,204 @@ public class FontPropertyEditor extends PropertyEditorSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getCustomEditor() {
|
public void setValue(Object value) {
|
||||||
return previewButton;
|
if (fontChooserPanel != null) {
|
||||||
|
fontChooserPanel.updateControls((Font) value);
|
||||||
|
}
|
||||||
|
if (!Objects.equals(value, getValue())) {
|
||||||
|
super.setValue(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
class FontChooserPanel extends JPanel {
|
||||||
// Inner Classes
|
|
||||||
//==================================================================================================
|
|
||||||
|
|
||||||
private class FontPanel extends JPanel implements ActionListener {
|
private GDLabel previewLabel;
|
||||||
JLabel fontLabel, sizeLabel, styleLabel;
|
private GComboBox<FontWrapper> fontCombo;
|
||||||
JLabel fontStringLabel;
|
private GComboBox<Integer> sizeCombo;
|
||||||
JComboBox<FontWrapper> fonts;
|
private GComboBox<String> styleCombo;
|
||||||
JComboBox<Integer> sizes;
|
private ActionListener actionListener = e -> fontChanged();
|
||||||
JComboBox<String> styles;
|
|
||||||
int styleChoice;
|
|
||||||
int sizeChoice;
|
|
||||||
|
|
||||||
FontPanel() {
|
public FontChooserPanel() {
|
||||||
init();
|
build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void updateControls(Font font) {
|
||||||
this.setLayout(new BorderLayout());
|
if (font == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updatePreviewLabel(font);
|
||||||
|
|
||||||
JPanel topPanel = new JPanel();
|
fontCombo.removeActionListener(actionListener);
|
||||||
JPanel fontPanel = new JPanel();
|
sizeCombo.removeActionListener(actionListener);
|
||||||
JPanel sizePanel = new JPanel();
|
styleCombo.removeActionListener(actionListener);
|
||||||
JPanel stylePanel = new JPanel();
|
|
||||||
JPanel sizeAndStylePanel = new JPanel();
|
|
||||||
|
|
||||||
topPanel.setLayout(new BorderLayout());
|
FontWrapper fontWrapper = new FontWrapper(font.getName());
|
||||||
fontPanel.setLayout(new GridLayout(2, 1));
|
int styleChoice = font.getStyle();
|
||||||
sizePanel.setLayout(new GridLayout(2, 1));
|
int size = font.getSize();
|
||||||
stylePanel.setLayout(new GridLayout(2, 1));
|
|
||||||
sizeAndStylePanel.setLayout(new BorderLayout());
|
|
||||||
|
|
||||||
topPanel.add(BorderLayout.WEST, fontPanel);
|
fontCombo.setSelectedItem(fontWrapper);
|
||||||
sizeAndStylePanel.add(BorderLayout.WEST, sizePanel);
|
sizeCombo.setSelectedItem(size);
|
||||||
sizeAndStylePanel.add(BorderLayout.CENTER, stylePanel);
|
styleCombo.setSelectedIndex(styleChoice);
|
||||||
topPanel.add(BorderLayout.CENTER, sizeAndStylePanel);
|
|
||||||
|
|
||||||
fontStringLabel = new GDLabel(FontPropertyEditor.SAMPLE_STRING);
|
fontCombo.addActionListener(actionListener);
|
||||||
fontStringLabel.setPreferredSize(new Dimension(350, 50));
|
sizeCombo.addActionListener(actionListener);
|
||||||
fontStringLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
styleCombo.addActionListener(actionListener);
|
||||||
fontStringLabel.setFont(font);
|
|
||||||
topPanel.add(BorderLayout.SOUTH, fontStringLabel);
|
|
||||||
|
|
||||||
add(BorderLayout.NORTH, topPanel);
|
}
|
||||||
|
|
||||||
fontLabel = new GDLabel("Fonts");
|
private void build() {
|
||||||
Font newFont = getFont().deriveFont(1);
|
setLayout(new BorderLayout());
|
||||||
fontLabel.setFont(newFont);
|
add(buildTopPanel(), BorderLayout.NORTH);
|
||||||
fontLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
add(buildPreviewLabel(), BorderLayout.CENTER);
|
||||||
fontPanel.add(fontLabel);
|
}
|
||||||
|
|
||||||
sizeLabel = new GDLabel("Sizes");
|
private Component buildTopPanel() {
|
||||||
sizeLabel.setFont(newFont);
|
JPanel panel = new JPanel(new FlowLayout(SwingConstants.CENTER, 10, 0));
|
||||||
sizeLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
panel.add(buildFontPanel());
|
||||||
sizePanel.add(sizeLabel);
|
panel.add(buildSizePanel());
|
||||||
|
panel.add(buildStylePanel());
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
styleLabel = new GDLabel("Styles");
|
private Component buildPreviewLabel() {
|
||||||
styleLabel.setFont(newFont);
|
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);
|
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();
|
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();
|
fontCombo = new GComboBox<>(array);
|
||||||
List<FontWrapper> list = new ArrayList<>(envfonts.length);
|
fontCombo.setMaximumRowCount(9);
|
||||||
for (String envfont : envfonts) {
|
fontCombo.addActionListener(actionListener);
|
||||||
list.add(new FontWrapper(envfont));
|
panel.add(fontCombo);
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
sizes = new GComboBox<>(IntStream.rangeClosed(1, 72).boxed().toArray(Integer[]::new));
|
return panel;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void fontChanged() {
|
||||||
public void actionPerformed(ActionEvent event) {
|
FontWrapper fontWrapper = (FontWrapper) fontCombo.getSelectedItem();
|
||||||
// get values of panels
|
String fontNameChoice = fontWrapper.getFontName();
|
||||||
// set the editors new font
|
int styleChoice = styleCombo.getSelectedIndex();
|
||||||
Object list = event.getSource();
|
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();
|
private void updatePreviewLabel(Font font) {
|
||||||
if (list == fonts) {
|
previewLabel.setFont(font);
|
||||||
FontWrapper fontWrapper = (FontWrapper) fonts.getSelectedItem();
|
FontMetrics fm = previewLabel.getFontMetrics(font);
|
||||||
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);
|
|
||||||
int height = fm.getHeight();
|
int height = fm.getHeight();
|
||||||
Dimension d = fontStringLabel.getSize();
|
Dimension d = previewLabel.getSize();
|
||||||
if (d.height < height) {
|
if (d.height < height) {
|
||||||
d = new Dimension(d.width, 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.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import ghidra.util.WebColors;
|
import ghidra.util.WebColors;
|
||||||
|
import resources.icons.UrlImageIcon;
|
||||||
|
|
||||||
public class FileGTheme extends GTheme {
|
public class FileGTheme extends GTheme {
|
||||||
public static final String FILE_PREFIX = "File:";
|
public static final String FILE_PREFIX = "File:";
|
||||||
|
@ -117,7 +120,15 @@ public class FileGTheme extends GTheme {
|
||||||
if (iconValue.getReferenceId() != null) {
|
if (iconValue.getReferenceId() != null) {
|
||||||
return iconValue.toExternalId(iconValue.getReferenceId());
|
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) {
|
private String getValueOutput(FontValue fontValue) {
|
||||||
|
@ -125,10 +136,14 @@ public class FileGTheme extends GTheme {
|
||||||
return fontValue.toExternalId(fontValue.getReferenceId());
|
return fontValue.toExternalId(fontValue.getReferenceId());
|
||||||
}
|
}
|
||||||
Font font = fontValue.getRawValue();
|
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());
|
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 bold = font.isBold();
|
||||||
boolean italic = font.isItalic();
|
boolean italic = font.isItalic();
|
||||||
if (bold && italic) {
|
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 javax.swing.Icon;
|
||||||
|
|
||||||
import resources.ResourceManager;
|
import docking.theme.Refreshable;
|
||||||
|
import ghidra.util.datastruct.WeakStore;
|
||||||
|
|
||||||
public class GIcon implements Icon, Refreshable {
|
public class GIcon implements Icon, Refreshable {
|
||||||
|
private static WeakStore<GIcon> inUseIcons = new WeakStore<>();
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private Icon delegate;
|
private Icon delegate;
|
||||||
|
|
||||||
public GIcon(String id) {
|
public static void refreshAll() {
|
||||||
this.id = id;
|
for (GIcon gIcon : inUseIcons.getValues()) {
|
||||||
delegate = Gui.getRawIcon(id);
|
gIcon.refresh();
|
||||||
if (delegate == null) {
|
|
||||||
delegate = ResourceManager.getDefaultIcon();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +66,7 @@ public class GIcon implements Icon, Refreshable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
Icon icon = Gui.getRawIcon(id);
|
Icon icon = Gui.getRawIcon(id, false);
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
delegate = icon;
|
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.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to store all the configurable appearance properties (Colors, Fonts, Icons, Look and Feel)
|
* Class to store all the configurable appearance properties (Colors, Fonts, Icons, Look and Feel)
|
||||||
* in an application.
|
* in an application.
|
||||||
|
@ -124,10 +126,10 @@ public class GTheme extends GThemeValueMap {
|
||||||
/**
|
/**
|
||||||
* Sets the icon for the given id
|
* Sets the icon for the given id
|
||||||
* @param id the id to associate with the given IconPath
|
* @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) {
|
public void setIcon(String id, Icon icon) {
|
||||||
addIconPath(new IconValue(id, null, iconPath));
|
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.
|
* @param refId the id of an indirect Icon lookup for the given id.
|
||||||
*/
|
*/
|
||||||
public void setIconRef(String id, String refId) {
|
public void setIconRef(String id, String refId) {
|
||||||
addIconPath(new IconValue(id, refId, null));
|
addIcon(new IconValue(id, refId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addIconPath(IconValue value) {
|
public void addIcon(IconValue value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
iconMap.put(value.getId(), value);
|
iconMap.put(value.getId(), value);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public class GThemeValueMap {
|
||||||
public void load(GThemeValueMap valueMap) {
|
public void load(GThemeValueMap valueMap) {
|
||||||
valueMap.colorMap.values().forEach(v -> addColor(v));
|
valueMap.colorMap.values().forEach(v -> addColor(v));
|
||||||
valueMap.fontMap.values().forEach(v -> addFont(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) {
|
public boolean containsFont(String id) {
|
||||||
return colorMap.containsKey(id);
|
return fontMap.containsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsIconPath(String id) {
|
public boolean containsIcon(String id) {
|
||||||
return colorMap.containsKey(id);
|
return iconMap.containsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object size() {
|
public Object size() {
|
||||||
|
@ -122,9 +122,14 @@ public class GThemeValueMap {
|
||||||
}
|
}
|
||||||
for (IconValue icon : iconMap.values()) {
|
for (IconValue icon : iconMap.values()) {
|
||||||
if (!icon.equals(base.getIcon(icon.getId()))) {
|
if (!icon.equals(base.getIcon(icon.getId()))) {
|
||||||
map.addIconPath(icon);
|
map.addIcon(icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map;
|
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
|
// TODO doc what this concept is
|
||||||
public class Gui {
|
public class Gui {
|
||||||
|
public static final String THEME_DIR = "themes";
|
||||||
public static final String BACKGROUND_KEY = "color.bg.text";
|
public static final String BACKGROUND_KEY = "color.bg.text";
|
||||||
|
|
||||||
private static final String THEME_PREFFERENCE_KEY = "Theme";
|
private static final String THEME_PREFFERENCE_KEY = "Theme";
|
||||||
|
@ -53,8 +53,7 @@ public class Gui {
|
||||||
private static ThemePropertiesLoader themePropertiesLoader = new ThemePropertiesLoader();
|
private static ThemePropertiesLoader themePropertiesLoader = new ThemePropertiesLoader();
|
||||||
|
|
||||||
private static Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
private static Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
||||||
|
private static Map<String, GIconUIResource> gIconMap = new HashMap<>();
|
||||||
private static JPanel jPanel;
|
|
||||||
|
|
||||||
static void setPropertiesLoader(ThemePropertiesLoader loader) {
|
static void setPropertiesLoader(ThemePropertiesLoader loader) {
|
||||||
themePropertiesLoader = loader;
|
themePropertiesLoader = loader;
|
||||||
|
@ -178,12 +177,15 @@ public class Gui {
|
||||||
return color.brighter();
|
return color.brighter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GFont getFont(String id) {
|
public static Font getFont(String id) {
|
||||||
return new GFont(id);
|
FontValue font = currentValues.getFont(id);
|
||||||
}
|
if (font == null) {
|
||||||
|
Throwable t = getFilteredTrace();
|
||||||
|
|
||||||
public static GIcon getIcon(String id) {
|
Msg.error(Gui.class, "No font value registered for: " + id, t);
|
||||||
return new GIcon(id);
|
return null;
|
||||||
|
}
|
||||||
|
return font.get(currentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveThemeToPreferences(GTheme theme) {
|
public static void saveThemeToPreferences(GTheme theme) {
|
||||||
|
@ -227,27 +229,16 @@ public class Gui {
|
||||||
return color.get(currentValues);
|
return color.get(currentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Font getRawFont(String id) {
|
public static Icon getRawIcon(String id, boolean validate) {
|
||||||
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) {
|
|
||||||
IconValue icon = currentValues.getIcon(id);
|
IconValue icon = currentValues.getIcon(id);
|
||||||
if (icon == null) {
|
if (icon == null) {
|
||||||
Throwable t = getFilteredTrace();
|
if (validate) {
|
||||||
|
Throwable t = getFilteredTrace();
|
||||||
Msg.error(Gui.class, "No color value registered for: " + id, t);
|
Msg.error(Gui.class, "No color value registered for: " + id, t);
|
||||||
return null;
|
}
|
||||||
|
return ResourceManager.getDefaultIcon();
|
||||||
}
|
}
|
||||||
String iconPath = icon.get(currentValues);
|
return icon.get(currentValues);
|
||||||
return ResourceManager.loadImage(iconPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Throwable getFilteredTrace() {
|
private static Throwable getFilteredTrace() {
|
||||||
|
@ -270,6 +261,7 @@ public class Gui {
|
||||||
map.load(activeTheme);
|
map.load(activeTheme);
|
||||||
currentValues = map;
|
currentValues = map;
|
||||||
GColor.refreshAll();
|
GColor.refreshAll();
|
||||||
|
GIcon.refreshAll();
|
||||||
repaintAll();
|
repaintAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,10 +288,14 @@ public class Gui {
|
||||||
|
|
||||||
private static Collection<GTheme> loadThemesFromFiles() {
|
private static Collection<GTheme> loadThemesFromFiles() {
|
||||||
List<File> fileList = new ArrayList<>();
|
List<File> fileList = new ArrayList<>();
|
||||||
|
FileFilter themeFileFilter = file -> file.getName().endsWith(GTheme.FILE_EXTENSION);
|
||||||
|
|
||||||
File dir = Application.getUserSettingsDirectory();
|
File dir = Application.getUserSettingsDirectory();
|
||||||
FileFilter themeFileFilter = file -> file.getName().endsWith(GTheme.FILE_EXTENSION);
|
File themeDir = new File(dir, THEME_DIR);
|
||||||
fileList.addAll(Arrays.asList(dir.listFiles(themeFileFilter)));
|
File[] files = themeDir.listFiles(themeFileFilter);
|
||||||
|
if (files != null) {
|
||||||
|
fileList.addAll(Arrays.asList(files));
|
||||||
|
}
|
||||||
|
|
||||||
List<GTheme> list = new ArrayList<>();
|
List<GTheme> list = new ArrayList<>();
|
||||||
for (File file : fileList) {
|
for (File file : fileList) {
|
||||||
|
@ -351,16 +347,55 @@ public class Gui {
|
||||||
return new DefaultTheme();
|
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) {
|
public static void setColor(String id, Color color) {
|
||||||
setColor(new ColorValue(id, color));
|
setColor(new ColorValue(id, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setColor(ColorValue colorValue) {
|
public static void setColor(ColorValue colorValue) {
|
||||||
currentValues.addColor(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();
|
GColor.refreshAll();
|
||||||
repaintAll();
|
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() {
|
private static void repaintAll() {
|
||||||
for (Window window : Window.getWindows()) {
|
for (Window window : Window.getWindows()) {
|
||||||
window.repaint();
|
window.repaint();
|
||||||
|
@ -368,6 +403,7 @@ public class Gui {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GColorUIResource getGColorUiResource(String id) {
|
public static GColorUIResource getGColorUiResource(String id) {
|
||||||
|
|
||||||
GColorUIResource gColor = gColorMap.get(id);
|
GColorUIResource gColor = gColorMap.get(id);
|
||||||
if (gColor == null) {
|
if (gColor == null) {
|
||||||
gColor = new GColorUIResource(id);
|
gColor = new GColorUIResource(id);
|
||||||
|
@ -376,6 +412,16 @@ public class Gui {
|
||||||
return gColor;
|
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) {
|
public static void setJavaDefaults(GThemeValueMap map) {
|
||||||
javaDefaults = map;
|
javaDefaults = map;
|
||||||
buildCurrentValues();
|
buildCurrentValues();
|
||||||
|
@ -417,4 +463,5 @@ public class Gui {
|
||||||
}
|
}
|
||||||
return currentDefaults;
|
return currentDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,24 @@
|
||||||
*/
|
*/
|
||||||
package docking.theme;
|
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.";
|
static final String ICON_ID_PREFIX = "icon.";
|
||||||
|
|
||||||
public static final String LAST_RESORT_DEFAULT = "images/bomb.gif";
|
public static final String LAST_RESORT_DEFAULT = "images/bomb.gif";
|
||||||
|
|
||||||
private static final String EXTERNAL_PREFIX = "[icon]";
|
private static final String EXTERNAL_PREFIX = "[icon]";
|
||||||
|
|
||||||
public IconValue(String id, String refId, String iconPath) {
|
public IconValue(String id, Icon icon) {
|
||||||
super(id, refId, iconPath);
|
super(id, null, icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconValue(String id, String refId) {
|
||||||
|
super(id, refId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -34,10 +41,10 @@ public class IconValue extends ThemeValue<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getUnresolvedReferenceValue(String id) {
|
protected Icon getUnresolvedReferenceValue(String id) {
|
||||||
Msg.warn(this,
|
Msg.warn(this,
|
||||||
"Could not resolve indirect icon path for" + id + ", using last resort default");
|
"Could not resolve indirect icon path for" + id + ", using last resort default");
|
||||||
return LAST_RESORT_DEFAULT;
|
return ResourceManager.getDefaultIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,7 +73,7 @@ public class IconValue extends ThemeValue<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int compareValues(String v1, String v2) {
|
protected int compareValues(Icon v1, Icon v2) {
|
||||||
return v1.compareTo(v2);
|
return v1.toString().compareTo(v2.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,15 @@ import java.awt.Font;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.plaf.FontUIResource;
|
||||||
|
|
||||||
import org.apache.commons.collections4.map.HashedMap;
|
import org.apache.commons.collections4.map.HashedMap;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.WebColors;
|
import ghidra.util.WebColors;
|
||||||
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class ThemePropertyFileReader {
|
public class ThemePropertyFileReader {
|
||||||
|
|
||||||
|
@ -112,7 +116,7 @@ public class ThemePropertyFileReader {
|
||||||
valueMap.addFont(parseFontProperty(key, value, lineNumber));
|
valueMap.addFont(parseFontProperty(key, value, lineNumber));
|
||||||
}
|
}
|
||||||
else if (IconValue.isIconKey(key)) {
|
else if (IconValue.isIconKey(key)) {
|
||||||
valueMap.addIconPath(parseIconProperty(key, value));
|
valueMap.addIcon(parseIconProperty(key, value));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
error(lineNumber, "Can't process property: " + key + " = " + value);
|
error(lineNumber, "Can't process property: " + key + " = " + value);
|
||||||
|
@ -122,9 +126,10 @@ public class ThemePropertyFileReader {
|
||||||
|
|
||||||
private IconValue parseIconProperty(String key, String value) {
|
private IconValue parseIconProperty(String key, String value) {
|
||||||
if (IconValue.isIconKey(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) {
|
private FontValue parseFontProperty(String key, String value, int lineNumber) {
|
||||||
|
@ -135,7 +140,7 @@ public class ThemePropertyFileReader {
|
||||||
if (font == null) {
|
if (font == null) {
|
||||||
error(lineNumber, "Could not parse Color: " + value);
|
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) {
|
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
|
// processValues expects only colors, fonts, and icons
|
||||||
themeSection.remove(GTheme.THEME_NAME_KEY);
|
themeSection.remove(GTheme.THEME_NAME_KEY);
|
||||||
themeSection.remove(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
themeSection.remove(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
||||||
|
themeSection.remove(GTheme.THEME_USE_DARK_DEFAULTS);
|
||||||
|
|
||||||
processValues(theme, themeSection);
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "Users";
|
return "Colors";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -181,7 +181,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||||
ResolvedColor resolved = (ResolvedColor) data.getValue();
|
ResolvedColor resolved = (ResolvedColor) data.getValue();
|
||||||
|
|
||||||
String text = getValueText(resolved);
|
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.setText(text);
|
||||||
label.setIcon(new SwatchIcon(color, label.getForeground()));
|
label.setIcon(new SwatchIcon(color, label.getForeground()));
|
||||||
label.setOpaque(true);
|
label.setOpaque(true);
|
||||||
|
@ -192,10 +192,10 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||||
if (resolvedColor == null) {
|
if (resolvedColor == null) {
|
||||||
return "<No Value>";
|
return "<No Value>";
|
||||||
}
|
}
|
||||||
if (resolvedColor.refId != null) {
|
if (resolvedColor.refId() != null) {
|
||||||
return resolvedColor.refId;
|
return resolvedColor.refId();
|
||||||
}
|
}
|
||||||
Color color = resolvedColor.color;
|
Color color = resolvedColor.color();
|
||||||
String text = WebColors.toString(color, false);
|
String text = WebColors.toString(color, false);
|
||||||
String name = WebColors.toWebColorName(color);
|
String name = WebColors.toWebColorName(color);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
|
@ -239,15 +239,5 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResolvedColor {
|
record ResolvedColor(String id, String refId, Color color) {/**/}
|
||||||
String id;
|
|
||||||
String refId;
|
|
||||||
Color color;
|
|
||||||
|
|
||||||
ResolvedColor(String id, String refId, Color color) {
|
|
||||||
this.id = id;
|
|
||||||
this.refId = refId;
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package docking.theme.gui;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -41,12 +42,16 @@ import docking.widgets.table.GTable;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||||
import resources.Icons;
|
|
||||||
|
|
||||||
public class ThemeDialog extends DialogComponentProvider {
|
public class ThemeDialog extends DialogComponentProvider {
|
||||||
private static ThemeDialog INSTANCE;
|
private static ThemeDialog INSTANCE;
|
||||||
private ThemeColorTableModel colorTableModel;
|
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
|
// stores the original value for ids whose value has changed
|
||||||
private GThemeValueMap changedValuesMap = new GThemeValueMap();
|
private GThemeValueMap changedValuesMap = new GThemeValueMap();
|
||||||
|
@ -70,22 +75,22 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
DockingAction importAction = new ActionBuilder("Import Theme", getTitle())
|
DockingAction importAction =
|
||||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
new ActionBuilder("Import Theme", getTitle()).toolBarIcon(new GIcon("icon.navigate.in"))
|
||||||
.onAction(e -> importTheme())
|
.onAction(e -> importTheme())
|
||||||
.build();
|
.build();
|
||||||
addAction(importAction);
|
addAction(importAction);
|
||||||
|
|
||||||
DockingAction exportAction = new ActionBuilder("Export Theme", getTitle())
|
DockingAction exportAction = new ActionBuilder("Export Theme", getTitle())
|
||||||
.toolBarIcon(Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON)
|
.toolBarIcon(new GIcon("icon.navigate.out"))
|
||||||
.onAction(e -> exportTheme())
|
.onAction(e -> exportTheme())
|
||||||
.build();
|
.build();
|
||||||
addAction(exportAction);
|
addAction(exportAction);
|
||||||
|
|
||||||
DockingAction reloadDefaultsAction =
|
DockingAction reloadDefaultsAction = new ActionBuilder("Reload Ghidra Defaults", getTitle())
|
||||||
new ActionBuilder("Reload Ghidra Defaults", getTitle()).toolBarIcon(Icons.REFRESH_ICON)
|
.toolBarIcon(new GIcon("icon.refresh"))
|
||||||
.onAction(e -> reloadDefaultsCallback())
|
.onAction(e -> reloadDefaultsCallback())
|
||||||
.build();
|
.build();
|
||||||
addAction(reloadDefaultsAction);
|
addAction(reloadDefaultsAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +149,8 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
private void reset() {
|
private void reset() {
|
||||||
changedValuesMap.clear();
|
changedValuesMap.clear();
|
||||||
colorTableModel.reloadAll();
|
colorTableModel.reloadAll();
|
||||||
|
fontTableModel.reloadAll();
|
||||||
|
iconTableModel.reloadAll();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
updateCombo();
|
updateCombo();
|
||||||
}
|
}
|
||||||
|
@ -211,8 +218,12 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
private File getSaveFile(String themeName) {
|
private File getSaveFile(String themeName) {
|
||||||
File dir = Application.getUserSettingsDirectory();
|
File dir = Application.getUserSettingsDirectory();
|
||||||
|
File themeDir = new File(dir, Gui.THEME_DIR);
|
||||||
|
if (!themeDir.exists()) {
|
||||||
|
themeDir.mkdir();
|
||||||
|
}
|
||||||
String cleanedName = themeName.replaceAll(" ", "_") + GTheme.FILE_EXTENSION;
|
String cleanedName = themeName.replaceAll(" ", "_") + GTheme.FILE_EXTENSION;
|
||||||
return new File(dir, cleanedName);
|
return new File(themeDir, cleanedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void importTheme() {
|
private void importTheme() {
|
||||||
|
@ -252,15 +263,18 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
private void themeComboChanged(ItemEvent e) {
|
private void themeComboChanged(ItemEvent e) {
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
String themeName = (String) e.getItem();
|
String themeName = (String) e.getItem();
|
||||||
if (hasChanges()) {
|
|
||||||
Msg.debug(this, "has changes");
|
|
||||||
}
|
|
||||||
Swing.runLater(() -> {
|
Swing.runLater(() -> {
|
||||||
GTheme theme = Gui.getTheme(themeName);
|
GTheme theme = Gui.getTheme(themeName);
|
||||||
Gui.setTheme(theme);
|
Gui.setTheme(theme);
|
||||||
if (theme.getLookAndFeelType() == LafType.GTK) {
|
if (theme.getLookAndFeelType() == LafType.GTK) {
|
||||||
setStatusText(
|
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);
|
MessageType.ERROR, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -268,6 +282,8 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
changedValuesMap.clear();
|
changedValuesMap.clear();
|
||||||
colorTableModel.reloadAll();
|
colorTableModel.reloadAll();
|
||||||
|
fontTableModel.reloadAll();
|
||||||
|
iconTableModel.reloadAll();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,14 +293,21 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void editColor(ColorValue value) {
|
protected void editColor(ColorValue value) {
|
||||||
if (dialog == null) {
|
colorEditor.editValue(value);
|
||||||
dialog = new ThemeColorEditorDialog(this);
|
|
||||||
}
|
|
||||||
dialog.editColor(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorChanged(ColorValue oldValue, ColorValue newValue) {
|
protected void editFont(FontValue value) {
|
||||||
updateChanagedValueMap(oldValue, newValue);
|
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
|
// run later - don't rock the boat in the middle of a listener callback
|
||||||
Swing.runLater(() -> {
|
Swing.runLater(() -> {
|
||||||
Gui.setColor(newValue);
|
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());
|
ColorValue originalValue = changedValuesMap.getColor(oldValue.getId());
|
||||||
if (originalValue == null) {
|
if (originalValue == null) {
|
||||||
changedValuesMap.addColor(oldValue);
|
changedValuesMap.addColor(oldValue);
|
||||||
|
@ -304,16 +349,36 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
updateButtons();
|
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() {
|
private void updateButtons() {
|
||||||
boolean hasChanges = hasChanges();
|
boolean hasChanges = hasChanges();
|
||||||
saveButton.setEnabled(hasChanges);
|
saveButton.setEnabled(hasChanges);
|
||||||
restoreButton.setEnabled(hasChanges);
|
restoreButton.setEnabled(hasChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorEditorClosed() {
|
|
||||||
dialog = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JComponent createMainPanel() {
|
private JComponent createMainPanel() {
|
||||||
JPanel panel = new JPanel();
|
JPanel panel = new JPanel();
|
||||||
|
|
||||||
|
@ -362,9 +427,89 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
private Component buildTabedTables() {
|
private Component buildTabedTables() {
|
||||||
JTabbedPane tabbedPane = new JTabbedPane();
|
JTabbedPane tabbedPane = new JTabbedPane();
|
||||||
tabbedPane.add("Colors", buildColorTable());
|
tabbedPane.add("Colors", buildColorTable());
|
||||||
|
tabbedPane.add("Fonts", buildFontTable());
|
||||||
|
tabbedPane.add("Icons", buildIconTable());
|
||||||
return tabbedPane;
|
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() {
|
private JComponent buildColorTable() {
|
||||||
colorTableModel = new ThemeColorTableModel();
|
colorTableModel = new ThemeColorTableModel();
|
||||||
|
|
||||||
|
@ -390,8 +535,6 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
if (e.getClickCount() == 2) {
|
if (e.getClickCount() == 2) {
|
||||||
ColorValue value = filterTable.getItemAt(e.getPoint());
|
ColorValue value = filterTable.getItemAt(e.getPoint());
|
||||||
Object cellValue = filterTable.getCellValue(e.getPoint());
|
|
||||||
// editColor(value);
|
|
||||||
|
|
||||||
int col = filterTable.getColumn(e.getPoint());
|
int col = filterTable.getColumn(e.getPoint());
|
||||||
TableColumn column = table.getColumnModel().getColumn(col);
|
TableColumn column = table.getColumnModel().getColumn(col);
|
||||||
|
@ -433,5 +576,4 @@ public class ThemeDialog extends DialogComponentProvider {
|
||||||
DockingWindowManager.showDialog(INSTANCE);
|
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
|
* Installs Colors, Fonts, and Icons into the UIDefaults. Subclasses my override this if they need to install
|
||||||
* GColors in a different way.
|
* UI properties in a different way.
|
||||||
*/
|
*/
|
||||||
protected void installJavaDefaults() {
|
protected void installJavaDefaults() {
|
||||||
GThemeValueMap javaDefaults = extractJavaDefaults();
|
GThemeValueMap javaDefaults = extractJavaDefaults();
|
||||||
Gui.setJavaDefaults(javaDefaults);
|
Gui.setJavaDefaults(javaDefaults);
|
||||||
installIndirectValues(javaDefaults);
|
installPropertiesBackIntoUiDefaults(javaDefaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installIndirectValues(GThemeValueMap javaDefaults) {
|
private void installPropertiesBackIntoUiDefaults(GThemeValueMap javaDefaults) {
|
||||||
UIDefaults defaults = UIManager.getDefaults();
|
UIDefaults defaults = UIManager.getDefaults();
|
||||||
for (ColorValue colorValue : javaDefaults.getColors()) {
|
for (ColorValue colorValue : javaDefaults.getColors()) {
|
||||||
String id = colorValue.getId();
|
String id = colorValue.getId();
|
||||||
|
@ -103,25 +103,43 @@ public class LookAndFeelInstaller {
|
||||||
}
|
}
|
||||||
for (FontValue fontValue : javaDefaults.getFonts()) {
|
for (FontValue fontValue : javaDefaults.getFonts()) {
|
||||||
String id = fontValue.getId();
|
String id = fontValue.getId();
|
||||||
GFont gFont = new GFont(id);
|
//Note: fonts don't support indirect values, so there is no GFont object
|
||||||
if (!gFont.equals(fontValue.getRawValue())) {
|
Font font = Gui.getFont(id);
|
||||||
// only update if we have changed the default java color
|
defaults.put(id, font);
|
||||||
defaults.put(id, gFont);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// for (IconValue iconValue : javaDefaults.getIcons()) {
|
||||||
|
// String id = iconValue.getId();
|
||||||
|
// GIconUIResource gIcon = Gui.getGIconUiResource(id);
|
||||||
|
// defaults.put(id, gIcon);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GThemeValueMap extractJavaDefaults() {
|
protected GThemeValueMap extractJavaDefaults() {
|
||||||
|
return extractJavaDefaults(UIManager.getDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static GThemeValueMap extractJavaDefaults(UIDefaults defaults) {
|
||||||
GThemeValueMap values = new GThemeValueMap();
|
GThemeValueMap values = new GThemeValueMap();
|
||||||
// for now, just doing color properties.
|
// for now, just doing color properties.
|
||||||
List<String> ids =
|
List<String> ids = LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Color.class);
|
||||||
LookAndFeelUtils.getLookAndFeelIdsForType(UIManager.getDefaults(), Color.class);
|
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
// only use standard java colors here to avoid weird issues (such as GColor not
|
// 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
|
// resolving or ColorUIResource not being honored. Later we will go back
|
||||||
// and fix up the java defaults to use standard java color indirection
|
// and fix up the java defaults to use standard java color indirection
|
||||||
values.addColor(new ColorValue(id, getNormalizedColor(UIManager.getColor(id))));
|
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;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,9 +289,13 @@ public class LookAndFeelInstaller {
|
||||||
String id = colorValue.getId();
|
String id = colorValue.getId();
|
||||||
defaults.put(id, null);
|
defaults.put(id, null);
|
||||||
}
|
}
|
||||||
// for (FontValue fontValue : javaDefaults.getFonts()) {
|
for (FontValue fontValue : javaDefaults.getFonts()) {
|
||||||
// String id = fontValue.getId();
|
String id = fontValue.getId();
|
||||||
// defaults.put(id, null);
|
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;
|
package docking.theme.laf;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.*;
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -24,6 +23,7 @@ import javax.swing.plaf.nimbus.NimbusLookAndFeel;
|
||||||
|
|
||||||
import docking.theme.*;
|
import docking.theme.*;
|
||||||
import ghidra.docking.util.LookAndFeelUtils;
|
import ghidra.docking.util.LookAndFeelUtils;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
public class NimbusLookAndFeelInstaller extends LookAndFeelInstaller {
|
public class NimbusLookAndFeelInstaller extends LookAndFeelInstaller {
|
||||||
|
|
||||||
|
@ -71,13 +71,37 @@ public class NimbusLookAndFeelInstaller extends LookAndFeelInstaller {
|
||||||
ColorValue value = new ColorValue(id, color);
|
ColorValue value = new ColorValue(id, color);
|
||||||
javaDefaults.addColor(value);
|
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);
|
Gui.setJavaDefaults(javaDefaults);
|
||||||
for (String id : colorIds) {
|
for (String id : colorIds) {
|
||||||
defaults.put(id, Gui.getGColorUiResource(id));
|
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"));
|
// javaDefaults.addColor(new ColorValue("Label.textForground", "Label.foreground"));
|
||||||
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
||||||
GColor.refreshAll();
|
GColor.refreshAll();
|
||||||
|
GIcon.refreshAll();
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class WrappingLookAndFeel extends LookAndFeel {
|
||||||
}
|
}
|
||||||
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
||||||
GColor.refreshAll();
|
GColor.refreshAll();
|
||||||
|
GIcon.refreshAll();
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import javax.swing.ImageIcon;
|
||||||
|
|
||||||
import generic.Images;
|
import generic.Images;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
import resources.icons.UnresolvedIcon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container class for an icon and its location. If the location is
|
* 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?
|
// is it absolute, or in resources by the given path?
|
||||||
baseIcon = ResourceManager.loadImage(iconLocation);
|
baseIcon = ResourceManager.loadImage(iconLocation);
|
||||||
|
|
||||||
if (baseIcon == ResourceManager.getDefaultIcon()) {
|
if (baseIcon instanceof UnresolvedIcon) {
|
||||||
// ...must not be, look for it in our 'special' locations
|
// ...must not be, look for it in our 'special' locations
|
||||||
baseIcon = loadFromKnownImageResources(iconLocation);
|
baseIcon = loadFromKnownImageResources(iconLocation);
|
||||||
}
|
}
|
||||||
|
@ -143,8 +144,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResourceManager.getScaledIcon(unscaledIcon, SMALL_ICON_SIZE,
|
return ResourceManager.getScaledIcon(unscaledIcon, SMALL_ICON_SIZE, SMALL_ICON_SIZE);
|
||||||
SMALL_ICON_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageIcon getLargeIcon(ImageIcon unscaledIcon) {
|
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
|
// O.K., we will scale the icon. However, if it is the default icon, we know we have
|
||||||
// a 'large' version of that.
|
// a 'large' version of that.
|
||||||
if (unscaledIcon == ResourceManager.getDefaultIcon()) {
|
if (unscaledIcon instanceof UnresolvedIcon) {
|
||||||
return ResourceManager.loadImage(Images.BIG_BOMB);
|
return ResourceManager.loadImage(Images.BIG_BOMB);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResourceManager.getScaledIcon(unscaledIcon, LARGE_ICON_SIZE,
|
return ResourceManager.getScaledIcon(unscaledIcon, LARGE_ICON_SIZE, LARGE_ICON_SIZE);
|
||||||
LARGE_ICON_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageIcon findCompatibleImageForSize(String imagePath, int desiredSize) {
|
private ImageIcon findCompatibleImageForSize(String imagePath, int desiredSize) {
|
||||||
|
@ -191,11 +190,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||||
name += location.substring(dotIndex);
|
name += location.substring(dotIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageIcon image = getImageIcon(name);
|
return getImageIcon(name);
|
||||||
if (image != null) {
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String stripSizeOffName(String name) {
|
private String stripSizeOffName(String name) {
|
||||||
|
@ -218,11 +213,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||||
|
|
||||||
private ImageIcon getImageIcon(String name) {
|
private ImageIcon getImageIcon(String name) {
|
||||||
ImageIcon image = ResourceManager.loadImage(name);
|
ImageIcon image = ResourceManager.loadImage(name);
|
||||||
ImageIcon defaultIcon = ResourceManager.getDefaultIcon();
|
if (image instanceof UnresolvedIcon) {
|
||||||
if (image == defaultIcon) {
|
|
||||||
if (!name.startsWith("images")) {
|
|
||||||
return getImageIcon("images/" + name);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
|
@ -289,16 +280,8 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
|
||||||
* @param name name of the icon
|
* @param name name of the icon
|
||||||
*/
|
*/
|
||||||
private ImageIcon loadFromKnownImageResources(String name) {
|
private ImageIcon loadFromKnownImageResources(String name) {
|
||||||
// first look in special location for tool icons
|
|
||||||
String filename = "defaultTools/images/" + name;
|
String filename = "defaultTools/images/" + name;
|
||||||
ImageIcon image = ResourceManager.loadImage(filename);
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAnimated(ImageIcon imgIcon) {
|
private void checkAnimated(ImageIcon imgIcon) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class DefaultDropDownSelectionDataModel<T> implements DropDownTextFieldDa
|
||||||
|
|
||||||
protected List<T> data;
|
protected List<T> data;
|
||||||
|
|
||||||
private Comparator<Object> comparator;
|
protected Comparator<Object> comparator;
|
||||||
private DataToStringConverter<T> searchConverter;
|
private DataToStringConverter<T> searchConverter;
|
||||||
private DataToStringConverter<T> descriptionConverter;
|
private DataToStringConverter<T> descriptionConverter;
|
||||||
private ListCellRenderer<T> renderer =
|
private ListCellRenderer<T> renderer =
|
||||||
|
|
|
@ -115,8 +115,8 @@ public class ColumnFilterArchiveDialog<R> extends DialogComponentProvider {
|
||||||
|
|
||||||
private JComponent buildFilterList() {
|
private JComponent buildFilterList() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
panel.setBorder(BorderFactory.createTitledBorder(
|
panel.setBorder(BorderFactory
|
||||||
BorderFactory.createEmptyBorder(19, 0, 0, 5), "Filter Names"));
|
.createTitledBorder(BorderFactory.createEmptyBorder(19, 0, 0, 5), "Filter Names"));
|
||||||
|
|
||||||
jList = new JList<>();
|
jList = new JList<>();
|
||||||
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
@ -136,22 +136,22 @@ public class ColumnFilterArchiveDialog<R> extends DialogComponentProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private JComponent buildActionPanel() {
|
private JComponent buildActionPanel() {
|
||||||
ImageIcon icon = Icons.DELETE_ICON;
|
Icon icon = Icons.DELETE_ICON;
|
||||||
|
|
||||||
removeSelectedFiltersButton = new JButton("Remove", icon);
|
removeSelectedFiltersButton = new JButton("Remove", icon);
|
||||||
removeSelectedFiltersButton.setEnabled(false);
|
removeSelectedFiltersButton.setEnabled(false);
|
||||||
removeSelectedFiltersButton.addActionListener(e -> removeSelectedFilter());
|
removeSelectedFiltersButton.addActionListener(e -> removeSelectedFilter());
|
||||||
|
|
||||||
JPanel buttonPanel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
buttonPanel.add(removeSelectedFiltersButton, BorderLayout.EAST);
|
panel.add(removeSelectedFiltersButton, BorderLayout.EAST);
|
||||||
|
|
||||||
return buttonPanel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component buildPreviewPanel() {
|
private Component buildPreviewPanel() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
panel.setBorder(BorderFactory.createTitledBorder(
|
panel.setBorder(BorderFactory
|
||||||
BorderFactory.createEmptyBorder(19, 0, 26, 5), "Preview"));
|
.createTitledBorder(BorderFactory.createEmptyBorder(19, 0, 26, 5), "Preview"));
|
||||||
|
|
||||||
previewLabel = new GDHtmlLabel();
|
previewLabel = new GDHtmlLabel();
|
||||||
previewLabel.setVerticalAlignment(SwingConstants.TOP);
|
previewLabel.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
|
|
@ -93,7 +93,7 @@ public class ConstraintFilterPanel extends JPanel {
|
||||||
|
|
||||||
private Component buildButtonPanel() {
|
private Component buildButtonPanel() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
ImageIcon icon = Icons.DELETE_ICON;
|
Icon icon = Icons.DELETE_ICON;
|
||||||
|
|
||||||
JButton button = new EmptyBorderButton(icon);
|
JButton button = new EmptyBorderButton(icon);
|
||||||
button.setToolTipText("Delete entry");
|
button.setToolTipText("Delete entry");
|
||||||
|
|
|
@ -488,7 +488,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
mainContentPanel.add(progressBarPanel, BorderLayout.CENTER);
|
mainContentPanel.add(progressBarPanel, BorderLayout.CENTER);
|
||||||
mainContentPanel.add(progressPanel, BorderLayout.EAST);
|
mainContentPanel.add(progressPanel, BorderLayout.EAST);
|
||||||
|
|
||||||
ImageIcon icon = Icons.STOP_ICON;
|
Icon icon = Icons.STOP_ICON;
|
||||||
cancelButton = new EmptyBorderButton(icon);
|
cancelButton = new EmptyBorderButton(icon);
|
||||||
|
|
||||||
cancelButton.setName("CANCEL_TASK");
|
cancelButton.setName("CANCEL_TASK");
|
||||||
|
|
|
@ -23,72 +23,74 @@ import java.net.URL;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
|
import docking.theme.GIcon;
|
||||||
import ghidra.util.Msg;
|
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.'
|
* icon that is 16x16 unless the method name ends in another size.'
|
||||||
*/
|
*/
|
||||||
public class Icons {
|
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 Icon COLLAPSE_ALL_ICON = new GIcon("icon.collapse.all");
|
||||||
public static final ImageIcon EXPAND_ALL_ICON = get("images/expand_all.png");
|
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 Icon CONFIGURE_FILTER_ICON = new GIcon("icon.configure.filter");
|
||||||
public static final ImageIcon DELETE_ICON = get("images/error.png");
|
public static final Icon DELETE_ICON = new GIcon("icon.delete");
|
||||||
public static final ImageIcon ERROR_ICON = get("images/emblem-important.png");
|
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 Icon NAVIGATE_ON_INCOMING_EVENT_ICON = new GIcon("icon.navigate.in");
|
||||||
public static final ImageIcon NAVIGATE_ON_OUTGOING_EVENT_ICON = get("images/locationOut.gif");
|
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 Icon NOT_ALLOWED_ICON = new GIcon("icon.notallowed");
|
||||||
public static final ImageIcon OPEN_FOLDER_ICON = get("images/openSmallFolder.png");
|
public static final Icon OPEN_FOLDER_ICON = new GIcon("icon.folder.open");
|
||||||
public static final ImageIcon REFRESH_ICON = get("images/reload3.png");
|
public static final Icon REFRESH_ICON = new GIcon("icon.refresh");
|
||||||
|
|
||||||
public static final ImageIcon SORT_ASCENDING_ICON = get("images/sortascending.png");
|
public static final Icon SORT_ASCENDING_ICON = new GIcon("icon.sort.ascending");
|
||||||
public static final ImageIcon SORT_DESCENDING_ICON = get("images/sortdescending.png");
|
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 Icon STOP_ICON = new GIcon("icon.stop");
|
||||||
public static final ImageIcon STRONG_WARNING_ICON = get("images/software-update-urgent.png");
|
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 Icon LEFT_ICON = new GIcon("icon.left");
|
||||||
public static final ImageIcon RIGHT_ICON = get("images/right.png");
|
public static final Icon RIGHT_ICON = new GIcon("icon.right");
|
||||||
|
|
||||||
/** An version of the LEFT_ICON with a different color */
|
/** 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 */
|
/** 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 =
|
public static final Icon SAVE_AS =
|
||||||
ResourceManager.getImageIcon(new DotDotDotIcon(get("images/Disk.png")));
|
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
|
// probably be moved to the client that uses them, while updating the
|
||||||
// help system to use them there.
|
// help system to use them there.
|
||||||
public static final ImageIcon ARROW_DOWN_RIGHT_ICON =
|
public static final Icon ARROW_DOWN_RIGHT_ICON =
|
||||||
ResourceManager.getImageIcon(new RotateIcon(get("images/viewmagfit.png"), 90));
|
ResourceManager.getImageIcon(new RotateIcon(new GIcon("icon.arrow.up.right"), 90));
|
||||||
public static final ImageIcon ARROW_UP_LEFT_ICON =
|
public static final Icon ARROW_UP_LEFT_ICON =
|
||||||
ResourceManager.getImageIcon(new RotateIcon(get("images/viewmagfit.png"), 275));
|
ResourceManager.getImageIcon(new RotateIcon(new GIcon("icon.arrow.up.right"), 275));
|
||||||
public static final ImageIcon FILTER_NOT_ACCEPTED_ICON =
|
public static final Icon FILTER_NOT_ACCEPTED_ICON =
|
||||||
ResourceManager.getImageIcon(new MultiIcon(get("images/flag.png"), new TranslateIcon(
|
ResourceManager.getImageIcon(new MultiIcon(new GIcon("icon.flag"),
|
||||||
ResourceManager.loadImage("images/dialog-cancel.png", 10, 10), 6, 6)));
|
new TranslateIcon(ResourceManager.loadImage("icon.notallowed", 10, 10), 6, 6)));
|
||||||
public static final ImageIcon APPLY_BLOCKED_MATCH_ICON =
|
public static final Icon APPLY_BLOCKED_MATCH_ICON =
|
||||||
ResourceManager.getImageIcon(new MultiIcon(get("images/kgpg.png"), new TranslateIcon(
|
ResourceManager.getImageIcon(new MultiIcon(new GIcon("icon.lock"),
|
||||||
ResourceManager.loadImage("images/checkmark_green.gif", 12, 12), 4, 0)));
|
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
|
* Returns true if the given string is a Java code snippet that references this class
|
||||||
*
|
*
|
||||||
* @param snippet the string to check
|
* @param snippet the string to check
|
||||||
* @return true if the given string is a Java code snippet that references this class
|
* @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'
|
* Returns an {@link IconProvider} for the given string value, which is usually the 'src'
|
||||||
* attribute of an IMG tag
|
* attribute of an IMG tag
|
||||||
*
|
*
|
||||||
* @param snippet the snippet
|
* @param snippet the snippet
|
||||||
* @return the icon provider
|
* @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.
|
* 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.
|
* If an icon by that name can't be found, the default "bomb" icon is returned instead.
|
||||||
* <P>
|
* <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
|
* "{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.
|
* "images/foo.png", since "{modulePath}/src/main/resources" is in the classpath.
|
||||||
*
|
*
|
||||||
* @param iconPath the icon path (relative to 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) {
|
public static ImageIcon get(String iconPath) {
|
||||||
return ResourceManager.loadImage(iconPath);
|
return ResourceManager.loadImage(iconPath);
|
||||||
|
@ -139,14 +141,14 @@ public class Icons {
|
||||||
* The given path should be relative to the classpath.
|
* 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.
|
* If an icon by that name can't be found, the default "bomb" icon is returned instead.
|
||||||
* <P>
|
* <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
|
* "{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.
|
* "images/foo.png", since "{modulePath}/src/main/resources" is in the classpath.
|
||||||
*
|
*
|
||||||
* @param iconPath the icon path (relative to the classpath)
|
* @param iconPath the icon path (relative to the classpath)
|
||||||
* @param width the desired width after scaling
|
* @param width the desired width after scaling
|
||||||
* @param height the desired height 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) {
|
public static ImageIcon get(String iconPath, int width, int height) {
|
||||||
return ResourceManager.loadImage(iconPath, width, height);
|
return ResourceManager.loadImage(iconPath, width, height);
|
||||||
|
@ -181,10 +183,6 @@ public class Icons {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (icon instanceof UrlImageIcon) {
|
|
||||||
return ((UrlImageIcon) icon).getUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: we embed the icon's URL in its description
|
// Note: we embed the icon's URL in its description
|
||||||
String description = icon.getDescription();
|
String description = icon.getDescription();
|
||||||
if (description == null) {
|
if (description == null) {
|
|
@ -22,10 +22,13 @@ import java.awt.Font;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class GThemeTest extends AbstractGenericTest {
|
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 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_1 = "images/arrow.png";
|
||||||
private static final String ICON_PATH_2 = "images/disk.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;
|
private GTheme theme;
|
||||||
|
|
||||||
|
@ -64,8 +69,8 @@ public class GThemeTest extends AbstractGenericTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetIconPath() {
|
public void testSetIconPath() {
|
||||||
theme.setIcon("icon.a.1", ICON_PATH_1);
|
theme.setIcon("icon.a.1", ICON1);
|
||||||
assertEquals(ICON_PATH_1, theme.getIcon("icon.a.1").get(null));
|
assertEquals(ICON1, theme.getIcon("icon.a.1").get(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -84,10 +89,10 @@ public class GThemeTest extends AbstractGenericTest {
|
||||||
theme.setFont("x.y.z", COURIER);
|
theme.setFont("x.y.z", COURIER);
|
||||||
theme.setFontRef("x.y.z.1", "x.y.z");
|
theme.setFontRef("x.y.z.1", "x.y.z");
|
||||||
|
|
||||||
theme.setIcon("icon.a.1", ICON_PATH_1);
|
theme.setIcon("icon.a.1", ICON1);
|
||||||
theme.setIcon("icon.a.2", ICON_PATH_2);
|
theme.setIcon("icon.a.2", ICON2);
|
||||||
theme.setIconRef("icon.a.3", "icon.a.1");
|
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");
|
theme.setIconRef("t.u.v.1", "t.u.v");
|
||||||
|
|
||||||
File file = createTempFile("themeTest.theme");
|
File file = createTempFile("themeTest.theme");
|
||||||
|
|
|
@ -473,6 +473,27 @@ public class ResourceManager {
|
||||||
return getScaledIcon(loadImage, width, height);
|
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
|
* Load the image specified by filename; returns the default bomb icon
|
||||||
* if problems occur trying to load the file.
|
* if problems occur trying to load the file.
|
||||||
|
@ -483,13 +504,27 @@ public class ResourceManager {
|
||||||
public static ImageIcon loadImage(String filename) {
|
public static ImageIcon loadImage(String filename) {
|
||||||
ImageIcon icon = iconMap.get(filename);
|
ImageIcon icon = iconMap.get(filename);
|
||||||
if (icon == null) {
|
if (icon == null) {
|
||||||
icon = doLoadIcon(filename, ResourceManager.getDefaultIcon());
|
icon = doLoadIcon(filename);
|
||||||
|
if (icon == null) {
|
||||||
|
icon = new UnresolvedIcon(filename, getDefaultIcon());
|
||||||
|
}
|
||||||
iconMap.put(filename, icon);
|
iconMap.put(filename, icon);
|
||||||
}
|
}
|
||||||
return 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
|
// 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
|
// a resource that lives under our "images/" folder
|
||||||
if (!filename.contains("/")) {
|
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.
|
* {@link LazyImageIcon} that is created from a URL to an icon file.
|
||||||
*/
|
*/
|
||||||
public class UrlImageIcon extends LazyImageIcon {
|
public class UrlImageIcon extends LazyImageIcon {
|
||||||
|
private String originalPath;
|
||||||
private URL imageUrl;
|
private URL imageUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,14 +39,27 @@ public class UrlImageIcon extends LazyImageIcon {
|
||||||
* @param url the {@link URL} to an icon resource file
|
* @param url the {@link URL} to an icon resource file
|
||||||
*/
|
*/
|
||||||
public UrlImageIcon(String path, URL url) {
|
public UrlImageIcon(String path, URL url) {
|
||||||
super(path);
|
super(url.toExternalForm());
|
||||||
|
this.originalPath = Objects.requireNonNull(path);
|
||||||
this.imageUrl = Objects.requireNonNull(url);
|
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() {
|
public URL getUrl() {
|
||||||
return imageUrl;
|
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
|
@Override
|
||||||
protected ImageIcon createImageIcon() {
|
protected ImageIcon createImageIcon() {
|
||||||
String name = getFilename();
|
String name = getFilename();
|
||||||
|
|
|
@ -254,7 +254,7 @@ public class GProgressBar extends JPanel {
|
||||||
activeProgressPanel.add(imageLabel, BorderLayout.EAST);
|
activeProgressPanel.add(imageLabel, BorderLayout.EAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageIcon icon = Icons.STOP_ICON;
|
Icon icon = Icons.STOP_ICON;
|
||||||
cancelButton = new EmptyBorderButton(icon);
|
cancelButton = new EmptyBorderButton(icon);
|
||||||
|
|
||||||
cancelButton.setName("CANCEL_TASK");
|
cancelButton.setName("CANCEL_TASK");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue