GP-1981 - Updated help to allow authors to use theme image ids; updated

help to only allow modules that live on the classpath. Dpdating themd
documentation. Fixing gradle help build
This commit is contained in:
ghidragon 2022-10-20 14:09:21 -04:00
parent c86b884daf
commit 45c52e3cb9
105 changed files with 1660 additions and 569 deletions

View File

@ -92,8 +92,8 @@ icon.debugger.thread = thread.png
icon.debugger.processor = memory16.gif // TODO this icon was missing 'kcmprocessor.png'
icon.debugger.launch = launch.png
icon.debugger.attach = attach.png
icon.debugger.resume = continue.png
icon.debugger.terminate = stop.png
icon.debugger.resume = resume.png
icon.debugger.interrupt = interrupt.png
icon.debugger.kill = kill.png
icon.debugger.detach = detach.png
icon.debugger.record = record.png
@ -101,10 +101,11 @@ icon.debugger.step.into = stepinto.png
icon.debugger.step.over = stepover.png
icon.debugger.step.back = stepback.png
icon.debugger.step.finish = stepout.png
icon.debugger.step.last = steplast.png
icon.debugger.skip.over = skipover.png
icon.debugger.snap.forward = 2rightarrow.png
icon.debugger.snap.backward = 2leftarrow.png
icon.debugger.seek.present = icon.debugger.resume
icon.debugger.seek.present = seek-present.png
icon.debugger.breakpoint.set = breakpoint-enable.png
icon.debugger.breakpoint.clear = breakpoint-clear.png

View File

@ -60,7 +60,6 @@ import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import resources.MultiIcon;
import resources.ResourceManager;
public interface DebuggerResources {
String OPTIONS_CATEGORY_DEBUGGER = "Debugger";
@ -77,23 +76,20 @@ public interface DebuggerResources {
Icon ICON_PROGRAM = ProgramContentHandler.PROGRAM_ICON;
Icon ICON_PROCESSOR = new GIcon("icon.debugger.processor");
Icon ICON_INTERRUPT = ResourceManager.loadImage("images/interrupt.png"); // TODO do gColor
Icon ICON_LAUNCH = new GIcon("icon.debugger.launch");
Icon ICON_ATTACH = new GIcon("icon.debugger.attach");
Icon ICON_RESUME = new GIcon("icon.debugger.resume");
Icon ICON_TERMINATE = new GIcon("icon.debugger.terminate"); // TODO was this deleted
Icon ICON_INTERRUPT = new GIcon("icon.debugger.interrupt");
Icon ICON_KILL = new GIcon("icon.debugger.kill");
Icon ICON_DETACH = new GIcon("icon.debugger.detach");
Icon ICON_RECORD = new GIcon("icon.debugger.record");
Icon ICON_STEP_LAST = ResourceManager.loadImage("images/steplast.png"); // TODO GColor
Icon ICON_STEP_INTO = new GIcon("icon.debugger.step.into");
Icon ICON_STEP_OVER = new GIcon("icon.debugger.step.over");
Icon ICON_SKIP_OVER = new GIcon("icon.debugger.step.back");
Icon ICON_STEP_FINISH = new GIcon("icon.debugger.step.finish");
Icon ICON_STEP_BACK = new GIcon("icon.debugger.skip.over");
Icon ICON_STEP_LAST = new GIcon("icon.debugger.step.last");
Icon ICON_SNAP_FORWARD = new GIcon("icon.debugger.snap.forward");
Icon ICON_SNAP_BACKWARD = new GIcon("icon.debugger.snap.backward");

View File

@ -640,7 +640,9 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
}
assertEquals(2, filtLocs.size());
breakpointsProvider.setSelectedBreakpoints(Set.of(data.get(0).getLogicalBreakpoint()));
LogicalBreakpointRow bpRow = data.get(0);
runSwing(() -> breakpointsProvider
.setSelectedBreakpoints(Set.of(bpRow.getLogicalBreakpoint())));
waitForSwing();
filtLocs = breakpointsProvider.locationFilterPanel.getTableFilterModel().getModelData();

View File

@ -66,6 +66,7 @@ dependencies {
testImplementation project(path: ':Project', configuration: 'testArtifacts')
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
testImplementation project(path: ':DB', configuration: 'testArtifacts')
helpPath project(path: ':Docking', configuration: 'helpPath') // this module's help has links to Base help files
javacc 'net.java.dev.javacc:javacc:5.0'
}

View File

@ -1032,7 +1032,6 @@ src/main/resources/images/empty8x16.png||GHIDRA||||END|
src/main/resources/images/emptyFragment.gif||GHIDRA||||END|
src/main/resources/images/emptyFragmentInView.gif||GHIDRA||||END|
src/main/resources/images/enum.png||GHIDRA||||END|
src/main/resources/images/erase16.png||GHIDRA||||END|
src/main/resources/images/famfamfam_silk_icons_v013/application_cascade.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/famfamfam_silk_icons_v013/application_get.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/famfamfam_silk_icons_v013/application_key.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
@ -1071,6 +1070,8 @@ src/main/resources/images/fingerPointer.png||GHIDRA||||END|
src/main/resources/images/font.png||FAMFAMFAM Icons - CC 2.5||||END|
src/main/resources/images/format-text-bold.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/functionDef.png||GHIDRA||||END|
src/main/resources/images/function_graph.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/function_graph_curvey.png||GHIDRA||||END|
src/main/resources/images/functions.gif||GHIDRA||||END|
src/main/resources/images/go-down.tango.16.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/go-home.png||Tango Icons - Public Domain|||Tango|END|
@ -1139,7 +1140,7 @@ src/main/resources/images/package.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set
src/main/resources/images/package_development.png||Nuvola Icons - LGPL 2.1|||nuvola|END|
src/main/resources/images/package_green.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/page_white.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/page_white_copy.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/page_white_c.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/pencil.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/pencil16.png||GHIDRA||||END|
src/main/resources/images/phone.png||Oxygen Icons - LGPL 3.0||||END|
@ -1167,11 +1168,11 @@ src/main/resources/images/stopNode.png||FAMFAMFAM Icons - CC 2.5|||famfamfam sil
src/main/resources/images/table.png||FAMFAMFAM Icons - CC 2.5|||silk|END|
src/main/resources/images/table_delete.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/table_go.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/table_relationship.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/table_row_delete.png||FAMFAMFAM Icons - CC 2.5|||silk|END|
src/main/resources/images/tag_yellow.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/text-x-csrc.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/text_list_bullets.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/text_lowercase.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/textfield.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/tools-report-bug.png||Oxygen Icons - LGPL 3.0||||END|
src/main/resources/images/twosComplement.png||GHIDRA||||END|

View File

@ -23,6 +23,8 @@ icon.base.application.64 = GhidraIcon64.png
icon.base.application.128 = GhidraIcon128.png
icon.base.application.256 = GhidraIcon256.png
icon.help.home = GHIDRA_1.png
icon.provider.clone = camera-photo.png
icon.plugin.datatypes.built.in = package_development.png

View File

@ -49,10 +49,7 @@
<tocroot>
<tocdef id="Root"
sortgroup="a"
text="Welcome to Ghidra Help"
target="help/topics/Misc/Welcome_to_Ghidra_Help.htm">
<tocref id="Root">
<tocdef id="Intro" sortgroup="1a" text="Introduction" target="help/topics/Intro/Intro.htm" />
@ -383,11 +380,11 @@
<tocdef id="Glossary" sortgroup="i" text="Glossary" target="help/topics/Glossary/glossary.htm" />
<tocdef id="What's New" sortgroup="j" text="What's New" target="docs/WhatsNew.html" />
<tocdef id="Tips of the Day" sortgroup="k" text="Tips of the Day" target="help/topics/Misc/Tips.htm" />
<tocdef id="Appendix" sortgroup="m" text="Appendix" target="help/topics/Misc/Appendix.htm">
<tocdef id="Appendix" sortgroup="z" text="Appendix" target="help/topics/Misc/Appendix.htm">
<tocdef id="Block Models" sortgroup="a" text="Block Models" target="help/topics/BlockModel/Block_Model.htm" />
<tocdef id="Languages" sortgroup="b" text="Languages" target="help/topics/LanguageProviderPlugin/Languages.htm" />
</tocdef>
</tocdef> <!-- End Welcome to Ghidra Help -->
</tocref> <!-- End Welcome to Ghidra Help -->
</tocroot>

View File

@ -58,8 +58,8 @@ import ghidra.util.task.TaskMonitor;
public class ListingMergePanel extends JPanel
implements MergeConstants, FocusListener, CodeFormatService {
private static final Icon HIDE_ICON = new GIcon("icons.base.listing.conflict.collapse");
private static final Icon SHOW_ICON = new GIcon("icons.base.listing.conflict.expand");
private static final Icon HIDE_ICON = new GIcon("icon.plugin.merge.conflict.collapse");
private static final Icon SHOW_ICON = new GIcon("icon.plugin.merge.conflict.expand");
private JComponent topComp;
private JComponent bottomComp;

View File

@ -317,7 +317,7 @@ public class PreviewTable extends AbstractInstructionTable {
private void createCopyBtn(JToolBar toolbar1) {
Icon copyIcon = Icons.COPY_ICON;
Action copyAction = new CopyAction("copy", (ImageIcon) copyIcon,
Action copyAction = new CopyAction("copy", copyIcon,
"Copy the full search string to clipboard");
EmptyBorderButton copyBtn = new EmptyBorderButton();
copyBtn.setAction(copyAction);
@ -328,7 +328,7 @@ public class PreviewTable extends AbstractInstructionTable {
private EmptyBorderToggleButton createHexViewBtn(JToolBar toolbar1) {
Icon hexIcon = new GIcon("icon.plugin.instructiontable.hex");
Action hexAction = new HexAction("hex", (ImageIcon) hexIcon, "hex view");
Action hexAction = new HexAction("hex", hexIcon, "hex view");
EmptyBorderToggleButton hexBtn = new EmptyBorderToggleButton();
hexBtn.setAction(hexAction);
hexBtn.setName("Hex View Button");
@ -340,7 +340,7 @@ public class PreviewTable extends AbstractInstructionTable {
private EmptyBorderToggleButton createBinaryViewBtn(JToolBar toolbar1) {
Icon binaryIcon = new GIcon("icon.plugin.instructiontable.binary");
Action binaryAction = new BinaryAction("binary", (ImageIcon) binaryIcon, "binary view");
Action binaryAction = new BinaryAction("binary", binaryIcon, "binary view");
EmptyBorderToggleButton binaryBtn = new EmptyBorderToggleButton();
binaryBtn.setAction(binaryAction);
binaryBtn.setName("binary view button");
@ -558,7 +558,7 @@ public class PreviewTable extends AbstractInstructionTable {
private class BinaryAction extends AbstractAction {
public BinaryAction(String text, ImageIcon icon, String desc) {
public BinaryAction(String text, Icon icon, String desc) {
super(text, icon);
putValue(SHORT_DESCRIPTION, desc);
}
@ -572,7 +572,7 @@ public class PreviewTable extends AbstractInstructionTable {
private class HexAction extends AbstractAction {
public HexAction(String text, ImageIcon icon, String desc) {
public HexAction(String text, Icon icon, String desc) {
super(text, icon);
putValue(SHORT_DESCRIPTION, desc);
}
@ -586,7 +586,7 @@ public class PreviewTable extends AbstractInstructionTable {
private class CopyAction extends AbstractAction {
public CopyAction(String text, ImageIcon icon, String desc) {
public CopyAction(String text, Icon icon, String desc) {
super(text, icon);
putValue(SHORT_DESCRIPTION, desc);

View File

@ -515,17 +515,9 @@ public class ProgramTreePlugin extends ProgramPlugin
/**
* Method renameView.
<<<<<<< Upstream, based on origin/master
*
* @param treeViewProvider
* @param newName
* @return boolean
=======
*
* @param treeViewProvider the provider
* @param newName the new name
* @return true if renamed
>>>>>>> 0eb4b9d GP-1981 - Theming - Base Module
*/
boolean renameView(TreeViewProvider treeViewProvider, String newName) {
Listing listing = currentProgram.getListing();

View File

@ -296,16 +296,10 @@ public class FieldHeaderComp extends JPanel {
}
/**
<<<<<<< Upstream, based on origin/master
* Returns the index of the field on the given row containing the give x pos.
* @param row the row on which to find the index of the field contianing the x coordinate.
* @param x the horizontal coordinate (in pixels)
=======
* Returns the index of the field on the given row containing the give x position.
* @param row the row on which to find the index of the field containing the x coordinate.
* @param x the horizontal coordinate (in pixels)
* @return the column
>>>>>>> 1c5bb47 GP-1981 - Theming - GColor migration fixes
*/
public int getCol(int row, int x) {
if (x < 0) {

View File

@ -22,7 +22,8 @@ import java.util.Map.Entry;
import javax.help.HelpSet;
import javax.help.HelpSetException;
import docking.help.*;
import docking.help.GHelpClassLoader;
import docking.help.HelpManager;
import generic.jar.ResourceFile;
import generic.theme.*;
import ghidra.framework.Application;
@ -36,6 +37,12 @@ import resources.ResourceManager;
*/
public class GhidraHelpService extends HelpManager {
/**
* The hardcoded value to use for all HelpSet 'home id' values. Subclasses may change this
* value by overriding {@link #getHomeId()}.
*/
private static final String GHIDRA_HOME_ID = "Misc_Ghidra_Help_Contents";
private static final String MASTER_HELP_SET_HS = "Base_HelpSet.hs";
private ThemeListener listener = new HelpThemeListener();
@ -68,6 +75,11 @@ public class GhidraHelpService extends HelpManager {
return ResourceManager.getResource("help/" + HelpService.DUMMY_HELP_SET_NAME);
}
@Override
protected String getHomeId() {
return GHIDRA_HOME_ID;
}
private void loadHelpSets() {
Map<ResourceFile, Set<URL>> helpSetsByModule = findHelpSetsByModule();

View File

@ -22,6 +22,7 @@ import java.awt.Color;
import org.junit.Test;
import docking.AbstractErrDialog;
import generic.theme.GThemeDefaults.Colors.Palette;
import ghidra.program.database.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.util.*;
@ -64,8 +65,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
super();
}
@Test
public void testAddVoidProperty() throws Exception {
@Test
public void testAddVoidProperty() throws Exception {
mtf.initialize("DiffTestPgm1", new ProgramModifierListener() {
@Override
@ -127,8 +128,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testAddSpaceProperty() throws Exception {
@Test
public void testAddSpaceProperty() throws Exception {
// ********************
// *** DiffTestPgm2 ***
// ********************
@ -217,8 +218,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testAddObjectProperty() throws Exception {
@Test
public void testAddObjectProperty() throws Exception {
// ********************
// *** DiffTestPgm1 ***
// ********************
@ -334,7 +335,7 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
}
@Test
public void testAddStringProperty() throws Exception {
public void testAddStringProperty() throws Exception {
mtf.initialize("DiffTestPgm1", new ProgramModifierListener() {
@Override
@ -656,7 +657,7 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
AbstractErrDialog errDlg = waitForErrorDialog();
String message = errDlg.getMessage();
assertEquals("Latest and Checked Out program versions do not have the same type for " +
assertEquals("Latest and Checked Out program versions do not have the same type for " +
"'testMap' property.", message);
pressButtonByText(errDlg, "OK");
@ -683,7 +684,7 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
}
@Test
public void testRemoveSpaceProperty() throws Exception {
public void testRemoveSpaceProperty() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -745,8 +746,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testRemoveColorProperty() throws Exception {
@Test
public void testRemoveColorProperty() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -800,13 +801,13 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
Address address = resultProgram.getMinAddress();
address = pm.getNextPropertyAddress(address);
assertEquals(addr("0x10039fe"), address);
assertEquals(new SaveableColor(Color.GREEN), pm.get(address));
assertEquals(new SaveableColor(Palette.GREEN), pm.get(address));
address = pm.getNextPropertyAddress(address);
assertNull(address);
}
@Test
public void testRemoveVsChangeSpaceProperty() throws Exception {
@Test
public void testRemoveVsChangeSpaceProperty() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -882,8 +883,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testRemoveVsChangeTestColorProperty() throws Exception {
@Test
public void testRemoveVsChangeTestColorProperty() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -953,8 +954,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testChangeSpaceProperty() throws Exception {
@Test
public void testChangeSpaceProperty() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1031,8 +1032,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testChangeTestColorProperty() throws Exception {
@Test
public void testChangeTestColorProperty() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1103,8 +1104,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testApplyToAllSpacePropertyConflicts() throws Exception {
@Test
public void testApplyToAllSpacePropertyConflicts() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1172,8 +1173,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testApplyToAllColorPropertyConflicts() throws Exception {
@Test
public void testApplyToAllColorPropertyConflicts() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1240,8 +1241,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testMultiplePropertyTypeConflicts() throws Exception {
@Test
public void testMultiplePropertyTypeConflicts() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1350,8 +1351,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testApplyToAllSpaceForMultipleTypeConflicts() throws Exception {
@Test
public void testApplyToAllSpaceForMultipleTypeConflicts() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1453,8 +1454,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testApplyToAllForEachConflict() throws Exception {
@Test
public void testApplyToAllForEachConflict() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1563,8 +1564,8 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
assertNull(address);
}
@Test
public void testApplyToAllForEachConflictPickOriginal() throws Exception {
@Test
public void testApplyToAllForEachConflictPickOriginal() throws Exception {
// ** DiffTestPgm2 **
// 10018ba = 1
// 10018ce = 2
@ -1665,16 +1666,16 @@ public class UserDefinedPropertyMergeManagerTest extends AbstractListingMergeMan
address = resultProgram.getMinAddress();
address = opm.getNextPropertyAddress(address);
assertEquals(addr("0x100248c"), address);
assertEquals(new SaveableColor(Color.WHITE), opm.get(address));
assertEquals(new SaveableColor(Palette.WHITE), opm.get(address));
address = opm.getNextPropertyAddress(address);
assertEquals(addr("0x10039f1"), address);
assertEquals(new SaveableColor(Color.BLACK), opm.get(address));
assertEquals(new SaveableColor(Palette.BLACK), opm.get(address));
address = opm.getNextPropertyAddress(address);
assertEquals(addr("0x10039f8"), address);
assertEquals(new SaveableColor(Color.BLACK), opm.get(address));
assertEquals(new SaveableColor(Palette.BLACK), opm.get(address));
address = opm.getNextPropertyAddress(address);
assertEquals(addr("0x10039fe"), address);
assertEquals(new SaveableColor(Color.GREEN), opm.get(address));
assertEquals(new SaveableColor(Palette.GREEN), opm.get(address));
address = opm.getNextPropertyAddress(address);
assertNull(address);
}

View File

@ -351,27 +351,27 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertEquals("01", btf.getText());
assertEquals(3, btf.getNumCols(0));
FieldElement fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001104"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("05 06 07 08", btf.getText());
assertEquals(12, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 3);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 6);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 9);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001108"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("09", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
}
@Test
@ -393,39 +393,39 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertEquals("0102 0304", btf.getText());
assertEquals(10, btf.getNumCols(0));
FieldElement fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 2);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 5);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 7);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001104"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("0506 0708", btf.getText());
assertEquals(10, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 2);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 5);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 7);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001108"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("090a 0b0c", btf.getText());
assertEquals(10, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 2);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 5);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 7);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
}
@Test
@ -445,7 +445,7 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertEquals("01 02 03 04", btf.getText());
assertEquals(12, btf.getNumCols(0));
FieldElement fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 3);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 6);
@ -458,26 +458,26 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertEquals("05 06 07 08", btf.getText());
assertEquals(12, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 3);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 6);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 9);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001108"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("09 0a 0b 0c", btf.getText());
assertEquals(12, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 3);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 6);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 9);
assertEquals(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.ALIGNMENT_BYTES_COLOR, fe.getColor(0));
}
@Test
@ -498,69 +498,69 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertEquals("01", btf.getText());
assertEquals(3, btf.getNumCols(0));
FieldElement fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001201"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("02", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001202"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("03", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001203"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("04", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001204"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("05 06 07 08", btf.getText());
assertEquals(12, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 3);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 6);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
fe = btf.getFieldElement(0, 9);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001208"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("09", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x1001209"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("0a", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x100120a"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("0b", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
cb.goToField(addr("0x100120b"), "Bytes", 0, 0);
btf = (ListingTextField) cb.getCurrentField();
assertEquals("0c", btf.getText());
assertEquals(3, btf.getNumCols(0));
fe = btf.getFieldElement(0, 1);
assertEquals(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
assertColorsEqual(BytesFieldFactory.DEFAULT_COLOR, fe.getColor(0));
}
@SuppressWarnings("unchecked")

View File

@ -441,7 +441,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest {
private void assertColorForAddress(Color color, Address address) {
Color appliedColor = colorizingService.getBackgroundColor(address);
assertEquals(color, appliedColor);
assertColorsEqual(color, appliedColor);
assertMarkerColorAtAddress(address, color);
}

View File

@ -42,13 +42,8 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.util.GroupPath;
import ghidra.program.util.ProgramLocation;
<<<<<<< Upstream, based on origin/master
import ghidra.util.Swing;
import ghidra.util.task.TaskMonitor;
import resources.ResourceManager;
=======
import ghidra.util.task.TaskMonitorAdapter;
>>>>>>> 0eb4b9d GP-1981 - Theming - Base Module
public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
@ -740,15 +735,9 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
runSwing(() -> tree.removeFromView(finalNode.getTreePath()));
int row = getRowForPath(node.getTreePath());
<<<<<<< Upstream, based on origin/master
Component comp = runSwing(() -> tree.getCellRenderer()
.getTreeCellRendererComponent(tree, node, true, false, true, row, false));
assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.CLOSED_FOLDER),
=======
Component comp = tree.getCellRenderer()
.getTreeCellRendererComponent(tree, node, true, false, true, row, false);
assertEquals(new GIcon(DnDTreeCellRenderer.CLOSED_FOLDER),
>>>>>>> 0eb4b9d GP-1981 - Theming - Base Module
((JLabel) comp).getIcon());
}
@ -844,15 +833,10 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
assertTrue(getView().hasSameAddresses(viewMgrService.getCurrentView()));
int row = getRowForPath(child.getTreePath());
<<<<<<< Upstream, based on origin/master
Component comp = runSwing(() -> tree.getCellRenderer()
.getTreeCellRendererComponent(tree, child, true, false, true, row, false));
assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_FRAGMENT),
=======
Component comp = tree.getCellRenderer()
.getTreeCellRendererComponent(tree, child, true, false, true, row, false);
assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT),
>>>>>>> 0eb4b9d GP-1981 - Theming - Base Module
((JLabel) comp).getIcon());
}

View File

@ -631,23 +631,14 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
JComponent comp = simpleOptionsPanel.getComponent();
assertTrue(comp.isShowing());
Component component = findPairedComponent(comp, "Favorite Color");
Component component = findPairedComponent(comp, "Favorite String");
assertNotNull(component);
Rectangle rect = component.getBounds();
clickMouse(component, 1, rect.x, rect.y, 2, 0);
waitForSwing();
Window window = waitForWindow("Color Editor");
assertNotNull(window);
JColorChooser chooser = findComponent(window, JColorChooser.class);
assertNotNull(chooser);
chooser.setColor(Palette.BLUE);
JButton okButton = findButtonByText(window, "OK");
assertNotNull(okButton);
pressButton(okButton);
triggerText(component, "Bar");
waitForSwing();
@ -658,8 +649,8 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
Options options = tool.getOptions(ToolConstants.TOOL_OPTIONS);
Color c = options.getColor("Favorite Color", Palette.RED);
assertColorsEqual(Palette.BLUE, c);
String currentValue = options.getString("Favorite String", null);
assertEquals("Bar", currentValue);
assertTrue(tool.hasConfigChanged());
}
@ -718,10 +709,6 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
// Inner Classes
//=================================================================================================
private void assertColorsEqual(Color c1, Color c2) {
assertEquals(c1.getRGB(), c2.getRGB());
}
private KeyStroke getKeyBinding(String actionName) throws Exception {
OptionsEditor editor = seleNodeWithCustomEditor("Key Bindings");
KeyBindingsPanel panel = (KeyBindingsPanel) getInstanceField("panel", editor);
@ -1117,8 +1104,11 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
options.setInt(name, 300);
name = "Favorite Color";
options.registerOption(name, Palette.RED, null, "description");
options.setColor(name, Palette.RED);
name = "Favorite String";
options.registerOption(name, "Foo", null, "description");
// select the middle button
name = "Mouse Buttons" + Options.DELIMITER + "Mouse Button To Activate";

View File

@ -17,6 +17,7 @@ package ghidra.framework.data;
import static org.junit.Assert.*;
import java.awt.Color;
import java.awt.Font;
import java.beans.PropertyChangeListener;
import java.beans.PropertyEditorSupport;
@ -28,8 +29,10 @@ import javax.swing.KeyStroke;
import org.junit.*;
import generic.test.AbstractGenericTest;
import docking.test.AbstractDockingTest;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.Gui;
import ghidra.framework.options.*;
import ghidra.framework.options.OptionsTest.FRUIT;
import ghidra.program.database.ProgramBuilder;
@ -37,11 +40,12 @@ import ghidra.program.database.ProgramDB;
import ghidra.util.HelpLocation;
import ghidra.util.exception.InvalidInputException;
public class OptionsDBTest extends AbstractGenericTest {
public class OptionsDBTest extends AbstractDockingTest {
private OptionsDB options;
private ProgramBuilder builder;
private int txID;
private GColor testColor;
public enum fruit {
Apple, Pear, Orange
@ -57,6 +61,8 @@ public class OptionsDBTest extends AbstractGenericTest {
ProgramDB program = builder.getProgram();
txID = program.startTransaction("Test");
options = new OptionsDB(program);
Gui.setColor("color.test", Palette.MAGENTA);
testColor = new GColor("color.test");
}
private void saveAndRestoreOptions() {
@ -280,16 +286,25 @@ public class OptionsDBTest extends AbstractGenericTest {
@Test
public void testGetDefaultValue() {
options.registerOption("Foo", Palette.RED, null, "description");
options.setColor("Foo", Palette.BLUE);
assertEquals(Palette.BLUE, options.getColor("Foo", null));
assertEquals(Palette.RED, options.getDefaultValue("Foo"));
options.registerOption("Foo", Color.RED, null, "description");
options.setColor("Foo", Color.BLUE);
assertColorsEqual(Color.BLUE, options.getColor("Foo", null));
assertColorsEqual(Color.RED, (Color) options.getDefaultValue("Foo"));
}
@Test
public void testGetDefaultValueWithThemeValues() {
options.registerOption("Foo", testColor, null, "description");
options.setColor("Foo", Color.BLUE);
assertColorsEqual(Color.BLUE, options.getColor("Foo", null));
// registered options using theme values, don't have defaults
assertColorsEqual(Color.BLUE, (Color) options.getDefaultValue("Foo"));
}
@Test
public void testRegisterPropertyEditor() {
MyPropertyEditor editor = new MyPropertyEditor();
options.registerOption("color", OptionType.COLOR_TYPE, Palette.RED, null, "description",
options.registerOption("color", OptionType.COLOR_TYPE, testColor, null, "description",
editor);
assertEquals(editor, options.getRegisteredPropertyEditor("color"));
@ -304,11 +319,20 @@ public class OptionsDBTest extends AbstractGenericTest {
@Test
public void testRestoreOptionValue() {
options.registerOption("Foo", Palette.RED, null, "description");
options.setColor("Foo", Palette.BLUE);
assertEquals(Palette.BLUE, options.getColor("Foo", null));
options.registerOption("Foo", 4, null, "description");
options.setInt("Foo", 7);
assertEquals(7, options.getInt("Foo", 0));
options.restoreDefaultValue("Foo");
assertEquals(Palette.RED, options.getColor("Foo", null));
assertEquals(4, options.getInt("Foo", 0));
}
@Test
public void testRestoreThemeOptionValue() {
options.registerOption("Foo", testColor, null, "description");
options.setColor("Foo", Palette.BLUE);
assertColorsEqual(Palette.BLUE, options.getColor("Foo", null));
options.restoreDefaultValue("Foo");
assertColorsEqual(Palette.MAGENTA, options.getColor("Foo", null));
}
@Test
@ -549,7 +573,19 @@ public class OptionsDBTest extends AbstractGenericTest {
@Test
public void testSettingValueToNull() {
options.registerOption("Bar", Palette.BLUE, null, "description");
// this will cause the palette color LAVENDER to be null - make sure to not use it in other
//tests
options.registerOption("Bar", "HEY", null, "description");
options.setString("Bar", "THERE");
options.setString("Bar", null);
assertEquals(null, options.getString("Bar", null));
}
@Test
public void testSettingThemeValueToNull() {
// this will cause the palette color LAVENDER to be null - make sure to not use it in other
//tests
options.registerOption("Bar", testColor, null, "description");
options.setColor("Bar", Palette.RED);
options.setColor("Bar", null);
assertEquals(null, options.getColor("Bar", null));

View File

@ -17,6 +17,7 @@ package ghidra.framework.options;
import static org.junit.Assert.*;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
@ -33,17 +34,17 @@ public class FileOptionsTest extends AbstractGenericTest {
options.registerOption("aaa", Integer.valueOf(5), null, "aaa description");
options.registerOption("bbb", Integer.valueOf(5), null, "bbb description");
options.registerOption("ccc", Palette.RED, null, "ccc description");
options.registerOption("ccc", Color.RED, null, "ccc description");
TestCustomOption custom = new TestCustomOption("bob", 23, true);
options.setInt("aaa", 10);
options.setColor("ccc", Palette.BLUE);
options.setColor("ccc", Color.BLUE);
options.setCustomOption("ddd", custom);
assertEquals(10, options.getInt("aaa", 0));
assertEquals(5, options.getInt("bbb", 0));
assertEquals(Palette.BLUE, options.getColor("ccc", null));
assertEquals(Color.BLUE, options.getColor("ccc", null));
assertEquals(custom, options.getCustomOption("ddd", null));
File file = createTempFile("optionsFile", "options");
@ -54,7 +55,7 @@ public class FileOptionsTest extends AbstractGenericTest {
assertEquals(10, restored.getInt("aaa", 0));
assertFalse(restored.contains("bbb")); // default value should not have been saved
assertEquals(Palette.BLUE.getRGB(), restored.getColor("ccc", null).getRGB());
assertEquals(Color.BLUE.getRGB(), restored.getColor("ccc", null).getRGB());
assertEquals(custom, restored.getCustomOption("ddd", null));
}

View File

@ -281,16 +281,16 @@ public class OptionsTest extends AbstractGenericTest {
@Test
public void testGetDefaultValue() {
options.registerOption("Foo", Palette.RED, null, null);
options.setColor("Foo", Palette.BLUE);
assertColorsEqual(Palette.BLUE, options.getColor("Foo", null));
assertColorsEqual(Palette.RED, (Color) options.getDefaultValue("Foo"));
options.registerOption("Foo", Color.RED, null, null);
options.setColor("Foo", Color.BLUE);
assertColorsEqual(Color.BLUE, options.getColor("Foo", null));
assertColorsEqual(Color.RED, (Color) options.getDefaultValue("Foo"));
}
@Test
public void testRegisterPropertyEditor() {
MyPropertyEditor editor = new MyPropertyEditor();
options.registerOption("color", OptionType.COLOR_TYPE, Palette.RED, null, null, editor);
options.registerOption("color", OptionType.COLOR_TYPE, Color.RED, null, null, editor);
assertEquals(editor, options.getRegisteredPropertyEditor("color"));
}
@ -304,12 +304,12 @@ public class OptionsTest extends AbstractGenericTest {
@Test
public void testRestoreOptionValue() {
options.registerOption("Foo", Palette.RED, null, null);
options.setColor("Foo", Palette.BLUE);
assertColorsEqual(Palette.BLUE, options.getColor("Foo", null));
options.registerOption("Foo", Color.RED, null, null);
options.setColor("Foo", Color.BLUE);
assertColorsEqual(Color.BLUE, options.getColor("Foo", null));
options.restoreDefaultValue("Foo");
assertColorsEqual(Palette.RED, options.getColor("Foo", null));
assertColorsEqual(Color.RED, options.getColor("Foo", null));
}
@Test
@ -593,10 +593,6 @@ public class OptionsTest extends AbstractGenericTest {
assertEquals(OptionType.NO_TYPE, options.getType("bar"));// there is no bar
}
private void assertColorsEqual(Color c1, Color c2) {
assertEquals(c1.getRGB(), c2.getRGB());
}
private void saveAndRestoreOptions() {
Element root = options.getXmlRoot(false);
options = new ToolOptions(root);

View File

@ -18,10 +18,7 @@ font.byteviewer.status = SansSerif-PLAIN-11
[Dark Defaults]
color.bg.byteviewer.highlight = rgb(191, 191, 64) // olive
color.fg.byteviewer.novalue = DarkBlue
color.fg.byteviewer.changed = indianRed
color.cursor.focused.byteviewer.current = color.cursor.focused
color.cursor.focused.byteviewer.noncurrent = gray
color.cursor.unfocused.byteviewer = color.cursor.unfocused
color.fg.byteviewer.separator = darkBlue
color.cursor.byteviewer.focused.not.active = gray

View File

@ -74,7 +74,6 @@ public class ByteViewerPanel extends JPanel
private ByteViewerComponent currentView;
private Color editColor;
private Color currentCursorColor;
private Color cursorColor;
private Color currentCursorLineColor;
private Color highlightColor;
private int highlightButton;
@ -218,7 +217,6 @@ public class ByteViewerPanel extends JPanel
}
void setCursorColor(Color c) {
cursorColor = c;
for (int i = 0; i < viewList.size(); i++) {
ByteViewerComponent comp = viewList.get(i);
comp.setNonFocusCursorColor(c);
@ -418,7 +416,7 @@ public class ByteViewerPanel extends JPanel
ByteViewerComponent c = newByteViewerComponent(model);
c.setEditColor(editColor);
c.setNonFocusCursorColor(cursorColor);
c.setNonFocusCursorColor(ByteViewerComponentProvider.CURSOR_NOT_FOCUSED_COLOR);
c.setCurrentCursorColor(currentCursorColor);
c.setCurrentCursorLineColor(currentCursorLineColor);
c.setEditMode(editMode);

View File

@ -157,8 +157,6 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt
});
assertTrue(action.isSelected());
final ByteViewerComponent c = panelOne.getCurrentComponent();
assertEquals(ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR,
c.getFocusedCursorColor());
runSwing(() -> {
KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_1, '1');
c.keyPressed(ev, loc.getIndex(), loc.getFieldNum(), loc.getRow(), loc.getCol(),
@ -168,7 +166,7 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt
ByteViewerComponent c2 = panel2.getCurrentComponent();
ByteField f2 = c2.getField(BigInteger.ZERO, 0);
assertEquals(ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR, f2.getForeground());
assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, f2.getForeground());
}
@Test
@ -189,8 +187,6 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt
});
assertTrue(action.isSelected());
final ByteViewerComponent c = panelOne.getCurrentComponent();
assertEquals(ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR,
c.getFocusedCursorColor());
runSwing(() -> {
KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_1, '1');
c.keyPressed(ev, loc.getIndex(), loc.getFieldNum(), loc.getRow(), loc.getCol(),
@ -200,7 +196,7 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt
ByteViewerComponent c2 = panel2.getCurrentComponent();
ByteField f2 = c2.getField(BigInteger.ZERO, 0);
assertEquals(ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR, f2.getForeground());
assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, f2.getForeground());
undo(program);

View File

@ -1219,7 +1219,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest {
putColor(opt, ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR_OPTION_NAME, Palette.GREEN);
ByteViewerComponent c = panel.getCurrentComponent();
assertEquals(Palette.GREEN, c.getFocusedCursorColor());
assertColorsEqual(Palette.GREEN, c.getFocusedCursorColor());
}
@Test
@ -1236,11 +1236,11 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest {
Options opt = tool.getOptions("ByteViewer");
// change the color for Current View Cursor Color
putColor(opt, ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR_OPTION_NAME,
putColor(opt, ByteViewerComponentProvider.CURSOR_NOT_FOCUSED_COLOR_OPTION_NAME,
Palette.GREEN);
ByteViewerComponent c = findComponent(panel, "Octal");
assertEquals(Palette.GREEN, c.getNonFocusCursorColor());
assertColorsEqual(Palette.GREEN, c.getNonFocusCursorColor());
}
@Test
@ -1260,7 +1260,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest {
Palette.CYAN);
ByteViewerComponent c = findComponent(panel, "Octal");
assertEquals(Palette.CYAN, c.getNonFocusCursorColor());
assertColorsEqual(Palette.CYAN, c.getNonFocusCursorColor());
}
private void putFont(final Options options, final String optionName, final Font font) {
@ -1305,7 +1305,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest {
program.flushEvents();
ByteViewerComponent c = panel.getCurrentComponent();
ByteField field = c.getField(loc.getIndex(), loc.getFieldNum());
assertEquals(Palette.GREEN, field.getForeground());
assertColorsEqual(Palette.GREEN, field.getForeground());
}
@Test
@ -1348,7 +1348,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest {
ByteViewerComponent c = panel.getCurrentComponent();
FieldLocation loc = getFieldLocation(getAddr(0x0f001000));
ByteField field = c.getField(loc.getIndex().subtract(BigInteger.ONE), 0);
assertEquals(Palette.GREEN, field.getForeground());
assertColorsEqual(Palette.GREEN, field.getForeground());
}
@Test

View File

@ -436,7 +436,7 @@ public class ByteViewerPluginFormatsTest extends AbstractGhidraHeadedIntegration
intComp.setCursorPosition(l.getIndex(), l.getFieldNum(), 0, 0);
});
// color should indicate the edit
assertEquals(ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR,
assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR,
((ByteField) intComp.getCurrentField()).getForeground());
}

View File

@ -12,6 +12,7 @@ color.fg.decompiler.constant = forestGreen
color.fg.decompiler.type = mediumBlue
color.fg.decompiler.parameter = darkMagenta
color.fg.decompiler.global = darkCyan
color.fg.decompiler.special = #cc0033
color.bg.decompiler.current.variable = rgba(255,255,0,0.5)
color.fg.line.numbers = gray

View File

@ -330,11 +330,11 @@ public class DecompileOptions {
private final static Color HIGHLIGHT_PARAMETER_COLOR = new GColor("color.fg.decompiler.parameter");
private final static String HIGHLIGHT_GLOBAL_MSG = "Display.Color for Globals";
private Color globalColor;
private final static String HIGHLIGHT_SPECIAL_MSG = "Display.Color for Special";
private final static Color HIGHLIGHT_SPECIAL_DEF = Color.decode("0xCC0033");
private Color specialColor;
private final static Color HIGHLIGHT_GLOBAL_COLOR = new GColor("color.fg.decompiler.global");
private final static String HIGHLIGHT_SPECIAL_MSG = "Display.Color for Special";
private final static Color HIGHLIGHT_SPECIAL_COLOR = new GColor("color.fg.decompiler.special");
private final static String HIGHLIGHT_DEFAULT_MSG = "Display.Color Default";
private final static Color HIGHLIGHT_DEFAULT_COLOR = new GColor("color.fg.decompiler");
@ -399,21 +399,6 @@ public class DecompileOptions {
commentHeadInclude = COMMENTHEAD_OPTIONDEFAULT;
namespaceStrategy = NAMESPACE_OPTIONDEFAULT;
integerFormat = INTEGERFORMAT_OPTIONDEFAULT;
<<<<<<< Upstream, based on origin/master
keywordColor = HIGHLIGHT_KEYWORD_DEF;
functionColor = HIGHLIGHT_FUNCTION_DEF;
commentColor = HIGHLIGHT_COMMENT_DEF;
variableColor = HIGHLIGHT_VARIABLE_DEF;
constantColor = HIGHLIGHT_CONST_DEF;
typeColor = HIGHLIGHT_TYPE_DEF;
parameterColor = HIGHLIGHT_PARAMETER_DEF;
globalColor = HIGHLIGHT_GLOBAL_DEF;
specialColor = HIGHLIGHT_SPECIAL_DEF;
defaultColor = HIGHLIGHT_DEFAULT_DEF;
codeViewerBackgroundColor = CODE_VIEWER_BACKGROUND_COLOR;
defaultFont = DEFAULT_FONT;
=======
>>>>>>> 47fa38a GP-1981 converting option colors to theme colors and font usages to theme properties
displayLineNumbers = LINE_NUMBER_DEF;
displayLanguage = ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF;
protoEvalModel = "default";
@ -466,26 +451,7 @@ public class DecompileOptions {
commentHeadInclude = opt.getBoolean(COMMENTHEAD_OPTIONSTRING, COMMENTHEAD_OPTIONDEFAULT);
namespaceStrategy = opt.getEnum(NAMESPACE_OPTIONSTRING, NAMESPACE_OPTIONDEFAULT);
integerFormat = opt.getEnum(INTEGERFORMAT_OPTIONSTRING, INTEGERFORMAT_OPTIONDEFAULT);
<<<<<<< Upstream, based on origin/master
keywordColor = opt.getColor(HIGHLIGHT_KEYWORD_MSG, HIGHLIGHT_KEYWORD_DEF);
typeColor = opt.getColor(HIGHLIGHT_TYPE_MSG, HIGHLIGHT_TYPE_DEF);
functionColor = opt.getColor(HIGHLIGHT_FUNCTION_MSG, HIGHLIGHT_FUNCTION_DEF);
commentColor = opt.getColor(HIGHLIGHT_COMMENT_MSG, HIGHLIGHT_COMMENT_DEF);
variableColor = opt.getColor(HIGHLIGHT_VARIABLE_MSG, HIGHLIGHT_VARIABLE_DEF);
constantColor = opt.getColor(HIGHLIGHT_CONST_MSG, HIGHLIGHT_CONST_DEF);
parameterColor = opt.getColor(HIGHLIGHT_PARAMETER_MSG, HIGHLIGHT_PARAMETER_DEF);
globalColor = opt.getColor(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF);
specialColor = opt.getColor(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_DEF);
defaultColor = opt.getColor(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF);
codeViewerBackgroundColor =
opt.getColor(CODE_VIEWER_BACKGROUND_COLOR_MSG, CODE_VIEWER_BACKGROUND_COLOR);
currentVariableHighlightColor =
opt.getColor(HIGHLIGHT_CURRENT_VARIABLE_MSG, HIGHLIGHT_CURRENT_VARIABLE_DEF);
defaultFont = opt.getFont(FONT_MSG, DEFAULT_FONT);
defaultFont = SystemUtilities.adjustForFontSizeOverride(defaultFont);
defaultSearchHighlightColor = opt.getColor(SEARCH_HIGHLIGHT_MSG, SEARCH_HIGHLIGHT_DEF);
=======
>>>>>>> 47fa38a GP-1981 converting option colors to theme colors and font usages to theme properties
displayLineNumbers = opt.getBoolean(LINE_NUMBER_MSG, LINE_NUMBER_DEF);
decompileTimeoutSeconds = opt.getInt(DECOMPILE_TIMEOUT, SUGGESTED_DECOMPILE_TIMEOUT_SECS);
payloadLimitMBytes = opt.getInt(PAYLOAD_LIMIT, SUGGESTED_MAX_PAYLOAD_BYTES);
@ -643,14 +609,10 @@ public class DecompileOptions {
opt.registerOption(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_COLOR,
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
"Color used for highlighting global variables.");
<<<<<<< Upstream, based on origin/master
opt.registerOption(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_DEF,
opt.registerOption(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_COLOR,
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
"Color used for volatile or other exceptional variables.");
opt.registerOption(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF,
=======
opt.registerOption(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_COLOR,
>>>>>>> 47fa38a GP-1981 converting option colors to theme colors and font usages to theme properties
new HelpLocation(HelpTopics.DECOMPILER, "DisplayColorDefault"),
"The color used when a specific color is not specified.");
opt.registerOption(BACKGROUND_COLOR_MSG, BACKGROUND_COLOR,
@ -874,7 +836,7 @@ public class DecompileOptions {
* @return color associated with volatile variables or other special tokens
*/
public Color getSpecialColor() {
return specialColor;
return HIGHLIGHT_SPECIAL_COLOR;
}
/**

View File

@ -971,7 +971,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
removeSecondaryHighlight();
Color hlColor2 = highlight();
assertEquals(myColor, hlColor2);
assertEquals(myColor.getRGB(), hlColor2.getRGB());
}
@Test
@ -1981,7 +1981,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
Color hlColor = getSecondaryHighlight(token);
assertNotNull("No highlight for token: " + token, hlColor);
assertEquals(color, hlColor);
assertEquals(color.getRGB(), hlColor.getRGB());
}
private void removeSecondaryHighlight() {
@ -2279,7 +2279,17 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
public boolean matches(Color otherColor) {
for (Color c : myColors) {
if (Objects.equals(c, otherColor)) {
if (c == null) {
if (otherColor == null) {
return true;
}
continue;
}
if (otherColor == null) {
continue;
}
if (c.getRGB() == otherColor.getRGB()) {
return true;
}
}

View File

@ -2082,8 +2082,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
protected void verifyColor(FGVertex vertex, Color expectedColor) {
Color currentBackgroundColor = vertex.getBackgroundColor();
assertEquals("Color of vertex is not as expected - vertex: " + vertex, expectedColor,
currentBackgroundColor);
assertColorsEqual(expectedColor, currentBackgroundColor);
}
protected void verifyDefaultColor(FGVertex... vertices) {

View File

@ -627,7 +627,7 @@ public class FunctionGraphPlugin1Test extends AbstractFunctionGraphTest {
chooseColor(focusedVertex, testColor);
Color newVertexBackgroundColor = focusedVertex.getUserDefinedColor();
assertEquals("Background color not set", testColor, newVertexBackgroundColor);
assertColorsEqual(testColor, newVertexBackgroundColor);
DockingAction clearColorAction = getClearColorAction(focusedVertex);
performAction(clearColorAction, graphProvider, true);

View File

@ -285,7 +285,7 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest {
// make sure the service is also cognizant of the color change
appliedBackgroundColor = colorizingService.getBackgroundColor(vertex.getVertexAddress());
assertEquals(testColor, appliedBackgroundColor);
assertColorsEqual(testColor, appliedBackgroundColor);
Color vBg = vertex.getBackgroundColor();
assertEquals(appliedBackgroundColor, vBg);
@ -333,8 +333,8 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest {
Color newBackgroundColor =
colorizingService.getBackgroundColor(focusedVertex.getVertexAddress());
assertEquals("'Set Most Recent Color' action did not apply that color to the color service",
mostRecentColor, newBackgroundColor);
// "'Set Most Recent Color' action did not apply that color to the color service"
assertColorsEqual(mostRecentColor, newBackgroundColor);
}
// TODO: see SCR 9208 - we don't currently support this, although we could

View File

@ -12,7 +12,11 @@ data/ExtensionPoint.manifest||GHIDRA||||END|
data/docking.palette.theme.properties||GHIDRA||||END|
data/docking.theme.properties||GHIDRA||||END|
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
src/main/help/help/topics/Theming/Theming.htm||GHIDRA||||END|
src/main/help/help/topics/Misc/Welcome_to_Help.htm||GHIDRA||||END|
src/main/help/help/topics/Theming/ThemingDeveloperDocs.html||GHIDRA||||END|
src/main/help/help/topics/Theming/ThemingInternals.html||GHIDRA||||END|
src/main/help/help/topics/Theming/ThemingOverview.html||GHIDRA||||END|
src/main/help/help/topics/Theming/ThemingUserDocs.html||GHIDRA||||END|
src/main/help/help/topics/Theming/images/ColorEditor.png||GHIDRA||||END|
src/main/help/help/topics/Theming/images/FontEditor.png||GHIDRA||||END|
src/main/help/help/topics/Theming/images/IconEditor.png||GHIDRA||||END|
@ -22,8 +26,6 @@ src/main/java/docking/options/editor/package.html||GHIDRA||reviewed||END|
src/main/java/docking/widgets/fieldpanel/package.html||GHIDRA||reviewed||END|
src/main/java/docking/widgets/filechooser/package.html||GHIDRA||reviewed||END|
src/main/java/docking/wizard/package.html||GHIDRA||reviewed||END|
src/main/resources/images/EmptyIcon.gif||GHIDRA||reviewed||END|
src/main/resources/images/EmptyIcon16.gif||GHIDRA||reviewed||END|
src/main/resources/images/Plus.png||GHIDRA||reviewed||END|
src/main/resources/images/StackFrameElement.png||GHIDRA||reviewed||END|
src/main/resources/images/StackFrame_Red.png||GHIDRA||reviewed||END|
@ -32,18 +34,15 @@ src/main/resources/images/application-vnd.oasis.opendocument.spreadsheet-templat
src/main/resources/images/application_xp.png||FAMFAMFAM Icons - CC 2.5|||fam fam|END|
src/main/resources/images/arrow.gif||GHIDRA||||END|
src/main/resources/images/bullet_delete.png||FAMFAMFAM Icons - CC 2.5||||END|
src/main/resources/images/check.png||GHIDRA||||END|
src/main/resources/images/checkmark_green.gif||GHIDRA||reviewed||END|
src/main/resources/images/close16.gif||GHIDRA||reviewed||END|
src/main/resources/images/closedFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
src/main/resources/images/collapse.gif||GHIDRA||||END|
src/main/resources/images/collapse_all.png||GHIDRA||||END|
src/main/resources/images/computer.png||Tango Icons - Public Domain|||tango|END|
src/main/resources/images/desktop.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/dialog-cancel.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/dialog-warning.png||Oxygen Icons - LGPL 3.0||||END|
src/main/resources/images/disk.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/document-properties.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/down.png||GHIDRA||reviewed||END|
src/main/resources/images/drive.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/eatbits.gif||GHIDRA||reviewed||END|
src/main/resources/images/eatbits1.png||GHIDRA||reviewed||END|
@ -54,8 +53,6 @@ src/main/resources/images/eatbits5.png||GHIDRA||reviewed||END|
src/main/resources/images/eatbits6.png||GHIDRA||reviewed||END|
src/main/resources/images/eatbits7.png||GHIDRA||reviewed||END|
src/main/resources/images/edit-clear.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/edit-cut.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/edit-cut22.png||Tango Icons - Public Domain|||original name edit-cut.png in tango 22x22|END|
src/main/resources/images/edit-delete.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/edit-undo.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/expand.gif||GHIDRA||||END|
@ -63,7 +60,6 @@ src/main/resources/images/filter_off.png||GHIDRA||||END|
src/main/resources/images/filter_on.png||GHIDRA||||END|
src/main/resources/images/folder-open.png||Tango Icons - Public Domain||||END|
src/main/resources/images/folder_add.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/go-home.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/hourglass.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/hourglass24_01.png||GHIDRA||reviewed||END|
src/main/resources/images/hourglass24_02.png||GHIDRA||reviewed||END|
@ -79,13 +75,8 @@ src/main/resources/images/hourglass24_11.png||GHIDRA||reviewed||END|
src/main/resources/images/image-missing.png||Oxygen Icons - LGPL 3.0||||END|
src/main/resources/images/info_small.png||GHIDRA||||END|
src/main/resources/images/info_small_hover.png||GHIDRA||||END|
src/main/resources/images/information.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/inode-directory.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/left.alternate.png||GHIDRA||||END|
src/main/resources/images/left.png||GHIDRA||reviewed||END|
src/main/resources/images/list-remove.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/locationIn.gif||GHIDRA||||END|
src/main/resources/images/locationOut.gif||GHIDRA||||END|
src/main/resources/images/magnifier.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/mail-folder-outbox.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/mail-receive.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
@ -102,24 +93,17 @@ src/main/resources/images/page_green.png||FAMFAMFAM Icons - CC 2.5||||END|
src/main/resources/images/play.png||GHIDRA||||END|
src/main/resources/images/preferences-system-windows.png||Tango Icons - Public Domain||||END|
src/main/resources/images/redo.png||GHIDRA||||END|
src/main/resources/images/reload.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/right.alternate.png||GHIDRA||||END|
src/main/resources/images/right.png||GHIDRA||reviewed||END|
src/main/resources/images/software-update-available.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/sortascending.png||GHIDRA||reviewed||END|
src/main/resources/images/sortdescending.png||GHIDRA||reviewed||END|
src/main/resources/images/table.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/tag.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/text_lowercase.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/textfield_rename.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/tip.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/trash-empty.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/undo.png||GHIDRA||||END|
src/main/resources/images/up.png||GHIDRA||reviewed||END|
src/main/resources/images/user-home.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/view-filter.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/viewmagfit.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/warning.help.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/warning.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/weather-clear.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/weather-few-clouds-reverse.png||Tango Icons - Public Domain||||END|
src/main/resources/images/weather-few-clouds.png||Tango Icons - Public Domain|||tango icon set|END|

View File

@ -91,56 +91,14 @@ color.bg.fieldpanel.selection.and.highlight = green
// docking buttons
color.fg.button = black
// Icons files
icon.empty = EmptyIcon16.gif
icon.empty.20 = EmptyIcon.gif
icon.help = help-browser.png
icon.home = go-home.png
icon.add = Plus2.png
icon.folder.new = folder_add.png
icon.subtract = list-remove.png
icon.clear = erase16.png
icon.error = emblem-important.png
icon.delete = icon.error
icon.collapse.all = collapse_all.png
icon.expand.all = expand_all.png
icon.toggle.expand = expand.gif
icon.toggle.collapse = collapse.gif
icon.configure.filter = exec.png
icon.navigate.in = locationIn.gif
icon.navigate.out = locationOut.gif
icon.not.allowed = dialog-cancel.png
icon.folder.closed = closedSmallFolder.png
icon.folder.open = openSmallFolder.png
icon.folder.new = folder_add.png
icon.refresh = reload3.png
icon.sort.ascending = sortascending.png
icon.sort.descending = sortdescending.png
icon.stop = process-stop.png
icon.information = information.png
icon.warning = warning.png
icon.warning.strong = software-update-urgent.png
icon.left = left.png
icon.right = right.png
icon.left.alt = left.alternate.png
icon.right.alt = right.alternate.png
icon.save = disk.png
icon.save.as = disk_save_as.png
icon.make.selection = text_align_justify.png
icon.arrow.down.right = viewmagfit.png[rotate(90)]
icon.arrow.up.left = viewmagfit.png[rotate(275)]
icon.flag = flag.png
icon.lock = kgpg.png
icon.checkmark.green = checkmark_green.gif
icon.filter.not.accepted = icon.flag{dialog-cancel.png[size(10,10)][move(6,6)]}
icon.blocked.match = icon.lock{icon.checkmark.green[size(12,12)][move(4,0)]}
icon.undo = undo.png
icon.redo = redo.png
icon.font = text_lowercase.png
icon.up = up.png
icon.down = down.png
icon.copy = page_white_copy.png
icon.cut = edit-cut.png
icon.paste = page_paste.png
icon.rename = textfield_rename.png
icon.check = check.png
icon.search = magnifier.png

View File

@ -49,8 +49,19 @@
<tocroot>
<tocdef id="Theming"
text="Theming"
target="help/topics/Theming/Theming.htm" >
<!--
Note: we have omitted the target url for the root node. Rather than defining a help page
for this node, we allow the system's default 'home id' to be used. (Any time a help item
has no help defined, the 'home id' is displayed.) When the system's HelpManager loads
GHelpSets, it will specify the 'home id' specific to that application.
-->
<tocdef id="Root" sortgroup="a" text="Welcome to Help">
<tocdef id="Theming" text="Theming" sortgroup="t" target="help/topics/Theming/ThemingOverview.html">
<tocdef id="Overview" sortgroup="1" text="Overview" target="help/topics/Theming/ThemingOverview.html"/>
<tocdef id="Editing Themes" sortgroup="2" text="Editing Themes" target="help/topics/Theming/ThemingUserDocs.html"/>
<tocdef id="Developer Documentation" sortgroup="3" text="Developer Documentation" target="help/topics/Theming/ThemingDeveloperDocs.html"/>
<tocdef id="Architecture Documentation" sortgroup="4" text="Architecture Documentation" target="help/topics/Theming/ThemingInternals.html"/>
</tocdef>
</tocdef>
</tocroot>

View File

@ -0,0 +1,26 @@
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<html>
<head>
<title>Welcome to Help</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<link rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<meta name="generator" content="Microsoft FrontPage 4.0">
</head>
<body>
<h1 align="center"><a name="Help_Contents"></a>Welcome to Help...</h1>
<div align="left">
<p>We provide context sensitive help on menu items, dialogs, buttons,
and tool windows. To access the help, press &lt;F1&gt; or &lt;Help&gt; on
any menu item or dialog. If specific help is not available for an item,
this page will be displayed.</p>
</div>
</body>
</html>

View File

@ -0,0 +1,441 @@
<!DOCTYPE doctype>
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
<TITLE>Theming Developer Documentation</TITLE>
<TITLE></TITLE>
</HEAD>
<BODY>
Theming Development Documentation
<H1>Ghidra Theming Developer Documentation</H1>
<P>This document provides everything an application developer should know when developing
plugins, scripts, etc., that use colors, fonts, or icons. By following these guidelines,
developers can easily make use of Ghidra's theming capabilities.</P>
<H2>Theme Resource Types</H2>
<P>When developing application code for Ghidra such as plugins, actions, etc., developers often
want to use a color, font, or icon. The key idea to support theming is to never directly
reference these resources. Instead, the developer should "create" an id string for the resource
and then in a .theme.properties file provide a default value for that id (and if appropriate,
also define an alternate default value if the theme is a "dark" theme).&nbsp; The way you
define and use these ids is a bit different depending on whether the resource is a color, font,
or icon. Colors and Icons are similar in that references are done using either GColor or GIcon,
Unfortunately, because of the way Fonts are implemented, there is no GFont, so using fonts is a
bit more involved.</P>
<BLOCKQUOTE>
<H3>Colors</H3>
<P>For colors, developers should use the GColor class. Simply construct a new GColor object
passing in the color resource id as the argument. GColor is a subclass of Color, so it can be
used anywhere a Color would be used. The developer then needs to provide a default value for
that id in the module's theme.properties file. So, for example:</P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<CODE class="code">panel.setBackground(Color.Red);</CODE>
</BLOCKQUOTE>
<P>becomes</P>
<BLOCKQUOTE>
<CODE class="code">panel.setBackground(new GColor("color.bg.abc"));</CODE>
</BLOCKQUOTE>
<P>and</P>
<BLOCKQUOTE>
<CODE class="code">public static final Color MY_COLOR = Color.BLUE;</CODE>
</BLOCKQUOTE>
<P>becomes</P>
<BLOCKQUOTE>
<CODE class="code">public static final Color MY_COLOR = new
GColor("color.fg.xzy");</CODE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>The GColor class uses a delegation model where all method calls to GColor get mapped to
its delegate. If ever the color associated with a GColor's resource id changes, the GColor is
refreshed by calling the refresh() method. This is done automatically whenever the
Gui.setColor(id) is called or a new theme is loaded.</P>
<H3>Fonts</H3>
<P>Unfortunately, fonts able to use the delegation trick that was used for colors. Therefore,
there is no GFont class. Programming fonts requires a bit more work. If the use of a font is
in a renderer or in a paint method, imply get the font each time from the Gui class (Font
font = Gui.getFont(String id)). To set a font on a component, use the "registerFont" method
on the Gui class. Once the component is registered, the application will automatically update
the component's font if the font associated with that id changes. So, for example:</P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<CODE class="code">Font font = new Font("Monospaced", Font.BOLD, 12);</CODE>
</BLOCKQUOTE>
<P>becomes</P>
<BLOCKQUOTE>
<CODE class="code">Font font = Gui.getFont("font.xyz");</CODE>
</BLOCKQUOTE>
<P>or</P>
<BLOCKQUOTE>
<CODE class="code">myLabel.setFont(new Font("Dialog", Font.PLAIN, 14)</CODE>
</BLOCKQUOTE>
<P>becomes</P>
<BLOCKQUOTE>
<CODE class="code">Gui.registerFont(myLabel, "font.xyz");</CODE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H3>Icons</H3>
<P>Icons work just like colors, so you can just create a GIcon(String id). So, for
example,&nbsp;</P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<CODE class="code">public static final Icon MY_ICON =
ResourceManager("images/balloon.png");</CODE>
</BLOCKQUOTE>
<P>becomes</P>
<BLOCKQUOTE>
<CODE class="code">public static final Icon MY_ICON = new
GIcon("icon.text.bubble");</CODE>
</BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2>Resource Id Strings<A name="Resource_Ids"></A></H2>
<BLOCKQUOTE>
<P>Resource Ids are strings used to identify the color, font, or icon. These strings are
"made up" by the developer and should be chosen in a way that it is as self describing as
possible. So, for example, if you wanted the text color in some error message in some widget
"abc", you might create the color id "color.fg.abc.error". To make resource ids as consistent
as possible, we created a convention for ids as follows:&nbsp;</P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
<CODE>
[type].[category[...]].[client].[specialized uses]
</CODE>
</PRE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<UL>
<LI><B>type:</B> color, font, or icon.</LI>
<LI><B>category:</B> any value, examples include 'bg'(background), 'fg'(foreground),
'cursor'. There may be multiple dot-separated values.</LI>
<LI><B>client:</B> the plugin name or feature name; any value usd to represent a more
specialized use.</LI>
<LI><B>specialized uses:</B> any key value here that applies to the client, such as
"vertex' for a graph client.</LI>
</UL>
<BLOCKQUOTE>
<P>Examples:</P>
<UL>
<LI>color.bg</LI>
<LI>color.bg.listing</LI>
<LI>font.listing</LI>
<LI>font.listing.header</LI>
<LI>icon.error</LI>
<LI>icon.delete</LI>
<LI>icon.plugin.byteviewer.provider</LI>
</UL>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2>Theme Property Files</H2>
<BLOCKQUOTE>
<P>The default values for resource ids are defined in "theme property" files that created in
each module's data directory. For small modules there can be just one theme properties, but
larger modules should probably use multiple files; one for each sub-feature. The application
will find all theme property files as long as they exist in a module's data directory and end
with '.theme.properties'.</P>
<H3>Theme Properties File Naming Convention</H3>
<P>To promote consistency, theme property files should use the following naming
convention:</P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
<CODE>
[module name][.additional name]].theme.properties
</CODE>
</PRE>
</BLOCKQUOTE>
<P>Examples:</P>
<UL>
<LI>base.theme.properties</LI>
<LI>base.funtiongraph.theme.properties</LI>
</UL>
</BLOCKQUOTE>
<H3>Theme Properties File Format</H3>
<P>Theme files uses a very simple format for specifying theme property values. Each line
specifies a property id (sometimes referfed to as key) and a value, separated by an "=". A
theme properties file consists of two sections: the standard defaults section and a section
for specifying defaults for "dark" themes. So a file theme file uses the following
format:</P>
<BLOCKQUOTE>
<CODE>
<PRE>
[Defaults]
[property id 1] = [some value]
[property id 2] = [some value]
[property id 3] = [some value]
...
[Dark Defaults]
[property id 1] = [some value]
[property id 2] = [some value]
...
</PRE>
</CODE>
</BLOCKQUOTE>
<P>Example:</P>
<BLOCKQUOTE>
<PRE>
[Defaults]
color.bg = white
color.bg.listing = color.bg
color.fg.listing.address = black
color.fg.listing.bytes = #00ff00
font.global = courirer-BOLD-12
font.global.listing = font.global
icon.error = defaultError.png
[Dark Defaults]
color.bg = black
color.fg.listing.address = gray
color.fg.listing.bytes = orange
</PRE>
</BLOCKQUOTE>
<P>NOTE: The [Dark Defaults] section is for overriding values defined in the standard
[Defaults] section. If a property id is not given a value in the defaults section, it is an
error. If a value is not defined in the [Dark Defaults] section, then the value defined in
the [Defaults] section will be used in a dark theme.</P>
</BLOCKQUOTE>
<H2>Theme Property Values<A name="Theme_Property_Values"></A></H2>
<BLOCKQUOTE>
<P>The values specified in the theme properties files can be specified in a variety of ways,
including ways to modify other property values. For example, an icon's size can be modified
directly in the theme properties file. A font value can specified as a reference to another
defined font, but with a different size or style.</P>
<P>Also, any value can also be a reference to some other id of the same type. So, for
example, a reference color entry might be something like "color.bg.listing = color.bg". This
says that the listing's background color should be whatever "color.bg" is defined to be. Note
that all of the application's defined properties start with either "color.", "font.", or
"icon.". Properties defined by a Java LookAndFeel don't follow this pattern. To reference a
property that does not have a standard prefix, an id can be prefixed with "[color]",
"[font]", or "[icon] as appropriate to allow the theme property parser to recognize the
values as ids to other properties. So to refer to a property named "table.background, it
would be "color.bg.table = [color]table.background".</P>
<H3>Color Values</H3>
<P>Color values supports the following formats:</P>
<BLOCKQUOTE>
<UL>
<LI>#rrggbb</LI>
<LI>#rrggbbaa</LI>
<LI>0xrrggbb</LI>
<LI>0xrrggbbaa</LI>
<LI>rgb(red, green, blue)</LI>
<LI>rgba(red, green, blue, alpha)</LI>
<LI>[web color name] the name of a web color such as red, olive, or purple</LI>
</UL>
</BLOCKQUOTE>
<P>Examples:</P>
<PRE>
color.foo = #0000ff // blue
color.foo = #ff000080 // red with half transparency
color.foo = 0x00ff00 // green
color.foo = 0xff000080 // red with half transparency
color.foo = rgb(0, 0, 255) // blue
color.foo = rgba(255,0, 0, 128) // red with half transparency
color.foo = blue // web color defined as 0x0000FF
color.foo = LawnGreen // web color defined as 0x7CFC00
</PRE>
<H3>Font Values</H3>
<P>Font values are specified using the following format:</P>
<BLOCKQUOTE>
<PRE>
<CODE>
[family name]-[style]-[size]
</CODE>
</PRE>
<UL>
<LI>family name: the font name such as monospaced, dialog, courier.</LI>
<LI>style: One of PLAIN, BOLD, ITALIC, or BOLDITALIC.</LI>
<LI>size: the font point size. 12 is very common.</LI>
</UL>
</BLOCKQUOTE>
<P>Examples:</P>
<PRE>
font.foo = monospaced-PLAIN-12
font.foo = courier-BOLD-14
font.foo = SansSerif-ITALIC=10
</PRE>
<H4>Font Modifiers</H4>
<P>When referencing another font, the referenced font can be modified using the following
format:</P>
<BLOCKQUOTE>
<PRE>
<CODE>
font.ref[family name][style][size]
</CODE>
</PRE>
<UL>
<LI>font.ref - the theme property id of some other font</LI>
<LI>family name: use the size and style of the reference font, but use this font
family</LI>
<LI>style: use the same font as the reference font, but with this style. One of PLAIN,
BOLD, ITALIC, or BOLDITALIC</LI>
<LI>size: use the same font as the reference font, but with this size.</LI>
</UL>
</BLOCKQUOTE>
<P>Examples:</P>
<PRE>
font.foo = SansSerif-PLAIN-12 // standard font spec
font.bar = font.foo[BOLD] // results in SansSerif-BOLD-12
font.bar = font.foo[15] // results in SansSerif-PLAIN-15
font.bar = font.foo[monospaced] // results in monospaced-PLAIN-12
font.bar = font.foo[ITALIC][15] // results in SansSerif-ITALIC-15
</PRE>
<H3>Icon Values</H3>
<P>Icon are specified by simply entering the name of an icon that is in the classpath.
However, an icon value can get complicated because it can be modified in a number of ways,
such as scaling, disabling, even overlaying other icons. The format is as follows:</P>
<BLOCKQUOTE>
<PRE>
<CODE>
iconName[size(width,height)][disabled]{iconOverlayName[size(width,geight)[disabled][move(x,y)]}{...}
</CODE>
</PRE>
<UL>
<LI>iconName - the name the base icon</LI>
<LI>size(width,height) - optional modifier to scale the image to the given size.</LI>
<LI>disabled - optional modifier to create a disabled version of the icon.</LI>
<LI>{...} - optional modifier to overlay an icon on the base icon. It is recursively
defined using the same format.</LI>
<LI>move(x,y) - optional modifier on overlays to position them relative to the base
icon.</LI>
</UL>
</BLOCKQUOTE>
<P>Examples:</P>
<PRE>
icon.foo = house.png // using the icon house.png found as an image resource on the classpath
icon.foo = house.png[size(10,10)] // uses the house.png icon, but scales it to 10x10
icon.foo = house.png[disabled] // creates a disabled version of house.png
icon.foo = house.png[16,16]{hammer.png[size(4,4)][move(12,12)]}
// creates a 16x16 version of the house icon with a 4x4 scaled
// hammer.icon overlayed in its lower right corner
</PRE>
<P>To create an icon suitable for dynamically overlaying other icons, there is special syntax
for specifying an empty base icon, then overlay another icon in some specific area of the
empty icon. This icon can then be used to overlay dynamically in the code. For example, to
create an overlay icon that would add a flag to the bottom, right corner any other iconw:</P>
<PRE>
icon.foo = EMPTY_ICON[size(16,16)]{flag.png[size(6,6)][move(10,10)]}
</PRE>
<P class="relatedtopic">Related Topics</P>
<UL>
<LI><A href="ThemingOverview.html">Theming Overview</A></LI>
<LI><A href="ThemingUserDocs.html">Theming User Documentation</A></LI>
<LI><A href="ThemingInternals.html">Theming Architecture Documentation</A></LI>
</UL><BR>
</BLOCKQUOTE>
</BODY>
</HTML>

View File

@ -0,0 +1,186 @@
<!DOCTYPE doctype>
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<TITLE>Theming Internals Documentation</TITLE>
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD>
<BODY>
<H1>Ghidra Theming Internals Documentation</H1>
<P>This document describes the api for initializing and managing themes. A theme (the GTheme
class) in Ghidra represents a specific LookAndFeel as well the set of values for the color,
font, and icon resource ids used in the application.&nbsp; The Gui class provides a set of
static methods that serves as the primary interface for managing all aspects of theming.</P>
<H2>GTheme class</H2>
<P>The GTheme class is the implementation of the theme concept. At any giving time, the
application is using resource values as specified by an&nbsp; active theme. The theme specifies
the LookAndFeel, whether or not the overall theme is "dark" (which determines which default
values to use) and any resource values which have been overridden specifically by that theme.
There are two types of of themes; "built-in"&nbsp; themes and file based themes. "Built-in"
themes are implemented directly as sub-classes of GTheme and simply specify a Java LookAndFeel
and whether or not the theme is "dark". There is one "built-in" theme for each supported
LookAndFeel. File based themes read their values from a theme file. Theme files are created by
editing and saving existing themes.</P>
<H2>GThemeValueMap / ThemeValue class</H2>
<P>These are the base classes for storing values for resource ids.&nbsp; A GThemeValueMap
consists of three hashmaps; one each for colors, fonts, and icons. Each hashmap maps an id to a
appropriate subclass of ThemeValue, which is the base class for ColorValue, FontValue, and
IconValue. Resource values are stored in these ThemeValue sub-classes because the value can be
either a concrete value or be a reference to some other resource of the same type. So, for
example, "color.bg.foo" could map directly to an actual color or its value could be reference
to some other indirect color like "color.bg.bar". In any ThemeValue object, either the
referenceId or the direct value must be null.&nbsp; To get the ultimate concrete value, there
is a convenience method called "get" on ThemeValues that takes a GThemeValueMap as an argument.
This method will recursively resolve referenceIds which is why it needs a value map as an
argument.</P>
<P>GThemeValueMaps have some convenience methods for doing set operations.&nbsp; You can load
values from other GThemeValueMaps into this map, which adds to the current map, replacing
values with the same id with values from the other map. Also, there is a method for getting the
differences from one GThemeValueMap to another.&nbsp;</P>
<H2>Gui class</H2>
<P>The Gui class is a set of static methods that provides the primary API for managing themes.
It has methods for switching themes, adding themes, deleting themes, saving themes, restoring
themes, getting/setting values for resource ids, adding theme listeners, and others.</P>
<H2>Application Initialization</H2>
<P>Applications need to call Gui.initialize() before any uses of color, fonts, or icons occur.
This will load all resource defaults from the theme.properties files, read the last used theme
from preferences, and load that theme which includes setting the LookAndFeel.</P>
<H2>Loading a Theme</H2>
<P>Loading a theme consists of two main operations. Loading the LookAndFeel and building the
set of values for the resource ids.</P>
<H2>Loading the LookAndFeel</H2>
<P>Because each LookAndFeel present different challenges to the theming feature, there is a
LookAndFeelManager for each LookAndFeel. The LookAndFeelManager is responsible for installing
the lookAndFeel (in the case of Nimbus, we had to install a special subclass of the
NimbusLookAndFeel),&nbsp; extracting the Java resources mappings(Java LookAndFeel objects also
use a resource id concept), group the java resources into common groups,&nbsp; possibly fix up
some issues specific to that LookAndFeel, possibly install global properties, and have specific
update (kicking) techniques to get that LookAndFeel to update its componentUIs when values
change.</P>
<H2>Creating the Active Theme Values</H2>
<P>After the LookAndFeel is loaded and the java values extracted, the final resource mapping is
created. This is done by loading various resource values sets(each stored in a GThemeValueMap)
in the correct order into a new GThemeValueMap in GUI called "currentValues" .&nbsp; When
values are loaded into a GThemeValueMap, they will replace any existing values with the same
id.&nbsp; The values are loaded in the following order:</P>
<BLOCKQUOTE>
<UL>
<LI>java defaults (values from LookAndFeel)</LI>
<LI>application defaults (from theme.properties files)</LI>
<LI>applications dark defaults (if theme is dark)</LI>
<LI>theme values (values that were overridden by a specific theme)</LI>
</UL>
</BLOCKQUOTE>
<H2>Changing Values Associated With Resource Ids</H2>
<P>Whenever the value associated with a resource id changes, the application gets "kicked" in
various ways to update the display with the new value. The technique used to "kick" the
application differs depending on the resource type and the LookAndFeel (these differences are
captured in the LookAndFeelManager sub-classes for each LookAndFeel).&nbsp; It can also vary
depending on whether the value is an application defined resource or a java defined
resource.</P>
<H3>Updating Colors</H3>
<P>Updating Colors is the easiest of all the resource. First GColor.refreshAll() is called,
which causes every GColor to refresh its delegate. Next, repaint() is called on all the top
level java windows in the application. Also, since color values in the UIDefaults are actually
replaced with GColor objects, this technique works for both application defined resources and
java defined resources.</P>
<H3>Updating Fonts</H3>
<P>Updating Fonts is a bit more involved. First, if the changed font is java defined, the
UIDefaults for that font Id (and any that derive from it) are updated. Next, all the components
that have a registeredFontId are updated, and finally the updateComponentTreeUI method is
called on all windows in the application.</P>
<H3>Updating Icons</H3>
<P>Updating Icons is a mixed bag. If the Icon is application defined, GIcon.refreshAll() is
called which causes every GIcon to refresh its delegate and then call repaint on all the
windows. If the icon is java defined, then the UIDefaults has to be updated and the
updateComponentTreeUI method on all windows is called.</P>
<H2>Creating/Editing/Saving Themes</H2>
<P>New themes can be created and saved to files in the theme directory in the users ghidra
application directory. When the application is started, this directory is scanned and any
.theme files are loaded and available to be selected as the active theme. The Gui class has
methods for setting the value of a color, font, or icon for a given resource id. If any values
are currently different from the active theme, the theme can be saved. If the active theme is a
built-in theme, then the only choice is to save the theme with a new theme name. Saving the
theme will create a new xxx.theme file where xxx is the name of the theme. Otherwise, the
existing theme file can be overwritten or a new theme name can be supplied to save to a new
file.</P>
<H2>External Icons</H2>
<P>When settings icons for an icon resource id, the user has the option of using a icon that
exists on the application classpath or using any supported icon file (.png or .gif) If the user
chooses to use an icon file, then that icon will be copied into an images directory in their
application directory (.ghidra). These icons are considered external in that if the theme were
given to another user, you would also need to give them the icon files.</P>
<H2>Importing/Exporting Themes</H2>
<P>Themes can be shared with other users by exporting and importing themes. When exporting a
theme that doesn't use any external icons (icons not on the classpath), the theme can be
exported to a .theme file of the users choosing. If the theme does contain external icons, the
user has the option to save the theme as a .zip file which would contain both the .theme file
and all the external icon files.</P>
<H2>LookAndFeel Notes</H2>
<P>Getting the theming feature to work on all the various Java LookAndFeels is a
challenge.&nbsp; Java created the concept of UiDefaults, which is a mapping of property names
to values. The implication is that users can change default values by setting values on the
UIDefaults. Unfortunately, not all LookAndFeels support this concept. Nimbus and GTK+, in
particular are problematic. Nimbus sort of honors values in UIDefaults, but only if they are
installed before Nimbus is loaded. So for out theming purposes, we had to extend the Nimbus
LookAndFeel in order to override the getDefaults() method (this is the method where
LookAndFeels populate the UiDefaults) so that we can install any overridden values from the
selected theme. Also, every time a Java defined property changes, we have to re-install the
Nimbus LookAndFeel because once it is installed, it no longer pays attention to changes to the
UIDefaults.&nbsp; The GTK+ LookAndFeel is even more problematic. It gets many of its properties
from native libraries and there doesn't appear to be anyway of changing them. Therefore, themes
based on GTK+ doesn't allow for changing java defined values.&nbsp; To compensate for the
differences among LookAndFeels, we created a LookAndFeelManager base class with sub-classes for
each LookAndFeel that addresses these differences.</P>
<P class="relatedtopic">Related Topics</P>
<UL>
<LI><A href="ThemingOverview.html">Theming Overview</A></LI>
<LI><A href="ThemingUserDocs.html">Theming User Documentation</A></LI>
<LI><A href="ThemingDeveloperDocs.html">Theming Developer Documentation</A></LI>
</UL><BR>
</BODY>
</HTML>

View File

@ -0,0 +1,118 @@
<!DOCTYPE doctype>
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<TITLE>Theming Overivew</TITLE>
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD>
<BODY>
<H1>Ghidra Theming Overview</H1>
<H2>Goal</H2>
<P>The goal was to add a theming infrastructure/feature to Ghidra that would allow
users/developers to completely configure the colors, fonts, and icons used within Ghidra. There
are two main reasons for creating this feature. The first reason is to create the much
requested "Dark Theme". Many people find Ghidra's current color scheme to be hard on the eyes
and would greatly appreciate a color scheme that is not so bright.&nbsp; The second reason is
for accessibility purposes. For example, the themeing feature would allow for the creating of a
high contrast color scheme, or a color scheme that helps mitigate color blindness or a theme
that uses larger fonts.</P>
&nbsp;
<H2>Background</H2>
<P>Ghidra previously used hundreds of hard coded colors, fonts, and icons.&nbsp; They are
defined throughout the code in a somewhat haphazard fashion. Many features use colors to convey
similar concepts, but no effort was even made to use similar colors for those similar concepts.
Also, these colors were generally chosen to work with one of the common "light" java look and
feels. They often look terrible when used in conjunction with other LookAndFeels, especially
dark ones.</P>
<P>Ghidra does allow some customization of the current colors using "options", but this falls
short for several reasons. One problem is that not all colors or fonts are changeable via the
options. Another problem is that the options are tool based and you have to make the same
customization for each tool. A third problem is that options are unrelated to the LookAndFeel
option. In other words you can't have different option choices depending on the current
LookAndFeel.</P>
<P>Also, all of Ghidra's icons are hard coded and many are not suitable to use in a dark theme.
Overall, the hard coding of colors, fonts, and icons and the limitation of options makes
creating a good dark theme virtually impossible. So to address these issues, a new theming
infrastructure was created.</P>
<H2>General Concepts and Approach</H2>
<P>To achieve a theming capability in Ghidra, we had to implement the following concepts.
First, provide a level of indirection when using colors, fonts, or icons in code. Second,
introduce the concept of a theme which maps the indirect colors. font, and icons to actual
values in the context of a java LookAndFeel. Third, provide access to (and the ability to
change), the colors, fonts, and icons supplied by the Java LookAndFeel. And finally, provide
the GUIs needed to allow users to switch between, create, edit, save, import, and export
themes.</P>
<BLOCKQUOTE>
<H3>Indirection</H3>
<P>The basic idea for indirection is to never directly use a hard coded color, font, or icon
when developing a feature in the application. Instead, these properties will be indirectly
referred to by an identifying string such as "color.bg.mywidget", where the string will
follow a known convention that helps indicate its use. Default values for these identifying
strings will be specified in data files that exist in the module where the code that defined
id is located. Also, the values associated with these ids can be either a concrete value such
as an actual color, font, or icon, or the value can be just an identifying string to
different property. This allows users to change individual values or entire groups of values
with one change.</P>
<H3>Theme</H3>
<P>A theme is simply the object that specifies all the values for colors, fonts, and icons
used in the application as well as the LookAndFeel. The idea is that there will be a set of
themes to choose from and by simply switching the theme, the LookAndFeel and all the colors,
fonts, and icons can be switched out at one time. The set of themes to choose from are a mix
of built-in themes and saved custom themes. There is one built-in theme for each supported
LookAndFeel, which will use the values from the LookAndFeel as well as all the default values
for the defined property ids. Users will be able to create custom themes where they can
basically change any defined color, font, or icon, including those supplied by the associated
LookAndFeel for that theme.</P>
<H3>Look and Feel Values</H3>
<P>The Java LookAndFeel is specified by the active theme. The Java LookAndFeel objects also
define colors, fonts, and icons indirectly using identifying strings such as "Button.font"
and "Menu.background". These values determine the default values used by all GUI elements
unless overridden by developers in code when they create the components. Uses have the
ability to change these values in the same way as values defined by Ghidra code. This will
allow users to generate themes that completely change the look of the GUI with out the
developers having to explicitly set a color, font and icon on every component as they get
created in code.&nbsp; Another concept used by Java LookAndFeels is that many of the
individual components share the same colors and those shared colors are defined using a group
key such as "control", "text", or "menu". The idea is that by changing a group color, all
components that share that group color are changed together. Or an individual components
color can be changed by changing its specific key such as "Menu.background".</P>
<H3>User Interaction</H3>
<P>Users will be able create, edit, delete, import, export, and of course switch the
application's active theme. The GUI theme editor allows users to do all of these actions.
Using the active theme as a starting point, users will be able to change any color, font, or
icon defined either by the LookAndFeel or the application. One or more of these changes can
be saved as a new theme and stored in a file in their application directory. Themes can be
shared with other users by exporting and import themes.</P>
</BLOCKQUOTE>
<P class="relatedtopic">Related Topics</P>
<UL>
<LI><A href="ThemingUserDocs.html">Theming User Documentation</A></LI>
<LI><A href="ThemingDeveloperDocs.html">Theming Developer Documentation</A></LI>
<LI><A href="ThemingInternals.html">Theming Architecture Documentation</A></LI>
</UL><BR>
</BODY>
</HTML>

View File

@ -5,14 +5,14 @@
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<TITLE>Theming</TITLE>
<TITLE>Theming User Documentation</TITLE>
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD>
<BODY>
<H1 align="center">Theming</H1>
<H1 align="center">Theming User Help</H1>
<H2>Overview</H2>
<H2>Description</H2>
<P>The Theming feature allows users to customize the colors, fonts, and icons used throughout
the application. The active theme determines the Java LookAndFeel, whether the theme should use
@ -21,7 +21,7 @@
their home application directory</P>
<P>Users can also edit and create their own themes using the Theme Editor. Custom themes are
stored in the users &lt;application dir&gt;/themes. These are simple text files that can also
stored in the users &lt;application dir&gt;/themes. These are simple text files that can
easily be modified using any text editor. Also, users can share themes by exporting them to a
file that can be given to other users who can them import them into their own system.</P>
@ -171,52 +171,39 @@
<H2>Theme Property Names</H2>
<P>Theme Property Names (also referred to as ids or keys) that are defined by Ghidra use a
common format to help make sorting and viewing properties more intuitive as to their use.</P>
<P>The general format is:</P>
common format to help make sorting and viewing properties more intuitive as to their use. See
the <A href="ThemingDeveloperDocs.html#Resource_Ids">Developer Documentation</A> for more details on the property id
format and naming conventions.</P>
<H2>Theme Files</H2>
<BLOCKQUOTE>
<BLOCKQUOTE>
[type].[category[...]].[client].[specialized uses]
<UL>
<LI><B>type:</B> color, font, or icon</LI>
<P>Theme Files are used to store saved custom themes. They are simple text files and are
stored in the user's home application directory. The first three properties are always the
theme name, the look and feel name, and whether the theme uses standard defaults or dark
defaults. Then there is just a list of overridden property "name = value" lines.So the format
is:</P>
<CODE>
<PRE>
name = [theme name]
lookAndFeel = [lookAndFeel name]
useDarkDefaults = [true or false]
[theme id 1]= [color, icon, or font value]
[theme id 2]= [color, icon, or font value]
[theme id 3]= [color, icon, or font value]
[theme id 4]= [color, icon, or font value]
...
</PRE>
</CODE>
<LI><B>category:</B> any value, examples include "bg" (background), "fg" (foreground);
this may be multiple separated values</LI>
<LI><B>client:</B> the plugin name or feature name; any value used to represent a more
specialized use</LI>
<LI><B>specialized uses:</B> any key value here that applies to the client, such as
"vertex" for a vertex background</LI>
</UL>Examples:
<UL>
<LI>color.bg</LI>
<LI>color.bg.listing</LI>
<LI>font.button</LI>
<LI>icon.refresh</LI>
<LI>icon.refresh.disabled</LI>
</UL>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2>Theme File Format</H2>
<BLOCKQUOTE>
<P>Saved theme files have the following format:</P>
<PRE>
<CODE class="code">
name = ThemeName
<BLOCKQUOTE>
<P>Example:</P>
<PRE>
name = BigFontTheme
lookAndFeel = Nimbus
useDarkDefaults = false
color.bg = Black
color.bg.foo = #012345
[color]Panel.background = Red
@ -224,13 +211,8 @@
icon.refresh = images/reload3.png
color.bg.bar = color.bg.foo
color.bg.xxx = [color]Panel.background
</CODE>
</PRE>
</PRE>
<P>The first three properties are always the theme name, the look and feel name, and whether
the theme uses standard defaults or dark defaults. Then there is just a list of overridden
property "name = value" lines.</P>
<P>Each property line is expected to begin with either "color.", "font.", or "icon." Since
java defined properties don't start with these prefixes, they will have "[color]", "[font]",
@ -242,61 +224,17 @@
right side of the assignment is a property name and not a value, then it must also use the
bracketed prefix if the property name doesn't start with "color.", "font.", or "icon."</P>
<H3>Specifying Color Values</H3>
<H3>Specifying Theme Property Values</H3>
<P>Specifying property values varies depending on whether it is a color, font, or icon. Fonts
and icons also support specifying modifiers. For a complete description of how to specify
these values, see the <A href="ThemingDeveloperDocs.html#Theme_Property_Values">Developer Documentation</A>.
<P>To specify the value for a color, there are 3 acceptable formats:</P>
<UL>
<LI><B>Web Color Name</B> - Examples: Blue, Red, Black, etc.</LI>
<LI><B>Hex value</B> - #rrggbb, Example: #ff01a4, where ff is the red value, 01 is the
green value, and a4 is the blue value</LI>
<LI><B>Hex with alpha value</B> -Example: #ff01a480, where ff is the red value, 01 is the
green value, and a4 is the blue value, and 80 is the alpha value</LI>
<LI><B>RGB values</B> - Example: rgb(12, 34, 56) where red is 12(decimal), green is 34, and
blue is 56</LI>
<LI><B>RGBA values</B> - Eample: rgba(12, 34, 56, 127) where red is 12(decimal), green is
34, blue is 56, and alpha is 127</LI>
</UL>
<H3>Specifying Font Values</H3>
<P>Font values are specified as follows:</P>
<PRE>
familyName-style-size
</PRE>
<UL>
<LI><B>familyName:</B> the font family name such as "monospace", "dialog", "courier"</LI>
<LI><B>style:</B>either PLAIN, BOLD, ITALIC, or BOLDITALIC</LI>
<LI><B>size:</B> the font size such as 12, 14, 22</LI>
</UL>
<P>Examples: monospace-PLAIN-12 or courier-BOLD-15</P>
<H3>Specifying Icon Values</H3>
<P>Icon values are specified by a relative path to the icon file. There are two types of
icons; those that are included with Ghidra and those that were selected from the filesystem
and imported into the theme. Icons that have been imported into the theme are stored in an
images directory in the users Ghidra application directory. Icons included with Ghidra are
relative to an images data directory in some module. So for example,</P>
<PRE>
icon.refresh = images/view-refresh.png
icon.push = [EXTERNAL]images/energy.png
</PRE>
<P>The first example is a standard icon included with Ghidra. It exists in a module's data
directory in the images folder. The second example is for an icon that is not included with
Ghidra. The "[EXTERNAL]" prefix indicates that this icon is being stored in the user's
application directory in the images folder.</P>
</BLOCKQUOTE>
<P class="relatedtopic">Related Topics</P>
<UL>
<LI><A href="ThemingOverview.html">Theming Overview</A></LI>
<LI><A href="ThemingDeveloperDocs.html">Theming Developer Documentation</A></LI>
<LI><A href="ThemingInternals.html">Theming Architecture Documentation</A></LI>
</UL><BR>
</BODY>
</HTML>

View File

@ -72,11 +72,7 @@ public class DockingApplicationLayout extends ApplicationLayout {
* properties.
*
* @param applicationRootDirs list of application root directories which should be
<<<<<<< Upstream, based on origin/master
* used to identify modules and resources. The first entry will be treated as the
=======
* used to identify modules and resources. The first entry will be treated as the
>>>>>>> 4485b75 GP-1981 - Support Tool - initial support tool fixes; updates to module discovery to use the classpath in dev mode for filtering
* installation root.
* @param applicationProperties The properties object that will be read system properties.
* @throws FileNotFoundException if there was a problem getting a user directory.

View File

@ -51,6 +51,12 @@ import utilities.util.reflection.ReflectionUtilities;
*/
public class HelpManager implements HelpService {
/**
* The hardcoded value to use for all HelpSet 'home id' values. Subclasses may change this
* value by overriding {@link #getHomeId()}.
*/
private static final String HOME_ID = "Misc_Help_Contents";
public static final String SHOW_AID_KEY = "SHOW.HELP.NAVIGATION.AID";
private static final String TABLE_OF_CONTENTS_FILENAME_KEY = "data";
@ -84,6 +90,7 @@ public class HelpManager implements HelpService {
*/
protected HelpManager(URL url) throws HelpSetException {
mainHS = new DockingHelpSet(new GHelpClassLoader(null), url);
mainHS.setHomeID(getHomeId());
mainHB = mainHS.createHelpBroker();
mainHS.setTitle(GHIDRA_HELP_TITLE);
@ -121,6 +128,15 @@ public class HelpManager implements HelpService {
}
}
/**
* Returns the 'home id' to be used by all help sets in the system (as opposed to allowing each
* help set to define its own home id.
* @return the home id
*/
protected String getHomeId() {
return HOME_ID;
}
@Override
public void excludeFromHelp(Object helpObject) {
excludedFromHelp.add(helpObject);
@ -695,6 +711,7 @@ public class HelpManager implements HelpService {
private HelpSet createHelpSet(URL url, GHelpClassLoader classLoader) throws HelpSetException {
if (!urlToHelpSets.containsKey(url)) {
GHelpSet hs = new GHelpSet(classLoader, url);
hs.setHomeID(getHomeId());
urlToHelpSets.put(url, hs);
return hs;
}

View File

@ -211,7 +211,7 @@ public class ToolIconURL implements Comparable<ToolIconURL> {
}
private ImageIcon getImageIcon(String name) {
ImageIcon image = ResourceManager.loadImage(name);
ImageIcon image = ResourceManager.findIcon(name);
if (image instanceof UnresolvedIcon) {
return null;
}

View File

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 709 B

After

Width:  |  Height:  |  Size: 709 B

View File

@ -15,10 +15,6 @@
*/
package docking.widgets.fieldpanel;
import static org.junit.Assert.*;
import java.awt.Color;
import org.junit.Test;
import docking.widgets.fieldpanel.internal.ColorRangeMap;
@ -60,8 +56,4 @@ public class ColorRangeMapTest extends AbstractGenericTest {
assertColorsEqual(Palette.WHITE, map.getColor(100, Palette.WHITE));
}
private void assertColorsEqual(Color c1, Color c2) {
assertEquals(c1.getRGB(), c2.getRGB());
}
}

View File

@ -25,6 +25,8 @@ src/main/resources/generic.log4j.xml||GHIDRA||||END|
src/main/resources/generic.log4jdev.xml||GHIDRA||||END|
src/main/resources/generic.log4jfile.xml||GHIDRA||||END|
src/main/resources/generic.log4jtest.xml||GHIDRA||||END|
src/main/resources/images/EmptyIcon.gif||GHIDRA||||END|
src/main/resources/images/EmptyIcon16.gif||GHIDRA||||END|
src/main/resources/images/GhidraIcon128.png||GHIDRA||||END|
src/main/resources/images/GhidraIcon16.png||GHIDRA||||END|
src/main/resources/images/GhidraIcon24.png||GHIDRA||||END|
@ -36,34 +38,57 @@ src/main/resources/images/GhidraIcon64.png||GHIDRA||||END|
src/main/resources/images/Plus2.png||GHIDRA||||END|
src/main/resources/images/applications-multimedia16.png||Tango Icons - Public Domain|||tango|END|
src/main/resources/images/checkmark_green.gif||GHIDRA||||END|
src/main/resources/images/closedSmallFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
src/main/resources/images/collapse_all.png||GHIDRA||||END|
src/main/resources/images/core.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/core24.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/dialog-cancel.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/disk.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/disk_save_as.png||FAMFAMFAM Icons - CC 2.5||||END|
src/main/resources/images/down.png||GHIDRA||||END|
src/main/resources/images/dragon16.gif||GHIDRA||||END|
src/main/resources/images/edit-cut.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/edit-cut22.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/emblem-important.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/erase16.png||GHIDRA||||END|
src/main/resources/images/error.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/exec.png||Crystal Clear Icons - LGPL 2.1||||END|
src/main/resources/images/expand_all.png||GHIDRA||||END|
src/main/resources/images/face-monkey16.png||Tango Icons - Public Domain|||originally face-monkey from tango|END|
src/main/resources/images/flag.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/go-home.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/greenDragon16.png||GHIDRA||||END|
src/main/resources/images/greenDragon24.png||GHIDRA||||END|
src/main/resources/images/help-browser.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/information.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/internet-web-browser16.png||Tango Icons - Public Domain|||originally internet-web-browser.png from tango|END|
src/main/resources/images/kgpg.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/left.alternate.png||GHIDRA||||END|
src/main/resources/images/left.png||GHIDRA||||END|
src/main/resources/images/locationIn.gif||GHIDRA||||END|
src/main/resources/images/locationOut.gif||GHIDRA||||END|
src/main/resources/images/mergemgr16.gif||GHIDRA||||END|
src/main/resources/images/network-receive16.png||Tango Icons - Public Domain|||originally network-receive.png from tango|END|
src/main/resources/images/openFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
src/main/resources/images/openSmallFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
src/main/resources/images/page_paste.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/page_white_copy.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/process-stop.png||Tango Icons - Public Domain|||Theirs: Oxygen icon theme (dual license; LGPL or CC-SA-3.0)tango icon set|END|
src/main/resources/images/program_obj.png||GHIDRA|||Custom Icon|END|
src/main/resources/images/redDragon16.png||GHIDRA|||Renamed GIF version of redDragon16.png|END|
src/main/resources/images/redDragon24.png||GHIDRA||||END|
src/main/resources/images/redDragon32.png||GHIDRA||||END|
src/main/resources/images/reload3.png||Crystal Clear Icons - LGPL 2.1||||END|
src/main/resources/images/right.alternate.png||GHIDRA||||END|
src/main/resources/images/right.png||GHIDRA||||END|
src/main/resources/images/software-update-urgent.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/sortascending.png||GHIDRA||||END|
src/main/resources/images/sortdescending.png||GHIDRA||||END|
src/main/resources/images/text_align_justify.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/up.png||GHIDRA||||END|
src/main/resources/images/video-x-generic16.png||Tango Icons - Public Domain|||tango|END|
src/main/resources/images/viewmagfit.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
src/main/resources/images/warning.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/log4j-appender-console-with-links.xml||GHIDRA||||END|
src/main/resources/log4j-appender-console.xml||GHIDRA||||END|
src/main/resources/log4j-appender-logpanel.xml||GHIDRA||||END|

View File

@ -7,5 +7,65 @@ font.italics = font.standard[italic]
font.bold.italic = font.standard[bold][italic]
font.monospaced = monospaced-PLAIN-12
// Icons files
icon.flag = flag.png
icon.lock = kgpg.png
icon.checkmark.green = checkmark_green.gif
icon.empty = EmptyIcon16.gif
icon.empty.20 = EmptyIcon.gif
icon.help = help-browser.png
icon.add = Plus2.png
icon.copy = page_white_copy.png
icon.cut = edit-cut.png
icon.paste = page_paste.png
icon.collapse.all = collapse_all.png
icon.expand.all = expand_all.png
icon.configure.filter = exec.png
icon.clear = erase16.png
icon.delete = icon.error
icon.error = emblem-important.png
icon.home = go-home.png
icon.navigate.in = locationIn.gif
icon.navigate.out = locationOut.gif
icon.not.allowed = dialog-cancel.png
icon.folder.open = openSmallFolder.png
icon.folder.closed = closedSmallFolder.png
icon.refresh = reload3.png
icon.sort.ascending = sortascending.png
icon.sort.descending = sortdescending.png
icon.stop = process-stop.png
icon.warning.strong = software-update-urgent.png
icon.warning = warning.png
icon.information = information.png
icon.left = left.png
icon.right = right.png
icon.up = up.png
icon.down = down.png
icon.left.alt = left.alternate.png
icon.right.alt = right.alternate.png
icon.save = disk.png
icon.save.as = disk_save_as.png
icon.make.selection = text_align_justify.png
icon.arrow.down.right = viewmagfit.png[rotate(90)]
icon.arrow.up.left = viewmagfit.png[rotate(275)]
icon.filter.not.accepted = icon.flag{dialog-cancel.png[size(10,10)][move(6,6)]}
icon.blocked.match = icon.lock{icon.checkmark.green[size(12,12)][move(4,0)]}
[Dark Defaults]

View File

@ -45,6 +45,7 @@ import org.junit.runner.Description;
import generic.jar.ResourceFile;
import generic.test.rule.Repeated;
import generic.test.rule.RepeatedTestRule;
import generic.theme.GIcon;
import generic.theme.Gui;
import generic.util.WindowUtilities;
import ghidra.GhidraTestApplicationLayout;
@ -56,6 +57,7 @@ import ghidra.util.exception.AssertException;
import ghidra.util.task.AbstractSwingUpdateManager;
import ghidra.util.task.SwingUpdateManager;
import junit.framework.AssertionFailedError;
import resources.icons.UrlImageIcon;
import sun.awt.AppContext;
import utilities.util.FileUtilities;
import utilities.util.reflection.ReflectionUtilities;
@ -2050,4 +2052,51 @@ public abstract class AbstractGenericTest extends AbstractGTest {
}
}
/**
* Asserts that the two colors have the same rgb values (handles GColor)
* @param expected the expected color
* @param actual the actual color
*/
public void assertColorsEqual(Color expected, Color actual) {
if (expected.getRGB() == actual.getRGB()) {
return;
}
fail("Expected: [" + expected.getClass().getSimpleName() + "]" + expected +
", but got: [" + actual.getClass().getSimpleName() + "]" + actual);
}
/**
* Asserts that the two icons are or refer to the same icon (handles GIcon)
* @param expected the expected icon
* @param actual the actual icon
*/
public void assertIconsEqual(Icon expected, Icon actual) {
if (expected.equals(actual)) {
return;
}
URL url1 = getURL(expected);
URL url2 = getURL(actual);
if (url1 != null && url1.equals(url2)) {
return;
}
fail("Expected icon [" + expected.getClass().getSimpleName() + "]" + expected.toString() +
", but got: [" + actual.getClass().getSimpleName() + "]" + actual.toString());
}
/**
* Gets the URL for the given icon
* @param icon the icon to get a URL for
* @return the URL for the given icon
*/
public URL getURL(Icon icon) {
if (icon instanceof UrlImageIcon urlIcon) {
return urlIcon.getUrl();
}
if (icon instanceof GIcon gIcon) {
return gIcon.getUrl();
}
return null;
}
}

View File

@ -32,7 +32,7 @@ public class ColorValue extends ThemeValue<Color> {
private static final String EXTERNAL_PREFIX = "[color]";
private static final String SYSTEM_COLOR_PREFIX = "system.color";
public static final Color LAST_RESORT_DEFAULT = Color.GRAY;
public static final Color LAST_RESORT_DEFAULT = new Color(128, 128, 128);
/**
* Constructor used when the ColorValue will have a direct {@link Color} value. The refId will
@ -93,7 +93,7 @@ public class ColorValue extends ThemeValue<Color> {
}
@Override
protected Color getUnresolvedReferenceValue(String unresolvedId) {
protected Color getUnresolvedReferenceValue(String id, String unresolvedId) {
Throwable t = ReflectionUtilities.createThrowableWithStackOlderThan();
StackTraceElement[] trace = t.getStackTrace();
@ -103,9 +103,8 @@ public class ColorValue extends ThemeValue<Color> {
t.setStackTrace(filtered);
Msg.error(this,
"Could not resolve indirect color for \"" + unresolvedId +
"\", using last resort default!",
t);
"Could not resolve indirect color path for \"" + unresolvedId +
"\" for primary id \"" + id + "\", using last resort default");
return LAST_RESORT_DEFAULT;
}

View File

@ -143,9 +143,10 @@ public class FontValue extends ThemeValue<Font> {
}
@Override
protected Font getUnresolvedReferenceValue(String unresolvedId) {
Msg.warn(this, "Could not resolve indirect font for " + unresolvedId +
", using last resort default");
protected Font getUnresolvedReferenceValue(String id, String unresolvedId) {
Msg.warn(this,
"Could not resolve indirect font path for \"" + unresolvedId +
"\" for primary id \"" + id + "\", using last resort default");
return LAST_RESORT_DEFAULT;
}

View File

@ -127,6 +127,10 @@ public class GColor extends Color {
return delegate.darker();
}
public boolean isUnresolved() {
return delegate == ColorValue.LAST_RESORT_DEFAULT;
}
@Override
public String toString() {
return toHexString();

View File

@ -321,7 +321,11 @@ public class Gui {
* @return the current {@link Font} associated with the given id.
*/
public static Font getFont(String id) {
return getFont(id, true);
Font font = getFont(id, true);
if (font == FontValue.LAST_RESORT_DEFAULT) {
return null;
}
return font;
}
/**
@ -390,6 +394,15 @@ public class Gui {
* @param color the new color for the id
*/
public static void setColor(String id, Color color) {
if (color == null) {
}
if (color instanceof GColor gColor) {
if (id.equals(gColor.getId())) {
Msg.warn(Gui.class, "Attempted to set a color to a reference to itself!");
return; // this would create a circular reference to itself, don't do it
}
}
setColor(new ColorValue(id, color));
}
@ -407,7 +420,9 @@ public class Gui {
notifyThemeChanged(new ColorChangedThemeEvent(currentValues, newValue));
// now update the ui
lookAndFeelManager.colorsChanged();
if (lookAndFeelManager != null) {
lookAndFeelManager.colorsChanged();
}
}
/**

View File

@ -180,7 +180,7 @@ public class IconValue extends ThemeValue<Icon> {
}
private static int getModifierIndex(String value) {
int baseModifierIndex = value.indexOf("[", 1); // start past first char as it coud be valid "[EXTERNAL]" prefix
int baseModifierIndex = value.indexOf("[", 1); // start past first char as it could be valid "[EXTERNAL]" prefix
int overlayModifierIndex = value.indexOf("{");
if (baseModifierIndex < 0) {
return overlayModifierIndex;
@ -197,10 +197,10 @@ public class IconValue extends ThemeValue<Icon> {
}
@Override
protected Icon getUnresolvedReferenceValue(String unresolvedId) {
protected Icon getUnresolvedReferenceValue(String id, String unresolvedId) {
Msg.warn(this,
"Could not resolve indirect icon path for \"" + unresolvedId +
"\", using last resort default");
"\" for primary id \"" + id + "\", using last resort default");
return LAST_RESORT_DEFAULT;
}

View File

@ -33,6 +33,9 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
protected final String referenceId;
protected ThemeValue(String id, String referenceId, T value) {
if (id.equals(referenceId)) {
throw new IllegalArgumentException("Can't create a themeValue that referencs itself");
}
this.id = id;
this.referenceId = referenceId;
this.value = value;
@ -92,11 +95,11 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
visitedKeys.add(parent.id);
if (visitedKeys.contains(parent.referenceId)) {
Msg.warn(this, "Theme value reference loop detected for key: " + id);
return getUnresolvedReferenceValue(id);
return getUnresolvedReferenceValue(id, parent.referenceId);
}
parent = getReferredValue(values, parent.referenceId);
}
return getUnresolvedReferenceValue(id);
return getUnresolvedReferenceValue(id, referenceId);
}
/**
@ -151,10 +154,11 @@ public abstract class ThemeValue<T> implements Comparable<ThemeValue<T>> {
/**
* Returns the T to be used if the indirect reference couldn't be resolved.
* @param unresolvedId the id that couldn't be resolved
* @param id the id we are trying to get a value foe
* @param unresolvedId the reference id that couldn't be resolved
* @return the default value to be used if the indirect reference couldn't be resolved.
*/
protected abstract T getUnresolvedReferenceValue(String unresolvedId);
protected abstract T getUnresolvedReferenceValue(String id, String unresolvedId);
/**
* Returns the ThemeValue referred to by this ThemeValue. Needs to be overridden by

View File

@ -141,7 +141,7 @@ public abstract class AbstractOptions implements Options {
if (type == OptionType.COLOR_TYPE) {
if (defaultValue instanceof GColor gColor) {
registerThemeColor(optionName, gColor.getId(), help, description);
registerThemeColor(optionName, gColor.getId(), help, description, editor);
return;
}
warnNonThemeValue("Registering non theme color: " + optionName);
@ -197,14 +197,14 @@ public abstract class AbstractOptions implements Options {
}
private void registerThemeColor(String optionName, String colorId, HelpLocation help,
String description) {
String description, PropertyEditor editor) {
Option currentOption = getExistingComptibleOption(optionName, OptionType.COLOR_TYPE);
if (currentOption != null && currentOption instanceof ThemeColorOption) {
currentOption.updateRegistration(description, help, null, null);
currentOption.updateRegistration(description, help, null, editor);
return;
}
description += " (Theme Color: " + colorId + ")";
Option option = new ThemeColorOption(optionName, colorId, description, help);
Option option = new ThemeColorOption(optionName, colorId, description, help, editor);
valueMap.put(optionName, option);
}

View File

@ -186,4 +186,9 @@ public class EditorState implements PropertyChangeListener {
return options.getDescription(name);
}
@Override
public String toString() {
return "EditorState: " + name + "= " + currentValue;
}
}

View File

@ -16,7 +16,9 @@
package ghidra.framework.options;
import java.awt.Color;
import java.beans.PropertyEditor;
import generic.theme.GColor;
import generic.theme.Gui;
import ghidra.util.HelpLocation;
@ -30,14 +32,23 @@ public class ThemeColorOption extends Option {
private String colorId;
public ThemeColorOption(String optionName, String colorId, String description,
HelpLocation help) {
super(optionName, OptionType.COLOR_TYPE, description, help, null, true, null);
HelpLocation help, PropertyEditor editor) {
super(optionName, OptionType.COLOR_TYPE, description, help, null, true, editor);
this.colorId = colorId;
}
@Override
public Color getCurrentValue() {
return Gui.getColor(colorId);
GColor gColor = new GColor(colorId);
if (gColor.isUnresolved()) {
return null;
}
return gColor;
}
@Override
public Object getDefaultValue() {
return getCurrentValue();
}
@Override

View File

@ -40,6 +40,11 @@ public class ThemeFontOption extends Option {
return Gui.getFont(fontId);
}
@Override
public Object getDefaultValue() {
return getCurrentValue();
}
@Override
public void doSetCurrentValue(Object value) {
Gui.setFont(fontId, (Font) value);

View File

Before

Width:  |  Height:  |  Size: 58 B

After

Width:  |  Height:  |  Size: 58 B

View File

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 771 B

View File

Before

Width:  |  Height:  |  Size: 620 B

After

Width:  |  Height:  |  Size: 620 B

View File

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 974 B

View File

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 192 B

View File

Before

Width:  |  Height:  |  Size: 807 B

After

Width:  |  Height:  |  Size: 807 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 606 B

View File

Before

Width:  |  Height:  |  Size: 778 B

After

Width:  |  Height:  |  Size: 778 B

View File

Before

Width:  |  Height:  |  Size: 188 B

After

Width:  |  Height:  |  Size: 188 B

View File

Before

Width:  |  Height:  |  Size: 219 B

After

Width:  |  Height:  |  Size: 219 B

View File

Before

Width:  |  Height:  |  Size: 220 B

After

Width:  |  Height:  |  Size: 220 B

View File

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

View File

Before

Width:  |  Height:  |  Size: 190 B

After

Width:  |  Height:  |  Size: 190 B

View File

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 193 B

View File

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 975 B

View File

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 666 B

View File

@ -28,7 +28,6 @@ import org.junit.Test;
import generic.constraint.DecisionNode.PropertyValue;
import generic.test.AbstractGenericTest;
import generic.theme.GThemeDefaults.Colors.Palette;
public class DecisionTreeTest extends AbstractGenericTest {
@ -134,7 +133,7 @@ public class DecisionTreeTest extends AbstractGenericTest {
@Test
public void testMatchFromFirstXML() {
Color c = Palette.WHITE;
Color c = Color.WHITE;
DecisionSet decisionSet = decisionTree.getDecisionsSet(c, "NAME");
List<Decision> decisions = decisionSet.getDecisions();
assertEquals(1, decisions.size());
@ -147,7 +146,7 @@ public class DecisionTreeTest extends AbstractGenericTest {
@Test
public void testMatchFromAdditionalXML() {
Color c = Palette.MAGENTA;
Color c = new Color(255, 0, 255);
DecisionSet decisionSet = decisionTree.getDecisionsSet(c, "NAME");
List<Decision> decisions = decisionSet.getDecisions();
assertEquals(1, decisions.size());
@ -160,7 +159,7 @@ public class DecisionTreeTest extends AbstractGenericTest {
@Test
public void testMatchMultiple() {
Color c = Palette.YELLOW;
Color c = Color.YELLOW;
DecisionSet decisionSet = decisionTree.getDecisionsSet(c, "NAME");
List<Decision> decisions = decisionSet.getDecisions();
assertEquals(2, decisions.size());
@ -179,7 +178,7 @@ public class DecisionTreeTest extends AbstractGenericTest {
@Test
public void testNoMatchUsingDefault() {
Color c = Palette.GRAY;
Color c = Color.GRAY;
DecisionSet decisionSet = decisionTree.getDecisionsSet(c, "NAME");
List<Decision> decisions = decisionSet.getDecisions();
assertEquals(1, decisions.size());

View File

@ -69,6 +69,7 @@ public class GuiTest {
Gui.setThemePreferenceManager(new ThemePreferenceManager() {
@Override
public GTheme getTheme() {
return new MetalTheme();
}
@ -337,7 +338,7 @@ public class GuiTest {
@Test
public void testGetApplicationDarkDefaults() {
// dark defaults are a combination of standard defalts overlayed with dark defaults
// dark defaults are a combination of standard defaults overlayed with dark defaults
GThemeValueMap expected = new GThemeValueMap();
expected.load(defaultValues);
expected.load(darkDefaultValues);

View File

@ -21,8 +21,6 @@ import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import generic.theme.GThemeDefaults.Colors.Palette;
public class HTMLUtilitiesTest {
private SpyErrorLogger spyLogger = new SpyErrorLogger();
@ -128,13 +126,13 @@ public class HTMLUtilitiesTest {
@Test
public void testToRGBString() {
String rgb = HTMLUtilities.toRGBString(Palette.RED);
String rgb = HTMLUtilities.toRGBString(WebColors.RED);
assertEquals("255000000", rgb);
}
@Test
public void testToHexString() {
String rgb = HTMLUtilities.toHexString(Palette.RED);
String rgb = HTMLUtilities.toHexString(WebColors.RED);
assertEquals("#FF0000", rgb);
}

View File

@ -15,7 +15,7 @@
*/
package ghidra.graph;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
@ -25,6 +25,8 @@ import javax.swing.JFrame;
import org.junit.Test;
import docking.framework.DockingApplicationConfiguration;
import ghidra.framework.ApplicationConfiguration;
import ghidra.graph.algo.*;
import ghidra.graph.algo.viewer.*;
import ghidra.util.SystemUtilities;
@ -37,6 +39,13 @@ import ghidra.util.exception.CancelledException;
*/
public class GraphAlgorithmsVisualDebugger extends AbstractGraphAlgorithmsTest {
@Override
protected ApplicationConfiguration createApplicationConfiguration() {
DockingApplicationConfiguration config = new DockingApplicationConfiguration();
config.setShowSplashScreen(false);
return config;
}
@Override
protected GDirectedGraph<TestV, TestE> createGraph() {
return GraphFactory.createDirectedGraph();

View File

@ -17,6 +17,7 @@ package ghidra.service.graph;
import static org.junit.Assert.*;
import java.awt.Font;
import java.util.Arrays;
import java.util.List;
@ -24,22 +25,47 @@ import org.junit.Before;
import org.junit.Test;
import docking.FakeDockingTool;
import docking.test.AbstractDockingTest;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.Gui;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.util.HelpLocation;
public class GraphDisplayOptionsTest {
public class GraphDisplayOptionsTest extends AbstractDockingTest {
private GraphType graphType;
private GraphDisplayOptions options;
@Before
public void setUp() {
Gui.setColor("color.V1", Palette.BLACK);
Gui.setColor("color.V2", Palette.BLACK);
Gui.setColor("color.V3", Palette.BLACK);
Gui.setColor("color.E1", Palette.BLACK);
Gui.setColor("color.E2", Palette.BLACK);
Gui.setColor("color.E3", Palette.BLACK);
Gui.setColor("color.edge.default", Palette.BLACK);
Gui.setColor("color.vertex.default", Palette.BLACK);
Gui.setColor("color.edge.selected", Palette.BLACK);
Gui.setColor("color.vertex.selected", Palette.BLACK);
Gui.setFont("font.graph", new Font("monospaced", Font.PLAIN, 12));
List<String> vertexTypes = Arrays.asList("V1", "V2", "V3");
List<String> edgeTypes = Arrays.asList("E1", "E2", "E3");
graphType = new GraphType("Test", "Test Description", vertexTypes, edgeTypes);
options = new GraphDisplayOptions(graphType);
options.setVertexColor("V1", "color.V1");
options.setVertexColor("V2", "color.V2");
options.setVertexColor("V3", "color.V3");
options.setEdgeColor("E1", "color.E1");
options.setEdgeColor("E2", "color.E2");
options.setEdgeColor("E3", "color.E3");
options.setDefaultEdgeColor("color.edge.default");
options.setDefaultVertexColor("color.vertex.default");
options.setEdgeSelectionColor("color.edge.selected");
options.setVertexSelectionColor("color.vertex.selected");
options.setFont("font.graph");
}
@Test
@ -204,9 +230,10 @@ public class GraphDisplayOptionsTest {
@Test
public void testGetVertexColorForType() {
assertEquals(options.getDefaultVertexColor(), options.getVertexColor("V1"));
assertEquals(options.getDefaultVertexColor().getRGB(),
options.getVertexColor("V1").getRGB());
options.setVertexColor("V1", Palette.RED);
assertEquals(Palette.RED, options.getVertexColor("V1"));
assertEquals(Palette.RED.getRGB(), options.getVertexColor("V1").getRGB());
}
@Test
@ -235,8 +262,8 @@ public class GraphDisplayOptionsTest {
Options vertexColorOptions = graphDisplayOptions.getOptions("Vertex Colors");
List<String> leafOptionNames = vertexColorOptions.getLeafOptionNames();
assertEquals(Arrays.asList("V1", "V2", "V3"), leafOptionNames);
assertEquals(options.getDefaultVertexColor(),
vertexColorOptions.getColor("V1", Palette.WHITE));
assertEquals(options.getDefaultVertexColor().getRGB(),
vertexColorOptions.getColor("V1", Palette.BLACK).getRGB());
Options vertexShapeOptions = graphDisplayOptions.getOptions("Vertex Shapes");
leafOptionNames = vertexShapeOptions.getLeafOptionNames();
@ -247,8 +274,8 @@ public class GraphDisplayOptionsTest {
Options edgeColorOptions = graphDisplayOptions.getOptions("Edge Colors");
leafOptionNames = edgeColorOptions.getLeafOptionNames();
assertEquals(Arrays.asList("E1", "E2", "E3"), leafOptionNames);
assertEquals(options.getDefaultEdgeColor(),
edgeColorOptions.getColor("E1", Palette.WHITE));
assertEquals(options.getDefaultEdgeColor().getRGB(),
edgeColorOptions.getColor("E1", Palette.WHITE).getRGB());
Options miscellaneousOptions = graphDisplayOptions.getOptions("Miscellaneous");
leafOptionNames = miscellaneousOptions.getLeafOptionNames();
@ -268,13 +295,13 @@ public class GraphDisplayOptionsTest {
AttributedVertex vertex = new AttributedVertex("Foo");
vertex.setVertexType("V1");
assertEquals(Palette.BLUE.getRGB(), options.getVertexColor(vertex).getRGB());
assertEquals(Palette.BLACK.getRGB(), options.getVertexColor(vertex).getRGB());
Options graphDisplayOptions = toolOptions.getOptions(options.getRootOptionsName());
Options vertexColorOptions = graphDisplayOptions.getOptions("Vertex Colors");
vertexColorOptions.setColor("V1", Palette.CYAN);
vertexColorOptions.setColor("V1", Palette.GOLD);
assertEquals(Palette.CYAN, options.getVertexColor(vertex));
assertEquals(Palette.GOLD.getRGB(), options.getVertexColor(vertex).getRGB());
}
}

View File

@ -18,10 +18,10 @@ package help;
import java.awt.Component;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Locale;
import java.util.*;
import javax.help.*;
import javax.help.Map;
import javax.help.Map.ID;
import javax.help.event.HelpModelEvent;
import javax.help.plaf.HelpNavigatorUI;
@ -143,6 +143,8 @@ public class CustomTOCView extends TOCView {
* Our hook to install our custom cell renderer.
*/
class CustomTOCNavigatorUI extends BasicTOCNavigatorUI {
private static final String ROOT_TOC_ID = "Root";
public CustomTOCNavigatorUI(JHelpTOCNavigator b) {
super(b);
}
@ -184,27 +186,42 @@ public class CustomTOCView extends TOCView {
}
TOCItem item = (TOCItem) treeItem;
ID itemID = item.getID();
if (itemID == null) {
Msg.debug(this, "No help ID for " + item);
return;
}
String presentation = item.getPresentation();
if (presentation != null) {
return; // don't currently support presentations
}
CustomTreeItemDecorator customItem = (CustomTreeItemDecorator) item;
ID itemId = getId(customItem, helpModel);
if (itemId == null) {
Msg.debug(this, "No help ID for " + item);
return;
}
String customDisplayText = customItem.getDisplayText();
try {
helpModel.setCurrentID(itemID, customDisplayText, navigator);
helpModel.setCurrentID(itemId, customDisplayText, navigator);
}
catch (InvalidHelpSetContextException ex) {
Msg.error(this, "Exception setting new help item ID", ex);
}
}
private ID getId(CustomTreeItemDecorator item, HelpModel helpModel) {
ID itemId = item.getID();
if (itemId != null) {
return itemId;
}
String tocID = item.getTocID();
if (Objects.equals(tocID, ROOT_TOC_ID)) {
HelpSet hs = helpModel.getHelpSet();
return hs.getHomeID();
}
return null;
}
private TOCItem getSelectedItem(TreeSelectionEvent e, JHelpNavigator navigator) {
TreePath newLeadSelectionPath = e.getNewLeadSelectionPath();
if (newLeadSelectionPath == null) {

View File

@ -21,7 +21,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import ghidra.GhidraApplicationLayout;
import generic.theme.Gui;
import ghidra.framework.Application;
import ghidra.framework.ApplicationConfiguration;
import help.validator.*;
@ -55,8 +55,8 @@ public class GHelpBuilder {
private String outputDirectoryName;
private String moduleName;
private Collection<File> dependencyHelpPaths = new LinkedHashSet<File>();
private Collection<File> helpInputDirectories = new LinkedHashSet<File>();
private Collection<File> dependencyHelpPaths = new LinkedHashSet<>();
private Collection<File> helpInputDirectories = new LinkedHashSet<>();
private static boolean debugEnabled = false;
private boolean ignoreInvalid = false; // TODO: Do actual validation here
@ -66,9 +66,18 @@ public class GHelpBuilder {
public static void main(String[] args) throws Exception {
GHelpBuilder builder = new GHelpBuilder();
builder.exitOnError = true;
ApplicationConfiguration config = new ApplicationConfiguration() {
@Override
protected void initializeApplication() {
Gui.initialize();
}
ApplicationConfiguration config = new ApplicationConfiguration();
Application.initializeApplication(new GhidraApplicationLayout(), config);
@Override
public boolean isHeadless() {
return false;
}
};
Application.initializeApplication(new HelpApplicationLayout("Help Builder", "0.1"), config);
builder.build(args);
}
@ -98,7 +107,7 @@ public class GHelpBuilder {
}
private HelpModuleCollection collectAllHelp() {
List<File> allHelp = new ArrayList<File>(helpInputDirectories);
List<File> allHelp = new ArrayList<>(helpInputDirectories);
for (File file : dependencyHelpPaths) {
allHelp.add(file);
}

View File

@ -34,6 +34,8 @@ import javax.swing.text.html.*;
import javax.swing.text.html.HTML.Tag;
import generic.jar.ResourceFile;
import generic.theme.GIcon;
import generic.theme.Gui;
import ghidra.framework.Application;
import ghidra.framework.preferences.Preferences;
import ghidra.util.Msg;
@ -480,6 +482,12 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit {
}
String srcString = src.toString();
//check if the icon is a defined icon theme id
if (Gui.hasIcon(srcString)) {
return new GIcon(srcString).getUrl();
}
if (isJavaCode(srcString)) {
return installImageFromJavaCode(srcString);
}

View File

@ -54,8 +54,6 @@ import ghidra.util.SystemUtilities;
*/
public class GHelpSet extends HelpSet {
private static final String HOME_ID = "Misc_Welcome_to_Ghidra_Help";
/** <b>static</b> map that contains all known help sets in the system. */
private static java.util.Map<HelpSet, Map> helpSetsToCombinedMaps = new java.util.HashMap<>();
private static java.util.Map<HelpSet, Map> helpSetsToLocalMaps = new java.util.HashMap<>();
@ -79,8 +77,6 @@ public class GHelpSet extends HelpSet {
setKeyData(kitTypeRegistry, type, editorKit);
setKeyData(kitLoaderRegistry, type, classLoader);
setHomeID(HOME_ID);
initializeCombinedMapWrapper();
}
@ -121,6 +117,11 @@ public class GHelpSet extends HelpSet {
}
}
@Override
public String toString() {
return getHelpSetURL().toString();
}
//==================================================================================================
// Inner Classes
//==================================================================================================

View File

@ -0,0 +1,154 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import generic.jar.ResourceFile;
import ghidra.framework.ApplicationProperties;
import ghidra.framework.GModule;
import ghidra.util.SystemUtilities;
import util.CollectionUtils;
import utility.application.ApplicationLayout;
import utility.application.ApplicationUtilities;
import utility.module.ClasspathFilter;
import utility.module.ModuleUtilities;
//
// TODO this class should be deleted when the GP-1981 branch is merged into master. The
// DockingApplicationLayout is not accessible by help, due to Docking depending on Help.
// Much of the application layout code should live in Utility so that it is reachable by more
// modules. Docking and Ghidra application layout classes should also have their names
// changed.
//
// Perhaps: ModuleAppliactionLayout and ClasspathApplicationLayout.
//
public class HelpApplicationLayout extends ApplicationLayout {
private static final String NO_RELEASE_NAME = "NO_RELEASE";
/** Dev mode main source bin dir pattern */
private static final Pattern CLASS_PATH_MODULE_NAME_PATTERN =
Pattern.compile(".*/(\\w+)/bin/main");
/**
* Constructs a new docking application layout object with the given name and version.
*
* @param name The name of the application.
* @param version The version of the application.
* @throws FileNotFoundException if there was a problem getting a user directory.
*/
public HelpApplicationLayout(String name, String version) throws FileNotFoundException {
this.applicationProperties =
Objects.requireNonNull(new ApplicationProperties(name, version, NO_RELEASE_NAME));
this.applicationRootDirs = getDefaultApplicationRootDirs();
applicationRootDirs.addAll(getAdditionalApplicationRootDirs(applicationRootDirs));
// Application installation directory
applicationInstallationDir = applicationRootDirs.iterator().next().getParentFile();
if (SystemUtilities.isInDevelopmentMode()) {
applicationInstallationDir = applicationInstallationDir.getParentFile();
}
// Modules
if (SystemUtilities.isInDevelopmentMode()) {
// In development mode we rely on the IDE's classpath to determine which modules to
// include, as opposed to scanning the filesystem. This prevents unrelated modules
// from being used.
modules = ModuleUtilities.findModules(applicationRootDirs,
ModuleUtilities.findModuleRootDirectories(applicationRootDirs),
new ClasspathFilter());
}
else {
modules = ModuleUtilities.findModules(applicationRootDirs, applicationRootDirs);
}
// User directories
userTempDir = ApplicationUtilities.getDefaultUserTempDir(applicationProperties);
userSettingsDir = ApplicationUtilities.getDefaultUserSettingsDir(applicationProperties,
applicationInstallationDir);
}
protected Collection<ResourceFile> getAdditionalApplicationRootDirs(
Collection<ResourceFile> roots) {
return Collections.emptyList();
}
protected Map<String, GModule> findModules() {
if (!SystemUtilities.isInDevelopmentMode()) {
// in release mode we only have one application root, so no need to find all others
return ModuleUtilities.findModules(applicationRootDirs, applicationRootDirs);
}
// In development mode we may have multiple module root directories under which modules may
// be found. Search all roots for modules.
Collection<ResourceFile> roots =
ModuleUtilities.findModuleRootDirectories(applicationRootDirs, new ArrayList<>());
Map<String, GModule> allModules = ModuleUtilities.findModules(applicationRootDirs, roots);
// Filter any modules found to ensure that we only include those that are listed on the
// classpath. (Due to the nature of how the development classpath is created, not all
// found modules may match the classpath entries.)
Set<String> cpNames = getClassPathModuleNames();
Map<String, GModule> filteredModules = new HashMap<>();
Set<Entry<String, GModule>> entrySet = allModules.entrySet();
for (Entry<String, GModule> entry : entrySet) {
GModule module = entry.getValue();
if (cpNames.contains(module.getName())) {
filteredModules.put(entry.getKey(), module);
}
}
return filteredModules;
}
private Set<String> getClassPathModuleNames() {
String cp = System.getProperty("java.class.path");
String[] pathParts = cp.split(File.pathSeparator);
Set<String> paths = new HashSet<>(Arrays.asList(pathParts));
Set<String> cpNames = new HashSet<>();
for (String cpEntry : paths) {
Matcher matcher = CLASS_PATH_MODULE_NAME_PATTERN.matcher(cpEntry);
if (matcher.matches()) {
cpNames.add(matcher.group(1));
}
}
return cpNames;
}
/**
* Get the default list of Application directories. In repo-based
* development mode this includes the root Ghidra directory within each repo.
* When not in development mode, the requirement is that the current working
* directory correspond to the installation root. The first entry will be
* the primary root in both cases.
* @return root directories
*/
public static Collection<ResourceFile> getDefaultApplicationRootDirs() {
if (SystemUtilities.isInDevelopmentMode()) {
return ApplicationUtilities.findDefaultApplicationRootDirs();
}
return CollectionUtils.asList(new ResourceFile(System.getProperty("user.dir")));
}
}

View File

@ -24,6 +24,8 @@ import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import generic.theme.GIcon;
import generic.theme.Gui;
import help.validator.location.*;
import resources.IconProvider;
import resources.Icons;
@ -73,9 +75,12 @@ public class HelpBuildUtils {
}
/**
* Returns a file object that is the help topic directory for the given file.
* This method is useful for finding the help topic directory when the given
* file doesn't live directly under a help topic.
* Returns a file object that is the help topic directory for the given file.
*
* <p>This method is useful for finding the help topic directory when the given file doesn't
* live directly under a help topic.
* @param file the file for which to find a topic
* @return the path to the help topic directory
*/
public static Path getHelpTopicDir(Path file) {
Path helpTopics = file.getFileSystem().getPath("help", "topics");
@ -540,7 +545,7 @@ public class HelpBuildUtils {
* @param sourceFile the source file path of the image reference
* @param ref the reference text
* @return an absolute path; null if the URI is remote
* @throws URISyntaxException
* @throws URISyntaxException if there is an exception creating a URL/URI for the image location
*/
public static ImageLocation locateImageReference(Path sourceFile, String ref)
throws URISyntaxException {
@ -563,6 +568,13 @@ public class HelpBuildUtils {
}
return ImageLocation.createRuntimeLocation(sourceFile, ref, resolved, path);
}
if (Gui.hasIcon(ref)) {
GIcon gIcon = new GIcon(ref);
URL url = gIcon.getUrl();
URI resolved = url.toURI();
Path path = toPath(resolved);
return ImageLocation.createRuntimeLocation(sourceFile, ref, resolved, path);
}
URI resolved = resolve(sourceFile, ref);
if (isRemote(resolved)) {
@ -574,13 +586,14 @@ public class HelpBuildUtils {
}
/**
* Turn an HTML HREF reference into an absolute path. This will
* locate files based upon relative references, specialized help system references (i.e.,
* help/topics/...), and absolute URLs.
* Turn an HTML HREF reference into an absolute path. This will locate files based upon
* relative references, specialized help system references (i.e., help/topics/...), and
* absolute URLs.
*
* @param sourceFile the reference's source file
* @param ref the reference text
* @return an absolute path; null if the URI is remote
* @throws URISyntaxException
* @throws URISyntaxException if there is an exception creating a URL/URI for the image location
*/
public static Path locateReference(Path sourceFile, String ref) throws URISyntaxException {

Some files were not shown because too many files have changed in this diff Show More