diff --git a/Ghidra/Debug/Debugger/certification.manifest b/Ghidra/Debug/Debugger/certification.manifest index 223beae5a3..71dd99cbf3 100644 --- a/Ghidra/Debug/Debugger/certification.manifest +++ b/Ghidra/Debug/Debugger/certification.manifest @@ -6,6 +6,7 @@ ##MODULE IP: Tango Icons - Public Domain Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/debugger.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||||END| src/main/help/help/shared/close16.gif||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger/data/debugger.theme.properties b/Ghidra/Debug/Debugger/data/debugger.theme.properties new file mode 100644 index 0000000000..63729a015e --- /dev/null +++ b/Ghidra/Debug/Debugger/data/debugger.theme.properties @@ -0,0 +1,199 @@ +[Defaults] + +color.bg.debugger.diff.marker = moccasin + +color.bg.debugger.listing.blended = color.bg +color.bg.debugger.memory.state = color.bg + +color.debugger.plugin.plugin.memview.arrow = red +color.debugger.plugin.memview.box = blue +color.debugger.plugin.memview.box.type.instructions = rgb(128, 000, 000) +color.debugger.plugin.memview.box.type.process = rgb(200, 200, 255) +color.debugger.plugin.memview.box.type.thread = rgb(200, 255, 255) +color.debugger.plugin.memview.box.type.module = lime +color.debugger.plugin.memview.box.type.region = yellow +color.debugger.plugin.memview.box.type.image = magenta +color.debugger.plugin.memview.box.type.virtual.alloc = lightgray +color.debugger.plugin.memview.box.type.heap.create = blue +color.debugger.plugin.memview.box.type.heap.alloc = rgb(000, 100, 050) +color.debugger.plugin.memview.box.type.pool = rgb(100, 000, 150) +color.debugger.plugin.memview.box.type.stack = cyan +color.debugger.plugin.memview.box.type.perfinfo = lightgray +color.debugger.plugin.memview.box.type.read.memory = darkgray +color.debugger.plugin.memview.box.type.write.memory = blue +color.debugger.plugin.memview.box.type.breakpoint = red + + +color.bg.debugger.plugin.objects.default = color.bg +color.fg.debugger.plugin.objects.default = color.fg +color.fg.debugger.plugin.objects.invisible = lightgray +color.fg.debugger.plugin.objects.invalidated = lightgray +color.fg.debugger.plugin.objects.modified = red +color.fg.debugger.plugin.objects.subscribed = black +color.fg.debugger.plugin.objects.error = color.fg.error +color.fg.debugger.plugin.objects.intrinsic = blue +color.fg.debugger.plugin.objects.target = magenta +color.fg.debugger.plugin.objects.accessor = lightgray +color.fg.debugger.plugin.objects.link = green + +color.bg.debugger.plugin.resources.stale = lightgray +color.bg.debugger.plugin.resources.error = lightpink + +color.debugger.plugin.resources.register.marker = lightcoral +color.debugger.plugin.resources.register.stale = gray +color.debugger.plugin.resources.register.stale.selected = lightgray +color.debugger.plugin.resources.register.changed = red +color.debugger.plugin.resources.register.changed.selected = lightcoral + +color.debugger.plugin.resources.watch.stale = gray +color.debugger.plugin.resources.watch.stale.selected = lightgray +color.debugger.plugin.resources.watch.changed = red +color.debugger.plugin.resources.watch.changed.selected = lightcoral + +color.debugger.plugin.resources.value.changed = red +color.debugger.plugin.resources.value.changed.selected = lightcoral + +color.debugger.plugin.resources.pcode.counter = lightgreen + +color.debugger.plugin.resources.breakpoint.marker.enabled = lightsteelblue +color.debugger.plugin.resources.breakpoint.marker.disabled = color.debugger.plugin.resources.breakpoint.marker.enabled +color.debugger.plugin.resources.breakpoint.marker.enabled.ineffective = silver +color.debugger.plugin.resources.breakpoint.marker.disabled.ineffective = color.debugger.plugin.resources.breakpoint.marker.enabled.ineffective + +icon.debugger.object.populated = object-populated.png +icon.debugger.object.unpopulated = object-unpopulated.png + +font.debugger.object.tree.renderer = Tahoma-plain-11 + +icon.debugger.display.graph = breakpoint-enable.png // TODO this icon was missing 'breakpoints.png' +icon.debugger.display.graph.filtered = icon.debugger.display.graph +icon.debugger.display.xml = text-xml.png +icon.debugger.display.xml.filtered = icon.debugger.display.xml +icon.debugger.display.export.facts = closedFolder.png +icon.debugger.display.export.xml = text-xml.png +icon.debugger.display.import.facts = closedFolder.png +icon.debugger.display.import.xml = text-xml.png +icon.debugger.open.windbg.trace = text-xml.png + +icon.debugger.node.object.empty = icon.debugger.object.unpopulated +icon.debugger.node.object.event = register-marker.png +icon.debugger.node.object.populated = icon.debugger.object.populated +icon.debugger.node.object.running = object-running.png +icon.debugger.node.object.terminated = object-terminated.png + +icon.debugger.table.object = icon.table +icon.debugger.tree.object = icon.debugger.object.unpopulated + +icon.debugger = debugger.png +icon.debugger.connect = connect.png +icon.debugger.disconnect = disconnect.png +icon.debugger.process = process.png +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 = resume.png +icon.debugger.interrupt = interrupt.png +icon.debugger.kill = kill.png +icon.debugger.detach = detach.png +icon.debugger.record = record.png +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 = seek-present.png + +icon.debugger.breakpoint.set = breakpoint-enable.png +icon.debugger.breakpoint.clear = breakpoint-clear.png +icon.debugger.breakpoint.enable = breakpoint-enable.png +icon.debugger.breakpoint.enable.all = breakpoints-enable-all.png +icon.debugger.breakpoint.disable = breakpoint-disable.png +icon.debugger.breakpoint.disable.all = breakpoints-disable-all.png +icon.debugger.breakpoint.clear.all = breakpoints-clear-all.png +icon.debugger.breakpoint.make.effective = breakpoints-make-effective.png + +icon.debugger.provider.listing = Browser.gif +icon.debugger.provider.memory.bytes = binaryData.gif +icon.debugger.provider.console = console.png +icon.debugger.provider.registers = registers.png +icon.debugger.provider.stack = stack.png +icon.debugger.provider.breakpoints = breakpoint-mixed.png +icon.debugger.provider.modules = modules.png +icon.debugger.provider.pcode = stepinto.png +icon.debugger.provider.regions = memory16.gif +icon.debugger.provider.time = time.png +icon.debugger.provider.objects = icon.debugger.object.populated +icon.debugger.provider.model = function_graph.png + +icon.debugger.save = icon.save +icon.debugger.close = x.gif +icon.debugger.add = add.png +icon.debugger.delete = delete.png +icon.debugger.clear = erase16.png +icon.debugger.refresh = view-refresh.png +icon.debugger.filter = filter_off.png +icon.debugger.select.rows = table_go.png +icon.debugger.autoread = autoread.png + + +icon.debugger.refresh.memory = icon.debugger.refresh +icon.debugger.rename.snapshot = icon.debugger.provider.time +icon.debugger.map.identically = doubleArrow.png +icon.debugger.map.modules = modules.png +icon.debugger.map.sections = icon.debugger.map.modules +icon.debugger.map.regions = icon.debugger.map.modules +icon.debugger.block = icon.debugger.map.sections +icon.debugger.select.addresses = text_align_justify.png +icon.debugger.data.types = dataTypes.png +icon.debugger.capture.symbols = closedFolderLabels.png +icon.debugger.log.fatal = edit-bomb.png +icon.debugger.log.error = dialog-warning_red.png +icon.debugger.log.warn = dialog-warning.png +icon.debugger.sync = sync_enabled.png +icon.debugger.visibility = format-text-bold.png +icon.debugger.pin = pin.png +icon.debugger.import = imported_bookmark.gif +icon.debugger.blank = blank.png +icon.debugger.package = debugger32.png +icon.debugger.emulate = icon.debugger.process +icon.debugger.config = conf.png +icon.debugger.toggle = system-switch-user.png + +icon.debugger.diff = table_relationship.png +icon.debugger.diff.previous = up.png +icon.debugger.diff.next = down.png + +icon.debugger.edit.mode.read.only = write-disabled.png +icon.debugger.edit.mode.write.target = write-target.png +icon.debugger.edit.mode.write.trace = write-trace.png +icon.debugger.edit.mode.write.emulator = write-emulator.png + +icon.debugger.marker.register = register-marker.png +icon.debugger.marker.event = icon.debugger.marker.register + +icon.debugger.breakpoint.overlay.inconsistent = breakpoint-overlay-inconsistent.png +icon.debugger.breakpoint.marker.enabled = icon.debugger.breakpoint.enable +icon.debugger.breakpoint.marker.disabled = icon.debugger.breakpoint.disable +icon.debugger.breakpoint.marker.mixed = breakpoint-mixed.png +icon.debugger.breakpoint.marker.ineffective.enabled = breakpoint-enable-ineff.png +icon.debugger.breakpoint.marker.ineffective.disabled = breakpoint-disable-ineff.png +icon.debugger.breakpoint.marker.ineffective.mixed = breakpoint-mixed-ineff.png + +icon.debugger.unique.ref.read = cursor_arrow.gif [rotate(180)] +icon.debugger.unique.ref.write = cursor_arrow.gif + +icon.debugger.select.registers = select-registers.png +icon.debugger.enable.edits = editbytes.gif +icon.debugger.disassemble = editbytes.gif // TODO this icon was missing 'disassemble.png' + + + +[Dark Defaults] + + + + diff --git a/Ghidra/Debug/Debugger/src/main/help/help/shared/Frontpage.css b/Ghidra/Debug/Debugger/src/main/help/help/shared/Frontpage.css index c8616e85e8..ff855bae04 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Debug/Debugger/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java index 3db1d4c8ed..bbd5f24881 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java @@ -30,6 +30,8 @@ import docking.action.ToggleDockingAction; import docking.action.builder.*; import docking.widgets.table.*; import docking.widgets.tree.GTreeNode; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.gui.breakpoint.DebuggerBreakpointsPlugin; import ghidra.app.plugin.core.debug.gui.console.DebuggerConsolePlugin; @@ -54,131 +56,129 @@ import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.util.PluginUtils; import ghidra.program.database.ProgramContentHandler; import ghidra.trace.model.Trace; -import ghidra.util.*; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.RotateIcon; public interface DebuggerResources { String OPTIONS_CATEGORY_DEBUGGER = "Debugger"; String OPTIONS_CATEGORY_WORKFLOW = "Workflow"; - ImageIcon ICON_DEBUGGER = ResourceManager.loadImage("images/debugger.png"); + Icon ICON_DEBUGGER = new GIcon("icon.debugger"); - ImageIcon ICON_CONNECTION = ResourceManager.loadImage("images/connect.png"); - ImageIcon ICON_DISCONNECT = ResourceManager.loadImage("images/disconnect.png"); + Icon ICON_CONNECTION = new GIcon("icon.debugger.connect"); + Icon ICON_DISCONNECT = new GIcon("icon.debugger.disconnect"); - ImageIcon ICON_PROCESS = ResourceManager.loadImage("images/process.png"); - ImageIcon ICON_TRACE = Trace.TRACE_ICON; - ImageIcon ICON_THREAD = ResourceManager.loadImage("images/thread.png"); - ImageIcon ICON_PROGRAM = ProgramContentHandler.PROGRAM_ICON; - ImageIcon ICON_PROCESSOR = ResourceManager.loadImage("images/kcmprocessor.png"); + Icon ICON_PROCESS = new GIcon("icon.debugger.process"); + Icon ICON_TRACE = Trace.TRACE_ICON; + Icon ICON_THREAD = new GIcon("icon.debugger.thread"); + Icon ICON_PROGRAM = ProgramContentHandler.PROGRAM_ICON; + Icon ICON_PROCESSOR = new GIcon("icon.debugger.processor"); - ImageIcon ICON_LAUNCH = ResourceManager.loadImage("images/launch.png"); - ImageIcon ICON_ATTACH = ResourceManager.loadImage("images/attach.png"); - ImageIcon ICON_RESUME = ResourceManager.loadImage("images/resume.png"); - ImageIcon ICON_INTERRUPT = ResourceManager.loadImage("images/interrupt.png"); - ImageIcon ICON_KILL = ResourceManager.loadImage("images/kill.png"); - ImageIcon ICON_DETACH = ResourceManager.loadImage("images/detach.png"); - ImageIcon ICON_RECORD = ResourceManager.loadImage("images/record.png"); + 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_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"); - ImageIcon ICON_STEP_INTO = ResourceManager.loadImage("images/stepinto.png"); - ImageIcon ICON_STEP_OVER = ResourceManager.loadImage("images/stepover.png"); - ImageIcon ICON_SKIP_OVER = ResourceManager.loadImage("images/skipover.png"); - ImageIcon ICON_STEP_FINISH = ResourceManager.loadImage("images/stepout.png"); - ImageIcon ICON_STEP_BACK = ResourceManager.loadImage("images/stepback.png"); - ImageIcon ICON_STEP_LAST = ResourceManager.loadImage("images/steplast.png"); - // TODO: Draw new icons? - ImageIcon ICON_SNAP_FORWARD = ResourceManager.loadImage("images/2rightarrow.png"); - ImageIcon ICON_SNAP_BACKWARD = ResourceManager.loadImage("images/2leftarrow.png"); - ImageIcon ICON_SEEK_PRESENT = ResourceManager.loadImage("images/seek-present.png"); + 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"); - ImageIcon ICON_SET_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-enable.png"); - ImageIcon ICON_CLEAR_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-clear.png"); - ImageIcon ICON_ENABLE_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-enable.png"); - ImageIcon ICON_ENABLE_ALL_BREAKPOINTS = - ResourceManager.loadImage("images/breakpoints-enable-all.png"); - ImageIcon ICON_DISABLE_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-disable.png"); - ImageIcon ICON_DISABLE_ALL_BREAKPOINTS = - ResourceManager.loadImage("images/breakpoints-disable-all.png"); - ImageIcon ICON_CLEAR_ALL_BREAKPOINTS = - ResourceManager.loadImage("images/breakpoints-clear-all.png"); - ImageIcon ICON_MAKE_BREAKPOINTS_EFFECTIVE = - ResourceManager.loadImage("images/breakpoints-make-effective.png"); + Icon ICON_SNAP_FORWARD = new GIcon("icon.debugger.snap.forward"); + Icon ICON_SNAP_BACKWARD = new GIcon("icon.debugger.snap.backward"); + Icon ICON_SEEK_PRESENT = new GIcon("icon.debugger.seek.present"); + + Icon ICON_SET_BREAKPOINT = new GIcon("icon.debugger.breakpoint.set"); + Icon ICON_CLEAR_BREAKPOINT = new GIcon("icon.debugger.breakpoint.clear"); + Icon ICON_ENABLE_BREAKPOINT = new GIcon("icon.debugger.breakpoint.enable"); + Icon ICON_ENABLE_ALL_BREAKPOINTS = + new GIcon("icon.debugger.breakpoint.enable.all"); + Icon ICON_DISABLE_BREAKPOINT = new GIcon("icon.debugger.breakpoint.disable"); + Icon ICON_DISABLE_ALL_BREAKPOINTS = + new GIcon("icon.debugger.breakpoint.disable.all"); + Icon ICON_CLEAR_ALL_BREAKPOINTS = + new GIcon("icon.debugger.breakpoint.clear.all"); + Icon ICON_MAKE_BREAKPOINTS_EFFECTIVE = + new GIcon("icon.debugger.breakpoint.make.effective"); // TODO: Some overlay to indicate dynamic, or new icon altogether - ImageIcon ICON_LISTING = ResourceManager.loadImage("images/Browser.gif"); - ImageIcon ICON_MEMORY_BYTES = ResourceManager.loadImage("images/binaryData.gif"); - ImageIcon ICON_CONSOLE = ResourceManager.loadImage("images/console.png"); - ImageIcon ICON_REGISTERS = ResourceManager.loadImage("images/registers.png"); - ImageIcon ICON_STACK = ResourceManager.loadImage("images/stack.png"); - ImageIcon ICON_BREAKPOINTS = ResourceManager.loadImage("images/breakpoint-mixed.png"); - ImageIcon ICON_MODULES = ResourceManager.loadImage("images/modules.png"); - ImageIcon ICON_MAPPINGS = ICON_PROGRAM; // TODO: A better icon - ImageIcon ICON_PCODE = ResourceManager.loadImage("images/stepinto.png"); // TODO - //ResourceManager.loadImage("images/mappings.png"); - ImageIcon ICON_REGIONS = ResourceManager.loadImage("images/memory16.gif"); - ImageIcon ICON_TIME = ResourceManager.loadImage("images/time.png"); + Icon ICON_LISTING = new GIcon("icon.debugger.provider.listing"); + Icon ICON_MEMORY_BYTES = new GIcon("icon.debugger.provider.memory.bytes"); + Icon ICON_CONSOLE = new GIcon("icon.debugger.provider.console"); + Icon ICON_REGISTERS = new GIcon("icon.debugger.provider.registers"); + Icon ICON_STACK = new GIcon("icon.debugger.provider.stack"); + Icon ICON_BREAKPOINTS = new GIcon("icon.debugger.provider.breakpoints"); + Icon ICON_MODULES = new GIcon("icon.debugger.provider.modules"); + Icon ICON_MAPPINGS = ICON_PROGRAM; // TODO: A better icon + Icon ICON_PCODE = new GIcon("icon.debugger.provider.pcode"); // TODO + Icon ICON_REGIONS = new GIcon("icon.debugger.provider.regions"); + Icon ICON_TIME = new GIcon("icon.debugger.provider.time"); // TODO: Draw a real icon. object-populated duplicates breakpoint-enabled - ImageIcon ICON_OBJECTS = ResourceManager.loadImage("images/object-populated.png"); + Icon ICON_OBJECTS = new GIcon("icon.debugger.provider.objects"); - ImageIcon ICON_SAVE = ResourceManager.loadImage("images/disk.png"); - ImageIcon ICON_CLOSE = ResourceManager.loadImage("images/x.gif"); - ImageIcon ICON_ADD = ResourceManager.loadImage("images/add.png"); - ImageIcon ICON_DELETE = ResourceManager.loadImage("images/delete.png"); - ImageIcon ICON_CLEAR = ResourceManager.loadImage("images/erase16.png"); - ImageIcon ICON_REFRESH = ResourceManager.loadImage("images/view-refresh.png"); - ImageIcon ICON_FILTER = ResourceManager.loadImage("images/filter_off.png"); // Eww. - ImageIcon ICON_SELECT_ROWS = ResourceManager.loadImage("images/table_go.png"); - ImageIcon ICON_AUTOREAD = ResourceManager.loadImage("images/autoread.png"); + Icon ICON_SAVE = new GIcon("icon.debugger.save"); + Icon ICON_CLOSE = new GIcon("icon.debugger.close"); + Icon ICON_ADD = new GIcon("icon.debugger.add"); + Icon ICON_DELETE = new GIcon("icon.debugger.delete"); + Icon ICON_CLEAR = new GIcon("icon.debugger.clear"); + Icon ICON_REFRESH = new GIcon("icon.debugger.refresh"); + Icon ICON_FILTER = new GIcon("icon.debugger.filter"); // Eww. + Icon ICON_SELECT_ROWS = new GIcon("icon.debugger.select.rows"); + Icon ICON_AUTOREAD = new GIcon("icon.debugger.autoread"); - ImageIcon ICON_OBJECT_POPULATED = ResourceManager.loadImage("images/object-populated.png"); - ImageIcon ICON_OBJECT_UNPOPULATED = ResourceManager.loadImage("images/object-unpopulated.png"); + Icon ICON_OBJECT_POPULATED = new GIcon("icon.debugger.object.populated"); + Icon ICON_OBJECT_UNPOPULATED = new GIcon("icon.debugger.object.unpopulated"); // TODO: Draw a real icon. - ImageIcon ICON_REFRESH_MEMORY = ICON_REFRESH; + Icon ICON_REFRESH_MEMORY = new GIcon("icon.debugger.refresh.memory"); - ImageIcon ICON_RENAME_SNAPSHOT = ICON_TIME; + Icon ICON_RENAME_SNAPSHOT = new GIcon("icon.debugger.rename.snapshot"); // TODO: Draw an icon - ImageIcon ICON_MAP_IDENTICALLY = ResourceManager.loadImage("images/doubleArrow.png"); - ImageIcon ICON_MAP_MODULES = ResourceManager.loadImage("images/modules.png"); - ImageIcon ICON_MAP_SECTIONS = ICON_MAP_MODULES; // TODO - ImageIcon ICON_MAP_REGIONS = ICON_MAP_MODULES; // TODO - ImageIcon ICON_BLOCK = ICON_MAP_SECTIONS; // TODO + Icon ICON_MAP_IDENTICALLY = new GIcon("icon.debugger.map.identically"); + Icon ICON_MAP_MODULES = new GIcon("icon.debugger.map.modules"); + Icon ICON_MAP_SECTIONS = new GIcon("icon.debugger.map.sections"); // TODO + Icon ICON_MAP_REGIONS = new GIcon("icon.debugger.map.regions"); // TODO + Icon ICON_BLOCK = new GIcon("icon.debugger.block"); // TODO // TODO: Draw an icon - ImageIcon ICON_SELECT_ADDRESSES = ResourceManager.loadImage("images/text_align_justify.png"); + Icon ICON_SELECT_ADDRESSES = new GIcon("icon.debugger.select.addresses"); // TODO: Draw an icon? - ImageIcon ICON_DATA_TYPES = ResourceManager.loadImage("images/dataTypes.png"); + Icon ICON_DATA_TYPES = new GIcon("icon.debugger.data.types"); // TODO: Draw an icon? - ImageIcon ICON_CAPTURE_SYMBOLS = ResourceManager.loadImage("images/closedFolderLabels.png"); + Icon ICON_CAPTURE_SYMBOLS = new GIcon("icon.debugger.capture.symbols"); - ImageIcon ICON_LOG_FATAL = ResourceManager.loadImage("images/edit-bomb.png"); - ImageIcon ICON_LOG_ERROR = ResourceManager.loadImage("images/dialog-warning_red.png"); - ImageIcon ICON_LOG_WARN = ResourceManager.loadImage("images/dialog-warning.png"); + Icon ICON_LOG_FATAL = new GIcon("icon.debugger.log.fatal"); + Icon ICON_LOG_ERROR = new GIcon("icon.debugger.log.error"); + Icon ICON_LOG_WARN = new GIcon("icon.debugger.log.warn"); - ImageIcon ICON_SYNC = ResourceManager.loadImage("images/sync_enabled.png"); - ImageIcon ICON_VISIBILITY = ResourceManager.loadImage("images/format-text-bold.png"); + Icon ICON_SYNC = new GIcon("icon.debugger.sync"); + Icon ICON_VISIBILITY = new GIcon("icon.debugger.visibility"); - ImageIcon ICON_PIN = ResourceManager.loadImage("images/pin.png"); + Icon ICON_PIN = new GIcon("icon.debugger.pin"); // TODO: Find better icon? - ImageIcon ICON_IMPORT = ResourceManager.loadImage("images/imported_bookmark.gif"); - ImageIcon ICON_BLANK = ResourceManager.loadImage("images/blank.png"); - ImageIcon ICON_PACKAGE = ResourceManager.loadImage("images/debugger32.png"); - ImageIcon ICON_EMULATE = ICON_PROCESS; // TODO - ImageIcon ICON_CONFIG = ResourceManager.loadImage("images/conf.png"); - ImageIcon ICON_TOGGLE = ResourceManager.loadImage("images/system-switch-user.png"); + Icon ICON_IMPORT = new GIcon("icon.debugger.import"); + Icon ICON_BLANK = new GIcon("icon.debugger.blank"); + Icon ICON_PACKAGE = new GIcon("icon.debugger.package"); + Icon ICON_EMULATE = new GIcon("icon.debugger.emulate"); // TODO + Icon ICON_CONFIG = new GIcon("icon.debugger.config"); + Icon ICON_TOGGLE = new GIcon("icon.debugger.toggle"); - ImageIcon ICON_DIFF = ResourceManager.loadImage("images/table_relationship.png"); - ImageIcon ICON_DIFF_PREV = ResourceManager.loadImage("images/up.png"); - ImageIcon ICON_DIFF_NEXT = ResourceManager.loadImage("images/down.png"); + Icon ICON_DIFF = new GIcon("icon.debugger.diff"); + Icon ICON_DIFF_PREV = new GIcon("icon.debugger.diff.previous"); + Icon ICON_DIFF_NEXT = new GIcon("icon.debugger.diff.next"); - ImageIcon ICON_EDIT_MODE_READ_ONLY = ResourceManager.loadImage("images/write-disabled.png"); - ImageIcon ICON_EDIT_MODE_WRITE_TARGET = ResourceManager.loadImage("images/write-target.png"); - ImageIcon ICON_EDIT_MODE_WRITE_TRACE = ResourceManager.loadImage("images/write-trace.png"); - ImageIcon ICON_EDIT_MODE_WRITE_EMULATOR = - ResourceManager.loadImage("images/write-emulator.png"); + Icon ICON_EDIT_MODE_READ_ONLY = new GIcon("icon.debugger.edit.mode.read.only"); + Icon ICON_EDIT_MODE_WRITE_TARGET = new GIcon("icon.debugger.edit.mode.write.target"); + Icon ICON_EDIT_MODE_WRITE_TRACE = new GIcon("icon.debugger.edit.mode.write.trace"); + Icon ICON_EDIT_MODE_WRITE_EMULATOR = + new GIcon("icon.debugger.edit.mode.write.emulator"); String NAME_EDIT_MODE_READ_ONLY = "Control Target w/ Edits Disabled"; String NAME_EDIT_MODE_WRITE_TARGET = "Control Target"; @@ -190,82 +190,82 @@ public interface DebuggerResources { String HELP_ANCHOR_PLUGIN = "plugin"; String TITLE_PROVIDER_BREAKPOINTS = "Breakpoints"; - ImageIcon ICON_PROVIDER_BREAKPOINTS = ICON_BREAKPOINTS; + Icon ICON_PROVIDER_BREAKPOINTS = ICON_BREAKPOINTS; HelpLocation HELP_PROVIDER_BREAKPOINTS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerBreakpointsPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_CONSOLE = "Debug Console"; - ImageIcon ICON_PROVIDER_CONSOLE = ICON_CONSOLE; + Icon ICON_PROVIDER_CONSOLE = ICON_CONSOLE; HelpLocation HELP_PROVIDER_CONSOLE = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerConsolePlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_LISTING = "Dynamic"; - ImageIcon ICON_PROVIDER_LISTING = ICON_LISTING; + Icon ICON_PROVIDER_LISTING = ICON_LISTING; HelpLocation HELP_PROVIDER_LISTING = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerListingPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_MAPPINGS = "Static Mappings"; - ImageIcon ICON_PROVIDER_MAPPINGS = ICON_MAPPINGS; + Icon ICON_PROVIDER_MAPPINGS = ICON_MAPPINGS; HelpLocation HELP_PROVIDER_MAPPINGS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerStaticMappingPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_MEMORY_BYTES = "Memory"; - ImageIcon ICON_PROVIDER_MEMORY_BYTES = ICON_MEMORY_BYTES; + Icon ICON_PROVIDER_MEMORY_BYTES = ICON_MEMORY_BYTES; HelpLocation HELP_PROVIDER_MEMORY_BYTES = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerMemoryBytesPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_MODULES = "Modules"; - ImageIcon ICON_PROVIDER_MODULES = ICON_MODULES; + Icon ICON_PROVIDER_MODULES = ICON_MODULES; HelpLocation HELP_PROVIDER_MODULES = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerModulesPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_PCODE = "Pcode Stepper"; - ImageIcon ICON_PROVIDER_PCODE = ICON_PCODE; + Icon ICON_PROVIDER_PCODE = ICON_PCODE; HelpLocation HELP_PROVIDER_PCODE = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerPcodeStepperPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_REGIONS = "Regions"; - ImageIcon ICON_PROVIDER_REGIONS = ICON_REGIONS; + Icon ICON_PROVIDER_REGIONS = ICON_REGIONS; HelpLocation HELP_PROVIDER_REGIONS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerRegionsPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_REGISTERS = "Registers"; - ImageIcon ICON_PROVIDER_REGISTERS = ICON_REGISTERS; + Icon ICON_PROVIDER_REGISTERS = ICON_REGISTERS; HelpLocation HELP_PROVIDER_REGISTERS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerRegistersPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_TARGETS = "Debugger Targets"; - ImageIcon ICON_PROVIDER_TARGETS = ICON_CONNECTION; // TODO: Same icon as action + Icon ICON_PROVIDER_TARGETS = ICON_CONNECTION; // TODO: Same icon as action HelpLocation HELP_PROVIDER_TARGETS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerTargetsPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_STACK = "Stack"; - ImageIcon ICON_PROVIDER_STACK = ICON_STACK; + Icon ICON_PROVIDER_STACK = ICON_STACK; HelpLocation HELP_PROVIDER_STACK = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerStackPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_THREADS = "Threads"; - ImageIcon ICON_PROVIDER_THREADS = ICON_DEBUGGER; + Icon ICON_PROVIDER_THREADS = ICON_DEBUGGER; HelpLocation HELP_PROVIDER_THREADS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerThreadsPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_TIME = "Time"; - ImageIcon ICON_PROVIDER_TIME = ICON_TIME; + Icon ICON_PROVIDER_TIME = ICON_TIME; HelpLocation HELP_PROVIDER_TIME = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerTimePlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_OBJECTS = "Objects"; - ImageIcon ICON_PROVIDER_OBJECTS = ResourceManager.loadImage("images/time.png"); + Icon ICON_PROVIDER_OBJECTS = new GIcon("icon.debugger.provider.objects"); HelpLocation HELP_PROVIDER_OBJECTS = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerObjectsPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_MODEL = "Model"; // TODO: An icon - ImageIcon ICON_PROVIDER_MODEL = ResourceManager.loadImage("images/function_graph.png"); + Icon ICON_PROVIDER_MODEL = new GIcon("icon.debugger.provider.model"); HelpLocation HELP_PROVIDER_MODEL = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerModelPlugin.class), HELP_ANCHOR_PLUGIN); String TITLE_PROVIDER_WATCHES = "Watches"; - ImageIcon ICON_PROVIDER_WATCHES = ICON_AUTOREAD; // TODO: Another icon? + Icon ICON_PROVIDER_WATCHES = ICON_AUTOREAD; // TODO: Another icon? HelpLocation HELP_PROVIDER_WATCHES = new HelpLocation( PluginUtils.getPluginNameFromClass(DebuggerWatchesPlugin.class), HELP_ANCHOR_PLUGIN); @@ -274,44 +274,51 @@ public interface DebuggerResources { String BOOKMARK_CATEGORY_MEMORY_READ_ERROR = "Debugger Memory Read Error"; String OPTION_NAME_COLORS_STALE_MEMORY = "Colors.Stale Memory"; - Color DEFAULT_COLOR_BACKGROUND_STALE = Color.LIGHT_GRAY; + Color DEFAULT_COLOR_BACKGROUND_STALE = new GColor("color.bg.debugger.plugin.resources.stale"); String OPTION_NAME_COLORS_ERROR_MEMORY = "Colors.Error Memory"; - Color DEFAULT_COLOR_BACKGROUND_ERROR = new Color(1.0f, 0.75f, 0.75f); + Color DEFAULT_COLOR_BACKGROUND_ERROR = new GColor("color.bg.debugger.plugin.resources.error"); int PRIORITY_REGISTER_MARKER = 10; String OPTION_NAME_COLORS_TRACKING_MARKERS = "Colors.Tracking Markers"; - Color DEFAULT_COLOR_REGISTER_MARKERS = new Color(0.75f, 0.875f, 0.75f); - ImageIcon ICON_REGISTER_MARKER = ResourceManager.loadImage("images/register-marker.png"); + Color DEFAULT_COLOR_REGISTER_MARKERS = + new GColor("color.debugger.plugin.resources.register.marker"); + Icon ICON_REGISTER_MARKER = new GIcon("icon.debugger.marker.register"); - ImageIcon ICON_EVENT_MARKER = ICON_REGISTER_MARKER; // TODO: Another icon? + Icon ICON_EVENT_MARKER = new GIcon("icon.debugger.marker.event"); // TODO: Another icon? // At least rename to "marker-arrow", and then have both ref it. + //@formatter:off String OPTION_NAME_COLORS_REGISTER_STALE = "Colors.Stale Registers"; - Color DEFAULT_COLOR_REGISTER_STALE = Color.GRAY; + Color DEFAULT_COLOR_REGISTER_STALE = new GColor("color.debugger.plugin.resources.register.stale"); String OPTION_NAME_COLORS_REGISTER_STALE_SEL = "Colors.Stale Registers (selected)"; - Color DEFAULT_COLOR_REGISTER_STALE_SEL = Color.LIGHT_GRAY; + Color DEFAULT_COLOR_REGISTER_STALE_SEL = new GColor("color.debugger.plugin.resources.register.stale.selected"); String OPTION_NAME_COLORS_REGISTER_CHANGED = "Colors.Changed Registers"; - Color DEFAULT_COLOR_REGISTER_CHANGED = Color.RED; + Color DEFAULT_COLOR_REGISTER_CHANGED = new GColor("color.debugger.plugin.resources.register.changed"); String OPTION_NAME_COLORS_REGISTER_CHANGED_SEL = "Colors.Changed Registers (selected)"; - Color DEFAULT_COLOR_REGISTER_CHANGED_SEL = ColorUtils.blend(Color.RED, Color.WHITE, 0.5f); + Color DEFAULT_COLOR_REGISTER_CHANGED_SEL = new GColor("color.debugger.plugin.resources.register.changed.selected"); + //@formatter:on + //@formatter:off String OPTION_NAME_COLORS_WATCH_STALE = "Colors.Stale Watches"; - Color DEFAULT_COLOR_WATCH_STALE = Color.GRAY; + Color DEFAULT_COLOR_WATCH_STALE = new GColor("color.debugger.plugin.resources.watch.stale"); String OPTION_NAME_COLORS_WATCH_STALE_SEL = "Colors.Stale Watches (selected)"; - Color DEFAULT_COLOR_WATCH_STALE_SEL = Color.LIGHT_GRAY; + Color DEFAULT_COLOR_WATCH_STALE_SEL = new GColor("color.debugger.plugin.resources.watch.stale.selected"); String OPTION_NAME_COLORS_WATCH_CHANGED = "Colors.Changed Watches"; - Color DEFAULT_COLOR_WATCH_CHANGED = Color.RED; + Color DEFAULT_COLOR_WATCH_CHANGED = new GColor("color.debugger.plugin.resources.watch.changed"); String OPTION_NAME_COLORS_WATCH_CHANGED_SEL = "Colors.Changed Watches (selected)"; - Color DEFAULT_COLOR_WATCH_CHANGED_SEL = ColorUtils.blend(Color.RED, Color.WHITE, 0.5f); + Color DEFAULT_COLOR_WATCH_CHANGED_SEL = new GColor("color.debugger.plugin.resources.watch.changed.selected"); + //@formatter:on + //@formatter:off String OPTION_NAME_COLORS_VALUE_CHANGED = "Colors.Changed Values"; - Color DEFAULT_COLOR_VALUE_CHANGED = Color.RED; + Color DEFAULT_COLOR_VALUE_CHANGED = new GColor("color.debugger.plugin.resources.value.changed"); String OPTION_NAME_COLORS_VALUE_CHANGED_SEL = "Colors.Changed Values (selected)"; - Color DEFAULT_COLOR_VALUE_CHANGED_SEL = ColorUtils.blend(Color.RED, Color.WHITE, 0.5f); + Color DEFAULT_COLOR_VALUE_CHANGED_SEL = new GColor("color.debugger.plugin.resources.value.changed.selected"); + //@formatter:on String OPTION_NAME_COLORS_PCODE_COUNTER = "Colors.Pcode Counter"; - Color DEFAULT_COLOR_PCODE_COUNTER = new Color(0.75f, 0.875f, 0.75f); + Color DEFAULT_COLOR_PCODE_COUNTER = new GColor("color.debugger.plugin.resources.pcode.counter"); String NAME_BREAKPOINT_MARKER_ENABLED = "Enabled Breakpoint"; String NAME_BREAKPOINT_MARKER_DISABLED = "Disabled Breakpoint"; @@ -323,19 +330,19 @@ public interface DebuggerResources { String NAME_BREAKPOINT_MARKER_INCON_DIS = "Inconsistent Disabled Breakpoint"; String NAME_BREAKPOINT_MARKER_INCON_MIX = "Inconsistent Mixed Breakpoint"; - ImageIcon ICON_BREAKPOINT_OVERLAY_INCONSISTENT = - ResourceManager.loadImage("images/breakpoint-overlay-inconsistent.png"); - ImageIcon ICON_BREAKPOINT_MARKER_ENABLED = ICON_ENABLE_BREAKPOINT; - ImageIcon ICON_BREAKPOINT_MARKER_DISABLED = ICON_DISABLE_BREAKPOINT; - ImageIcon ICON_BREAKPOINT_MARKER_MIXED = - ResourceManager.loadImage("images/breakpoint-mixed.png"); + Icon ICON_BREAKPOINT_OVERLAY_INCONSISTENT = + new GIcon("icon.debugger.breakpoint.overlay.inconsistent"); + Icon ICON_BREAKPOINT_MARKER_ENABLED = new GIcon("icon.debugger.breakpoint.marker.enabled"); + Icon ICON_BREAKPOINT_MARKER_DISABLED = new GIcon("icon.debugger.breakpoint.marker.disabled"); + Icon ICON_BREAKPOINT_MARKER_MIXED = + new GIcon("icon.debugger.breakpoint.marker.mixed"); - ImageIcon ICON_BREAKPOINT_MARKER_INEFF_EN = - ResourceManager.loadImage("images/breakpoint-enable-ineff.png"); - ImageIcon ICON_BREAKPOINT_MARKER_INEFF_DIS = - ResourceManager.loadImage("images/breakpoint-disable-ineff.png"); - ImageIcon ICON_BREAKPOINT_MARKER_INEFF_MIX = - ResourceManager.loadImage("images/breakpoint-mixed-ineff.png"); + Icon ICON_BREAKPOINT_MARKER_INEFF_EN = + new GIcon("icon.debugger.breakpoint.marker.ineffective.enabled"); + Icon ICON_BREAKPOINT_MARKER_INEFF_DIS = + new GIcon("icon.debugger.breakpoint.marker.ineffective.disabled"); + Icon ICON_BREAKPOINT_MARKER_INEFF_MIX = + new GIcon("icon.debugger.breakpoint.marker.ineffective.disabled"); Icon ICON_BREAKPOINT_MARKER_INCON_EN = new MultiIcon(ICON_BREAKPOINT_MARKER_ENABLED, ICON_BREAKPOINT_OVERLAY_INCONSISTENT); @@ -344,22 +351,20 @@ public interface DebuggerResources { Icon ICON_BREAKPOINT_MARKER_INCON_MIX = new MultiIcon(ICON_BREAKPOINT_MARKER_MIXED, ICON_BREAKPOINT_OVERLAY_INCONSISTENT); - Icon ICON_UNIQUE_REF_READ = - new RotateIcon(ResourceManager.loadImage("images/cursor_arrow.gif"), 180); // TODO - ImageIcon ICON_UNIQUE_REF_WRITE = ResourceManager.loadImage("images/cursor_arrow.gif"); // TODO + Icon ICON_UNIQUE_REF_READ = new GIcon("icon.debugger.unique.ref.read"); // TODO + Icon ICON_UNIQUE_REF_WRITE = new GIcon("icon.debugger.unique.ref.write"); // TODO Icon ICON_UNIQUE_REF_RW = new MultiIcon(ICON_UNIQUE_REF_READ, ICON_UNIQUE_REF_WRITE); // TODO + //@formatter:off String OPTION_NAME_COLORS_ENABLED_BREAKPOINT_MARKERS = "Colors.Enabled Breakpoint Markers"; - Color DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS = new Color(0.75f, 0.75f, 0.875f); + Color DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS = new GColor("color.debugger.plugin.resources.breakpoint.marker.enabled"); String OPTION_NAME_COLORS_DISABLED_BREAKPOINT_MARKERS = "Colors.Disabled Breakpoint Markers"; - Color DEFAULT_COLOR_DISABLED_BREAKPOINT_MARKERS = DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS; - String OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_MARKERS = - "Colors.Ineffective Enabled Breakpoint Markers"; - Color DEFAULT_COLOR_INEFF_EN_BREAKPOINT_MARKERS = new Color(0.75f, 0.75f, 0.75f); - String OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_MARKERS = - "Colors.Ineffective Disabled Breakpoint Markers"; - Color DEFAULT_COLOR_INEFF_DIS_BREAKPOINT_MARKERS = - DEFAULT_COLOR_INEFF_EN_BREAKPOINT_MARKERS; + Color DEFAULT_COLOR_DISABLED_BREAKPOINT_MARKERS = new GColor("color.debugger.plugin.resources.breakpoint.marker.disabled"); + String OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_MARKERS = "Colors.Ineffective Enabled Breakpoint Markers"; + Color DEFAULT_COLOR_INEFF_EN_BREAKPOINT_MARKERS = new GColor("color.debugger.plugin.resources.breakpoint.marker.enabled.ineffective"); + String OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_MARKERS = "Colors.Ineffective Disabled Breakpoint Markers"; + Color DEFAULT_COLOR_INEFF_DIS_BREAKPOINT_MARKERS = new GColor("color.debugger.plugin.resources.breakpoint.marker.disabled.ineffective"); + //@formatter:on String OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND = "Colors.Enabled Breakpoint Markers Have Background"; @@ -1037,7 +1042,7 @@ public interface DebuggerResources { String NAME = "Select Registers"; String DESCRIPTION = "Select registers to display/modify"; String GROUP = "aa"; - Icon ICON = ResourceManager.loadImage("images/select-registers.png"); + Icon ICON = new GIcon("icon.debugger.select.registers"); String HELP_ANCHOR = "select_registers"; static ActionBuilder builder(Plugin owner) { @@ -1053,7 +1058,7 @@ public interface DebuggerResources { String NAME = "Clone Window"; String DESCRIPTION = "Create a disconnected copy of this window"; String GROUP = "zzzz"; - Icon ICON = ResourceManager.loadImage("images/camera-photo.png"); + Icon ICON = new GIcon("icon.provider.clone"); String HELP_ANCHOR = "clone_window"; static ActionBuilder builder(Plugin owner) { @@ -1069,7 +1074,7 @@ public interface DebuggerResources { String NAME = "Enable Edits"; String DESCRIPTION = "Enable editing of recorded or live values"; String GROUP = "yyyy2"; - Icon ICON = ResourceManager.loadImage("images/editbytes.gif"); + Icon ICON = new GIcon("icon.debugger.enable.edits"); String HELP_ANCHOR = "enable_edits"; static ToggleActionBuilder builder(Plugin owner) { @@ -1084,7 +1089,7 @@ public interface DebuggerResources { interface DisassembleAsAction { String NAME = "Disassemble as"; String DESCRIPTION = "Disassemble using an alternative language"; - Icon ICON = ResourceManager.loadImage("images/disassemble.png"); + Icon ICON = new GIcon("icon.debugger.disassemble"); String HELP_ANCHOR = "disassemble_as"; static ActionBuilder builder(Plugin owner) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPlugin.java index 44eca5be13..26659b9a67 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPlugin.java @@ -28,6 +28,7 @@ import javax.swing.event.ChangeListener; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToggleDockingAction; +import generic.theme.GColor; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.core.codebrowser.MarkerServiceBackgroundColorModel; import ghidra.app.plugin.core.debug.*; @@ -57,28 +58,19 @@ import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.time.schedule.TraceSchedule; import ghidra.util.Msg; -@PluginInfo( - shortDescription = "Compare memory state between times in a trace", - description = "Provides a side-by-side diff view between snapshots (points in time) in a " + - "trace. The comparison is limited to raw bytes.", - category = PluginCategoryNames.DEBUGGER, - packageName = DebuggerPluginPackage.NAME, - status = PluginStatus.RELEASED, - eventsConsumed = { +@PluginInfo(shortDescription = "Compare memory state between times in a trace", description = "Provides a side-by-side diff view between snapshots (points in time) in a " + + "trace. The comparison is limited to raw bytes.", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.RELEASED, eventsConsumed = { TraceClosedPluginEvent.class, - }, - eventsProduced = {}, - servicesRequired = { + }, eventsProduced = {}, servicesRequired = { DebuggerListingService.class, - }, - servicesProvided = {}) + }, servicesProvided = {}) public class DebuggerTraceViewDiffPlugin extends AbstractDebuggerPlugin { protected static final String MARKER_NAME = "Trace Diff"; protected static final String MARKER_DESCRIPTION = "Difference between snapshots in this trace"; public static final String DIFF_COLOR_CATEGORY = "Listing Fields"; public static final String DIFF_COLOR_NAME = "Selection Colors.Difference Color"; - public static final Color DEFAULT_DIFF_COLOR = new Color(255, 230, 180); // light orange + public static final Color DEFAULT_DIFF_COLOR = new GColor("color.bg.debugger.diff.marker"); protected class ListingCoordinationListener implements CoordinatedListingPanelListener { @Override diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java index 2c928fe299..eb380fbce7 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/interpreters/AbstractDebuggerWrappedConsoleConnection.java @@ -22,7 +22,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; @@ -152,7 +152,7 @@ public abstract class AbstractDebuggerWrappedConsoleConnection models = new ArrayList<>(); private final ColorBlender blender = new ColorBlender(); @@ -60,7 +63,7 @@ public class MultiBlendedListingBackgroundColorModel implements ListingBackgroun @Override public Color getDefaultBackgroundColor() { if (models.isEmpty()) { - return Color.WHITE; + return BG_COLOR_EMPTY; } return models.get(0).getDefaultBackgroundColor(); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemoryBox.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemoryBox.java index aafea935c9..bc247d669e 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemoryBox.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemoryBox.java @@ -20,6 +20,8 @@ import java.awt.Graphics; import java.util.HashMap; import java.util.Map; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.program.model.address.AddressRange; import ghidra.trace.model.Lifespan; @@ -34,7 +36,7 @@ public class MemoryBox { protected long stopAddr = -1; protected long startTime; protected long stopTime = -1; - protected Color color = Color.BLUE; + protected Color color = new GColor("color.bg.debugger.memview.box"); protected int pixAstart; protected int pixAend; @@ -108,8 +110,9 @@ public class MemoryBox { } public int getAddressPixelWidth() { - if (pixAend - pixAstart <= 0) + if (pixAend - pixAstart <= 0) { return 1; + } return pixAend - pixAstart; } @@ -121,8 +124,9 @@ public class MemoryBox { if (pixTend < pixTstart) { pixTend = boundT; } - if (pixTend - pixTstart == 0) + if (pixTend - pixTstart == 0) { return 1; + } return pixTend - pixTstart; } @@ -147,7 +151,7 @@ public class MemoryBox { int w = vertical ? getTimePixelWidth() : getAddressPixelWidth(); int y = vertical ? getAddressPixelStart() : getTimePixelStart(); int h = vertical ? getAddressPixelWidth() : getTimePixelWidth(); - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); g.fillRect(x - 1, y - 1, w + 2, h + 2); g.setColor(color); g.fillRect(x, y, w, h); @@ -158,7 +162,7 @@ public class MemoryBox { int w = vertical ? sz : getAddressPixelWidth(); int y = vertical ? getAddressPixelStart() : 0; int h = vertical ? getAddressPixelWidth() : sz; - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); g.fillRect(x - 1, y - 1, w + 2, h + 2); g.setColor(color); g.fillRect(x, y, w, h); @@ -169,7 +173,7 @@ public class MemoryBox { int w = vertical ? 1 : sz; int y = vertical ? 0 : getTimePixelStart(); int h = vertical ? sz : 1; - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); g.fillRect(x - 1, y - 1, w + 2, h + 2); g.setColor(color); g.fillRect(x, y, w, h); @@ -227,10 +231,12 @@ public class MemoryBox { } public boolean inPixelRange(long pos) { - if (pos < pixTstart) + if (pos < pixTstart) { return false; - if (pixTend <= 0) + } + if (pixTend <= 0) { return true; + } return pos <= pixTend; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewBoxType.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewBoxType.java index ff6408e8e0..c0cdb8e3e8 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewBoxType.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewBoxType.java @@ -17,6 +17,8 @@ package ghidra.app.plugin.core.debug.gui.memview; import java.awt.Color; +import generic.theme.GColor; + public enum MemviewBoxType { INSTRUCTIONS, PROCESS, @@ -35,21 +37,21 @@ public enum MemviewBoxType { BREAKPOINT; Color[] colors = { // - new Color(128, 000, 000), // INSTRUCTIONS - new Color(200, 200, 255), // PROCESS - new Color(200, 255, 255), // THREAD - Color.GREEN, //new Color(000, 150, 200), // MODULE - Color.YELLOW, //new Color(000, 150, 200), // REGION - Color.MAGENTA, //new Color(050, 100, 255), // IMAGE - Color.LIGHT_GRAY, // VIRTUAL_ALLOC - Color.BLUE, // HEAP_CREATE - new Color(000, 100, 050), // HEAP_ALLOC - new Color(100, 000, 150), // POOL - Color.CYAN, // STACK - Color.LIGHT_GRAY, // PERFINFO - Color.DARK_GRAY, // READ_MEMORY - Color.BLUE, // WRITE_MEMORY - Color.RED, // WRITE_MEMORY + new GColor("color.debugger.plugin.memview.box.type.instructions"), + new GColor("color.debugger.plugin.memview.box.type.process"), + new GColor("color.debugger.plugin.memview.box.type.thread"), + new GColor("color.debugger.plugin.memview.box.type.module"), + new GColor("color.debugger.plugin.memview.box.type.region"), + new GColor("color.debugger.plugin.memview.box.type.image"), + new GColor("color.debugger.plugin.memview.box.type.virtual.alloc"), + new GColor("color.debugger.plugin.memview.box.type.heap.create"), + new GColor("color.debugger.plugin.memview.box.type.heap.alloc"), + new GColor("color.debugger.plugin.memview.box.type.pool"), + new GColor("color.debugger.plugin.memview.box.type.stack"), + new GColor("color.debugger.plugin.memview.box.type.perfinfo"), + new GColor("color.debugger.plugin.memview.box.type.read.memory"), + new GColor("color.debugger.plugin.memview.box.type.write.memory"), + new GColor("color.debugger.plugin.memview.box.type.breakpoint"), }; public Color getColor() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java index ffe529eb41..f3a55bbb08 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java @@ -22,16 +22,20 @@ import java.util.List; import javax.swing.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; public class MemviewPanel extends JPanel implements MouseListener, MouseMotionListener { private static final long serialVersionUID = 1L; + private Color ARROW_COLOR = new GColor("color.debugger.memview.arrow"); + private MemviewProvider provider; private MemviewMap amap; private MemviewMap tmap; - private List boxList = new ArrayList(); + private List boxList = new ArrayList<>(); private int pressedX; private int pressedY; @@ -60,7 +64,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi this.provider = provider; setPreferredSize(new Dimension(barWidth, barHeight)); setSize(getPreferredSize()); - setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); + setBorder(BorderFactory.createLineBorder(Java.BORDER, 1)); setFocusable(true); addMouseListener(this); @@ -129,7 +133,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi g.translate(currentPixelAddr, currentPixelTime); } - g.setColor(Color.RED); + g.setColor(ARROW_COLOR); g.fillPolygon(locXs, locYs, locXs.length); if (vertical) { @@ -149,7 +153,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi int y = currentRectangle.y; int w = currentRectangle.width; int h = currentRectangle.height; - g.setColor(Color.RED); + g.setColor(ARROW_COLOR); g.fillRect(x - 1, y - 1, 1, h + 2); g.fillRect(x - 1, y - 1, w + 2, 1); g.fillRect(x + w + 1, y - 1, 1, h + 2); @@ -180,17 +184,19 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi } void updateBoxes() { - if (!this.isShowing()) + if (!this.isShowing()) { return; + } - boxList = new ArrayList(); + boxList = new ArrayList<>(); Collection boxes = getBoxes(); if (boxes == null) { return; } for (MemoryBox box : boxes) { - if (box == null) + if (box == null) { continue; + } int bound = vertical ? getHeight() - 1 : getWidth() - 1; box.setAddressBounds(amap, bound); @@ -374,26 +380,26 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi Set mboxes = addr2box.get(box.getStartAddress()); if (mboxes == null) { - mboxes = new HashSet(); + mboxes = new HashSet<>(); } mboxes.add(box); addr2box.put(box.getStartAddress(), mboxes); mboxes = addr2box.get(box.getStopAddress()); if (mboxes == null) { - mboxes = new HashSet(); + mboxes = new HashSet<>(); } mboxes.add(box); addr2box.put(box.getStopAddress(), mboxes); mboxes = time2box.get(box.getStartTime()); if (mboxes == null) { - mboxes = new HashSet(); + mboxes = new HashSet<>(); } mboxes.add(box); time2box.put(box.getStartTime(), mboxes); mboxes = time2box.get(box.getStopTime()); if (mboxes == null) { - mboxes = new HashSet(); + mboxes = new HashSet<>(); } mboxes.add(box); time2box.put(box.getStopTime(), mboxes); @@ -415,7 +421,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi public void addBoxes(List boxes) { if (blist == null) { - blist = new ArrayList(); + blist = new ArrayList<>(); } for (MemoryBox b : boxes) { if (bmap.containsKey(b.getId())) { @@ -429,7 +435,7 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi } public void reset() { - blist = new ArrayList(); + blist = new ArrayList<>(); bmap.clear(); parseBoxes(blist); } @@ -451,14 +457,16 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi } public long getAddr(int x, int y) { - if (amap == null) + if (amap == null) { return 0; + } return vertical ? amap.getOffset(y) : amap.getOffset(x); } public long getTick(int x, int y) { - if (tmap == null) + if (tmap == null) { return 0; + } return vertical ? tmap.getOffset(x) : tmap.getOffset(y); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java index 39d68a351e..040f71f3f3 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java @@ -21,10 +21,9 @@ import java.awt.event.MouseEvent; import java.util.*; import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import docking.widgets.filter.FilterListener; +import generic.theme.GIcon; import ghidra.app.services.DebuggerListingService; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRangeImpl; @@ -32,11 +31,10 @@ import ghidra.program.model.listing.Program; import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.task.SwingUpdateManager; -import resources.ResourceManager; public class MemviewTable { - public static final ImageIcon ICON_TABLE = ResourceManager.loadImage("images/table.png"); + public static final Icon ICON_TABLE = new GIcon("icon.table"); private MemviewMapModel model; private GhidraTable table; @@ -61,19 +59,16 @@ public class MemviewTable { component.add(filterPanel, BorderLayout.SOUTH); table.setAutoscrolls(true); - table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - if (e.getValueIsAdjusting()) { - return; - } - int modelRow = filterPanel.getModelRow(table.getSelectedRow()); - MemoryBox box = model.getBoxAt(modelRow); - if (box != null) { - Set boxes = new HashSet(); - boxes.add(box); - provider.selectPanelPosition(boxes); - } + table.getSelectionModel().addListSelectionListener(e -> { + if (e.getValueIsAdjusting()) { + return; + } + int modelRow = filterPanel.getModelRow(table.getSelectedRow()); + MemoryBox box = model.getBoxAt(modelRow); + if (box != null) { + Set boxes = new HashSet<>(); + boxes.add(box); + provider.selectPanelPosition(boxes); } }); table.addMouseListener(new MouseAdapter() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInAAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInAAction.java index cca269873e..3d8862ea1a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInAAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInAAction.java @@ -15,18 +15,18 @@ */ package ghidra.app.plugin.core.debug.gui.memview.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.memview.MemviewProvider; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ZoomInAAction extends DockingAction { - private final ImageIcon ICON = ResourceManager.loadImage("images/zoom_in.png"); + private static final Icon ICON = new GIcon("icon.widget.imagepanel.zoom.in"); private MemviewProvider provider; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInTAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInTAction.java index 0effc0c1fe..71550db354 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInTAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomInTAction.java @@ -15,18 +15,18 @@ */ package ghidra.app.plugin.core.debug.gui.memview.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.memview.MemviewProvider; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ZoomInTAction extends DockingAction { - private final ImageIcon ICON = ResourceManager.loadImage("images/zoom_in.png"); + private static final Icon ICON = new GIcon("icon.widget.imagepanel.zoom.in"); private MemviewProvider provider; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutAAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutAAction.java index f3174c729c..84a6aec075 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutAAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutAAction.java @@ -15,18 +15,18 @@ */ package ghidra.app.plugin.core.debug.gui.memview.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.memview.MemviewProvider; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ZoomOutAAction extends DockingAction { - private final ImageIcon ICON = ResourceManager.loadImage("images/zoom_out.png"); + private static final Icon ICON = new GIcon("icon.widget.imagepanel.zoom.out"); private MemviewProvider provider; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutTAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutTAction.java index 0243042d94..3f914dfbba 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutTAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/actions/ZoomOutTAction.java @@ -15,18 +15,18 @@ */ package ghidra.app.plugin.core.debug.gui.memview.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.memview.MemviewProvider; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ZoomOutTAction extends DockingAction { - private final ImageIcon ICON = ResourceManager.loadImage("images/zoom_out.png"); + private static final Icon ICON = new GIcon("icon.widget.imagepanel.zoom.out"); private MemviewProvider provider; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java index 146abd0824..bd16375cd7 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java @@ -29,6 +29,7 @@ import docking.action.DockingAction; import docking.action.ToggleDockingAction; import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener; import docking.widgets.tree.support.GTreeSelectionEvent.EventOrigin; +import generic.theme.GColor; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.gui.DebuggerResources; @@ -77,16 +78,10 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable @SuppressWarnings("unused") private final AutoService.Wiring autoServiceWiring; - @AutoOptionDefined( - description = "Text color for values that have just changed", - name = DebuggerResources.OPTION_NAME_COLORS_VALUE_CHANGED, - help = @HelpInfo(anchor = "colors")) + @AutoOptionDefined(description = "Text color for values that have just changed", name = DebuggerResources.OPTION_NAME_COLORS_VALUE_CHANGED, help = @HelpInfo(anchor = "colors")) private Color diffColor = DebuggerResources.DEFAULT_COLOR_VALUE_CHANGED; - @AutoOptionDefined( - description = "Select text color for values that have just changed", - name = DebuggerResources.OPTION_NAME_COLORS_VALUE_CHANGED_SEL, - help = @HelpInfo(anchor = "colors")) + @AutoOptionDefined(description = "Select text color for values that have just changed", name = DebuggerResources.OPTION_NAME_COLORS_VALUE_CHANGED_SEL, help = @HelpInfo(anchor = "colors")) private Color diffColorSel = DebuggerResources.DEFAULT_COLOR_VALUE_CHANGED_SEL; @SuppressWarnings("unused") @@ -143,7 +138,8 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable setTitle("[" + DebuggerResources.TITLE_PROVIDER_MODEL + "]"); setWindowGroup("Debugger.Core.disconnected"); setIntraGroupPosition(WindowPosition.STACK); - mainPanel.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 2)); + mainPanel.setBorder(BorderFactory + .createLineBorder(new GColor("color.border.provider.disconnected"), 2)); setTransient(); } else { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java index 678f5ed370..615640aebd 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java @@ -43,6 +43,8 @@ import docking.widgets.OptionDialog; import docking.widgets.table.DefaultEnumeratedColumnTableModel; import docking.widgets.tree.GTree; import generic.jar.ResourceFile; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.gui.DebuggerResources; @@ -123,76 +125,76 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter public static final String OPTION_NAME_DEFAULT_BACKGROUND_COLOR = "Object Colors.Background"; @AutoOptionDefined( // - name = OPTION_NAME_DEFAULT_FOREGROUND_COLOR, // - description = "The default foreground color of items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_DEFAULT_FOREGROUND_COLOR, // + description = "The default foreground color of items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color defaultForegroundColor = Color.BLACK; + Color defaultForegroundColor = new GColor("color.fg.debugger.plugin.objects.default"); @AutoOptionDefined( // - name = OPTION_NAME_DEFAULT_BACKGROUND_COLOR, // - description = "The default background color of items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_DEFAULT_BACKGROUND_COLOR, // + description = "The default background color of items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color defaultBackgroundColor = Color.WHITE; + Color defaultBackgroundColor = new GColor("color.bg.debugger.plugin.objects.default"); @AutoOptionDefined( // - name = OPTION_NAME_INVISIBLE_FOREGROUND_COLOR, // - description = "The foreground color for items normally not visible (toggleable)", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_INVISIBLE_FOREGROUND_COLOR, // + description = "The foreground color for items normally not visible (toggleable)", // + help = @HelpInfo(anchor = "colors") // ) - Color invisibleForegroundColor = Color.LIGHT_GRAY; + Color invisibleForegroundColor = new GColor("color.fg.debugger.plugin.objects.invisible"); @AutoOptionDefined( // - name = OPTION_NAME_INVALIDATED_FOREGROUND_COLOR, // - description = "The foreground color for items no longer valid", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_INVALIDATED_FOREGROUND_COLOR, // + description = "The foreground color for items no longer valid", // + help = @HelpInfo(anchor = "colors") // ) - Color invalidatedForegroundColor = Color.LIGHT_GRAY; + Color invalidatedForegroundColor = new GColor("color.fg.debugger.plugin.objects.invalidated"); @AutoOptionDefined( // - name = OPTION_NAME_MODIFIED_FOREGROUND_COLOR, // - description = "The foreground color for modified items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_MODIFIED_FOREGROUND_COLOR, // + description = "The foreground color for modified items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color modifiedForegroundColor = Color.RED; + Color modifiedForegroundColor = new GColor("color.fg.debugger.plugin.objects.modified"); @AutoOptionDefined( // - name = OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR, // - description = "The foreground color for subscribed items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR, // + description = "The foreground color for subscribed items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color subscribedForegroundColor = Color.BLACK; + Color subscribedForegroundColor = new GColor("color.fg.debugger.plugin.objects.subscribed"); @AutoOptionDefined( // - name = OPTION_NAME_ERROR_FOREGROUND_COLOR, // - description = "The foreground color for items in error", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_ERROR_FOREGROUND_COLOR, // + description = "The foreground color for items in error", // + help = @HelpInfo(anchor = "colors") // ) - Color errorForegroundColor = Color.RED; + Color errorForegroundColor = new GColor("color.fg.debugger.plugin.objects.error"); @AutoOptionDefined( // - name = OPTION_NAME_INTRINSIC_FOREGROUND_COLOR, // - description = "The foreground color for intrinsic items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_INTRINSIC_FOREGROUND_COLOR, // + description = "The foreground color for intrinsic items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color intrinsicForegroundColor = Color.BLUE; + Color intrinsicForegroundColor = new GColor("color.fg.debugger.plugin.objects.intrinsic"); @AutoOptionDefined( // - name = OPTION_NAME_TARGET_FOREGROUND_COLOR, // - description = "The foreground color for target object items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_TARGET_FOREGROUND_COLOR, // + description = "The foreground color for target object items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color targetForegroundColor = Color.MAGENTA; + Color targetForegroundColor = new GColor("color.fg.debugger.plugin.objects.target"); @AutoOptionDefined( // - name = OPTION_NAME_ACCESSOR_FOREGROUND_COLOR, // - description = "The foreground color for property accessor items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_ACCESSOR_FOREGROUND_COLOR, // + description = "The foreground color for property accessor items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color accessorForegroundColor = Color.LIGHT_GRAY; + Color accessorForegroundColor = new GColor("color.fg.debugger.plugin.objects.accessor"); @AutoOptionDefined( // - name = OPTION_NAME_LINK_FOREGROUND_COLOR, // - description = "The foreground color for links to items in the objects tree", // - help = @HelpInfo(anchor = "colors") // + name = OPTION_NAME_LINK_FOREGROUND_COLOR, // + description = "The foreground color for links to items in the objects tree", // + help = @HelpInfo(anchor = "colors") // ) - Color linkForegroundColor = Color.GREEN.darker(); + Color linkForegroundColor = new GColor("color.fg.debugger.plugin.objects.link"); @AutoOptionDefined( // - name = "Default Extended Step", // - description = "The default string for the extended step command" // + name = "Default Extended Step", // + description = "The default string for the extended step command" // //help = @HelpInfo(anchor = "colors") // ) String extendedStep = ""; @@ -281,7 +283,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter this.asTree = asTree; setIcon(asTree ? ObjectTree.ICON_TREE : ObjectTable.ICON_TABLE); - targetMap = new LinkedMap(); + targetMap = new LinkedMap<>(); refSet = new HashSet<>(); getRoot().propagateProvider(this); @@ -658,7 +660,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter } } model.addAll(list); - return new ObjectTable(container, ObjectAttributeRow.class, model); + return new ObjectTable<>(container, ObjectAttributeRow.class, model); } private ObjectTable buildTableFromElements(ObjectContainer container) { @@ -678,7 +680,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter new ObjectEnumeratedColumnTableModel<>(name, cols); model.addAll(list); ObjectTable table = - new ObjectTable(container, ObjectElementRow.class, model); + new ObjectTable<>(container, ObjectElementRow.class, model); for (Object obj : map.values()) { if (obj instanceof TargetObject) { TargetObject ref = (TargetObject) obj; @@ -744,7 +746,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter static List getContainersFromObjects(Map objectMap, TargetObject parent, boolean usingAttributes) { - List result = new ArrayList(); + List result = new ArrayList<>(); if (parent == null || parent instanceof DummyTargetObject) { return result; } @@ -826,7 +828,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter public ObjectContainer getParent(ObjectContainer container) { List path = container.getTargetObject().getPath(); - List ppath = new ArrayList(); + List ppath = new ArrayList<>(); for (String link : path) { ppath.add(link); } @@ -2028,7 +2030,7 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter case OPTION_NAME_TARGET_FOREGROUND_COLOR: return targetForegroundColor; default: - return Color.BLACK; + return Colors.FOREGROUND; } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsGraphAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsGraphAction.java index 94aab1d014..6518ac2d9f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsGraphAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsGraphAction.java @@ -19,10 +19,11 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.KeyBindingData; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.services.GraphDisplayBroker; @@ -33,13 +34,12 @@ import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class DisplayAsGraphAction extends DisplayAsAction { protected GraphDisplayBroker graphBroker; - protected static ImageIcon ICON_GRAPH = ResourceManager.loadImage("images/breakpoints.png"); + protected static final Icon ICON_GRAPH = new GIcon("icon.debugger.display.graph"); public DisplayAsGraphAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { super("DisplayGraph", tool, owner, provider); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsXMLAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsXMLAction.java index 2c91a29bbe..5d302c7e97 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsXMLAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayAsXMLAction.java @@ -18,12 +18,13 @@ package ghidra.app.plugin.core.debug.gui.objects.actions; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.jdom.Element; import docking.action.KeyBindingData; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.services.ConsoleService; @@ -31,12 +32,11 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.xml.XmlUtilities; -import resources.ResourceManager; public class DisplayAsXMLAction extends DisplayAsAction { protected ConsoleService consoleService; - protected ImageIcon ICON_XML = ResourceManager.loadImage("images/text-xml.png");; + protected static final Icon ICON_XML = new GIcon("icon.debugger.display.xml"); public DisplayAsXMLAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { super("DisplayXml", tool, owner, provider); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredGraphAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredGraphAction.java index c6c1435bf1..3c18478b73 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredGraphAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredGraphAction.java @@ -20,10 +20,11 @@ import java.awt.event.KeyEvent; import java.util.List; import java.util.Set; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.KeyBindingData; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.services.GraphDisplayBroker; @@ -34,13 +35,12 @@ import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class DisplayFilteredGraphAction extends DisplayFilteredAction { protected GraphDisplayBroker graphBroker; - protected static ImageIcon ICON_GRAPH = ResourceManager.loadImage("images/breakpoints.png"); + protected static final Icon ICON_GRAPH = new GIcon("icon.debugger.display.xml.filtered"); public DisplayFilteredGraphAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredXMLAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredXMLAction.java index 655b050b27..9ae256bd59 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredXMLAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/DisplayFilteredXMLAction.java @@ -19,13 +19,14 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.apache.commons.lang3.StringUtils; import org.jdom.Element; import docking.action.KeyBindingData; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.services.ConsoleService; @@ -33,12 +34,11 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.xml.XmlUtilities; -import resources.ResourceManager; public class DisplayFilteredXMLAction extends DisplayFilteredAction { protected ConsoleService consoleService; - protected ImageIcon ICON_XML = ResourceManager.loadImage("images/text-xml.png");; + protected static final Icon ICON_XML = new GIcon("icon.debugger.display.xml.filtered"); public DisplayFilteredXMLAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsFactsAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsFactsAction.java index 419ddd2bfd..348e19aaa4 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsFactsAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsFactsAction.java @@ -21,17 +21,17 @@ import java.io.*; import java.util.HashMap; import java.util.Map; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.filechooser.GhidraFileChooserMode; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.dbg.target.TargetObject; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ExportAsFactsAction extends ImportExportAsAction { @@ -39,8 +39,8 @@ public class ExportAsFactsAction extends ImportExportAsAction { public static String JOIN = "."; public static String SPLIT = "\\."; public static String fileExt2 = ".facts"; - protected ImageIcon ICON_FACTS = ResourceManager.loadImage("images/closedFolder.png"); - private Map files = new HashMap(); + protected static final Icon ICON_FACTS = new GIcon("icon.debugger.display.export.facts"); + private Map files = new HashMap<>(); public ExportAsFactsAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { super("ExportAsFacts", tool, owner, provider); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsXMLAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsXMLAction.java index e4a1331c0c..71be677be1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsXMLAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ExportAsXMLAction.java @@ -20,7 +20,7 @@ import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.apache.commons.lang3.StringUtils; import org.jdom.Document; @@ -29,16 +29,16 @@ import org.jdom.Element; import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.filechooser.GhidraFileChooserMode; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; import ghidra.util.xml.XmlUtilities; -import resources.ResourceManager; public class ExportAsXMLAction extends ImportExportAsAction { - protected ImageIcon ICON_XML = ResourceManager.loadImage("images/text-xml.png"); + protected static final Icon ICON_XML = new GIcon("icon.debugger.display.export.xml"); public ExportAsXMLAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { super("ExportAsXML", tool, owner, provider); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromFactsAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromFactsAction.java index 0515bce7af..9656c25871 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromFactsAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromFactsAction.java @@ -20,26 +20,26 @@ import java.awt.event.KeyEvent; import java.io.*; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.SwingUtilities; import docking.ActionContext; import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.filechooser.GhidraFileChooserMode; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.plugin.core.debug.gui.objects.components.DummyTargetObject; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; import ghidra.util.Msg; -import resources.ResourceManager; public class ImportFromFactsAction extends ImportExportAsAction { - protected ImageIcon ICON_FACTS = ResourceManager.loadImage("images/closedFolder.png"); + protected static final Icon ICON_FACTS = new GIcon("icon.debugger.display.import.facts"); private Map> maps = - new LinkedHashMap>(); + new LinkedHashMap<>(); public ImportFromFactsAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { super("ImportFromFacts", tool, owner, provider); @@ -75,7 +75,7 @@ public class ImportFromFactsAction extends ImportExportAsAction { for (File f : dir.listFiles()) { BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f))); - Map map = new LinkedHashMap(); + Map map = new LinkedHashMap<>(); String name = f.getName(); name = name.substring(0, name.indexOf(ExportAsFactsAction.fileExt2)); maps.put(name, map); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromXMLAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromXMLAction.java index af97a71ece..7fa6be2a47 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromXMLAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/ImportFromXMLAction.java @@ -21,7 +21,7 @@ import java.io.*; import java.util.ArrayList; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.SwingUtilities; import org.jdom.Attribute; @@ -32,6 +32,7 @@ import docking.ActionContext; import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.filechooser.GhidraFileChooserMode; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.app.plugin.core.debug.gui.objects.components.DummyTargetObject; @@ -40,11 +41,10 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.xml.XmlUtilities; -import resources.ResourceManager; public class ImportFromXMLAction extends ImportExportAsAction { - protected ImageIcon ICON_XML = ResourceManager.loadImage("images/text-xml.png"); + protected static final Icon ICON_XML = new GIcon("icon.debugger.display.import.xml"); public ImportFromXMLAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { super("ImportFromXML", tool, owner, provider); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/OpenWinDbgTraceAction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/OpenWinDbgTraceAction.java index 1b80c5877d..a46320c874 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/OpenWinDbgTraceAction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/actions/OpenWinDbgTraceAction.java @@ -21,13 +21,14 @@ import java.io.File; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.SwingUtilities; import docking.ActionContext; import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.filechooser.GhidraFileChooserMode; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.async.AsyncUtils; @@ -38,11 +39,10 @@ import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher; import ghidra.dbg.target.TargetObject; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class OpenWinDbgTraceAction extends ImportExportAsAction { - protected ImageIcon ICON_TRACE = ResourceManager.loadImage("images/text-xml.png"); + protected static final Icon ICON_TRACE = new GIcon("icon.debugger.open.windbg.trace"); private ActionContext context; public OpenWinDbgTraceAction(PluginTool tool, String owner, DebuggerObjectsProvider provider) { @@ -66,23 +66,20 @@ public class OpenWinDbgTraceAction extends ImportExportAsAction { if (f == null) { return; } - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - String[] args = new String[2]; - args[0] = ".opendump"; - args[1] = f.getAbsolutePath(); - AtomicReference launcher = new AtomicReference<>(); - AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { - TargetObject obj = provider.getObjectFromContext(context); - DebugModelConventions.findSuitable(TargetLauncher.class, obj).handle(seq::next); - }, launcher).then(seq -> { - launcher.get() - .launch(Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, args)) - .handle(seq::next); - seq.exit(); - }).finish(); - } + SwingUtilities.invokeLater(() -> { + String[] args = new String[2]; + args[0] = ".opendump"; + args[1] = f.getAbsolutePath(); + AtomicReference launcher = new AtomicReference<>(); + AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { + TargetObject obj = provider.getObjectFromContext(context); + DebugModelConventions.findSuitable(TargetLauncher.class, obj).handle(seq::next); + }, launcher).then(seq -> { + launcher.get() + .launch(Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, args)) + .handle(seq::next); + seq.exit(); + }).finish(); }); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java index 813045526a..6d3320822c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectNode.java @@ -19,9 +19,9 @@ import java.util.*; import java.util.concurrent.*; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.widgets.tree.*; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.dbg.target.*; @@ -29,17 +29,14 @@ import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode - static final ImageIcon ICON_POPULATED = - ResourceManager.loadImage("images/object-populated.png"); - static final ImageIcon ICON_EMPTY = ResourceManager.loadImage("images/object-unpopulated.png"); - static final ImageIcon ICON_RUNNING = ResourceManager.loadImage("images/object-running.png"); - static final ImageIcon ICON_TERMINATED = - ResourceManager.loadImage("images/object-terminated.png"); - static final ImageIcon ICON_EVENT = ResourceManager.loadImage("images/register-marker.png"); + static final Icon ICON_POPULATED = new GIcon("icon.debugger.node.object.populated"); + static final Icon ICON_EMPTY = new GIcon("icon.debugger.node.object.empty"); + static final Icon ICON_RUNNING = new GIcon("icon.debugger.node.object.running"); + static final Icon ICON_TERMINATED = new GIcon("icon.debugger.node.object.terminated"); + static final Icon ICON_EVENT = new GIcon("icon.debugger.node.object.event"); private ObjectContainer container; private String name; @@ -212,26 +209,20 @@ public class ObjectNode extends GTreeSlowLoadingNode { //extends GTreeNode public void callUpdate() { // NB: this has to be in its own thread - CompletableFuture.runAsync(new Runnable() { - @Override - public void run() { - List updateNodes = tree.update(container); - if (isRestructured()) { - setChildren(updateNodes); - } + CompletableFuture.runAsync(() -> { + List updateNodes = tree.update(container); + if (isRestructured()) { + setChildren(updateNodes); } }); } public void callModified() { // NB: this has to be in its own thread - CompletableFuture.runAsync(new Runnable() { - @Override - public void run() { - List updateNodes = tree.update(container); - for (GTreeNode n : updateNodes) { - n.fireNodeChanged(); - } + CompletableFuture.runAsync(() -> { + List updateNodes = tree.update(container); + for (GTreeNode n : updateNodes) { + n.fireNodeChanged(); } }); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTable.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTable.java index 0090f348c6..9b93643e92 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTable.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTable.java @@ -20,21 +20,19 @@ import java.awt.event.MouseEvent; import java.util.*; import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import docking.widgets.table.AbstractSortedTableModel; import docking.widgets.table.EnumeratedColumnTableModel; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.dbg.target.TargetObject; import ghidra.util.Swing; import ghidra.util.table.GhidraTable; -import resources.ResourceManager; public class ObjectTable implements ObjectPane { - public static final ImageIcon ICON_TABLE = ResourceManager.loadImage("images/table.png"); + public static final Icon ICON_TABLE = new GIcon("icon.debugger.table.object"); private ObjectContainer container; private Class clazz; @@ -50,15 +48,12 @@ public class ObjectTable implements ObjectPane { this.clazz = clazz; this.model = model; - table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - if (e.getValueIsAdjusting()) { - return; - } - DebuggerObjectsProvider provider = container.getProvider(); - provider.getTool().contextChanged(provider); + table.getSelectionModel().addListSelectionListener(e -> { + if (e.getValueIsAdjusting()) { + return; } + DebuggerObjectsProvider provider = container.getProvider(); + provider.getTool().contextChanged(provider); }); table.addMouseListener(new MouseAdapter() { @Override diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java index d0a19529d9..c24777a8c1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTree.java @@ -21,7 +21,7 @@ import java.awt.event.MouseEvent; import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; @@ -33,6 +33,7 @@ import docking.widgets.tree.GTreeNode; import docking.widgets.tree.support.GTreeSelectionEvent; import docking.widgets.tree.support.GTreeSelectionEvent.EventOrigin; import docking.widgets.tree.support.GTreeSelectionListener; +import generic.theme.GIcon; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.async.AsyncUtils; @@ -40,14 +41,13 @@ import ghidra.async.TypeSpec; import ghidra.dbg.DebugModelConventions; import ghidra.dbg.target.TargetAccessConditioned; import ghidra.dbg.target.TargetObject; -import ghidra.util.*; +import ghidra.util.Msg; +import ghidra.util.Swing; import ghidra.util.task.SwingUpdateManager; -import resources.ResourceManager; public class ObjectTree implements ObjectPane { - public static final ImageIcon ICON_TREE = - ResourceManager.loadImage("images/object-unpopulated.png"); + public static final Icon ICON_TREE = new GIcon("icon.debugger.tree.object"); private ObjectNode root; private GTree tree; @@ -118,16 +118,12 @@ public class ObjectTree implements ObjectPane { } }); tree.setCellRenderer(new ObjectTreeCellRenderer(root.getProvider())); - tree.setDataTransformer(new FilterTransformer() { - - @Override - public List transform(GTreeNode t) { - if (t instanceof ObjectNode) { - ObjectNode node = (ObjectNode) t; - return List.of(node.getContainer().getDecoratedName()); - } - return null; + tree.setDataTransformer(t -> { + if (t instanceof ObjectNode) { + ObjectNode node = (ObjectNode) t; + return List.of(node.getContainer().getDecoratedName()); } + return null; }); tree.addTreeExpansionListener(new TreeExpansionListener() { @@ -329,7 +325,7 @@ public class ObjectTree implements ObjectPane { } Set currentChildren = container.getCurrentChildren(); - List childList = new ArrayList(); + List childList = new ArrayList<>(); node.setRestructured(false); for (ObjectContainer c : currentChildren) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTreeCellRenderer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTreeCellRenderer.java index 8055fae1bb..6541145314 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTreeCellRenderer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/ObjectTreeCellRenderer.java @@ -15,32 +15,27 @@ */ package ghidra.app.plugin.core.debug.gui.objects.components; -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; +import java.awt.*; import java.util.Map; import javax.swing.JTree; import javax.swing.tree.TreePath; import docking.widgets.tree.support.GTreeRenderer; +import generic.theme.GThemeDefaults.Colors.Tables; +import generic.theme.Gui; import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider; import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer; import ghidra.dbg.target.TargetExecutionStateful; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; import ghidra.dbg.target.TargetObject; -import ghidra.util.SystemUtilities; // TODO: In the new scheme, I'm not sure this is applicable anymore. class ObjectTreeCellRenderer extends GTreeRenderer { + private static final String FONT_ID = "font.debugger.object.tree.renderer"; private final DebuggerObjectsProvider provider; - private Font defaultFont = SystemUtilities.adjustForFontSizeOverride(new Font("Tahoma", Font.PLAIN, 11)); - private Font unsubscribedFont = SystemUtilities.adjustForFontSizeOverride(new Font("Tahoma", Font.ITALIC, 11)); - /** - * @param provider - */ public ObjectTreeCellRenderer(DebuggerObjectsProvider provider) { this.provider = provider; } @@ -90,7 +85,7 @@ class ObjectTreeCellRenderer extends GTreeRenderer { if (container.isSubscribed()) { Color color = provider .getColor(DebuggerObjectsProvider.OPTION_NAME_SUBSCRIBED_FOREGROUND_COLOR); - if (!color.equals(Color.BLACK)) { + if (!color.equals(Tables.FG_UNSELECTED)) { component.setForeground(color); } } @@ -100,11 +95,15 @@ class ObjectTreeCellRenderer extends GTreeRenderer { if (last instanceof ObjectNode) { ObjectContainer selection = ((ObjectNode) last).getContainer(); if (container.equals(selection)) { - component.setForeground(Color.WHITE); + component.setForeground(Tables.FG_SELECTED); } } } - component.setFont(container.isSubscribed() ? defaultFont : unsubscribedFont); + Font font = Gui.getFont(FONT_ID); + if (container.isSubscribed()) { + font = font.deriveFont(Font.ITALIC); + } + component.setFont(font); } return component; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java index 557b2906be..1eadc599bc 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java @@ -38,6 +38,7 @@ import docking.actions.PopupActionProvider; import docking.widgets.table.*; import docking.widgets.table.ColumnSortState.SortDirection; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; +import generic.theme.GColor; import ghidra.app.plugin.core.data.DataSettingsDialog; import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; @@ -472,25 +473,21 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter @SuppressWarnings("unused") private final AutoService.Wiring autoServiceWiring; - @AutoOptionDefined( - name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_STALE, // - description = "Text color for registers whose value is not known", // - help = @HelpInfo(anchor = "colors")) + @AutoOptionDefined(name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_STALE, // + description = "Text color for registers whose value is not known", // + help = @HelpInfo(anchor = "colors")) protected Color registerStaleColor = DebuggerResources.DEFAULT_COLOR_REGISTER_STALE; - @AutoOptionDefined( - name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_STALE_SEL, // - description = "Selected text color for registers whose value is not known", // - help = @HelpInfo(anchor = "colors")) + @AutoOptionDefined(name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_STALE_SEL, // + description = "Selected text color for registers whose value is not known", // + help = @HelpInfo(anchor = "colors")) protected Color registerStaleSelColor = DebuggerResources.DEFAULT_COLOR_REGISTER_STALE_SEL; - @AutoOptionDefined( - name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_CHANGED, // - description = "Text color for registers whose value just changed", // - help = @HelpInfo(anchor = "colors")) + @AutoOptionDefined(name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_CHANGED, // + description = "Text color for registers whose value just changed", // + help = @HelpInfo(anchor = "colors")) protected Color registerChangesColor = DebuggerResources.DEFAULT_COLOR_REGISTER_CHANGED; - @AutoOptionDefined( - name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_CHANGED_SEL, // - description = "Selected text color for registers whose value just changed", // - help = @HelpInfo(anchor = "colors")) + @AutoOptionDefined(name = DebuggerResources.OPTION_NAME_COLORS_REGISTER_CHANGED_SEL, // + description = "Selected text color for registers whose value just changed", // + help = @HelpInfo(anchor = "colors")) protected Color registerChangesSelColor = DebuggerResources.DEFAULT_COLOR_REGISTER_CHANGED_SEL; @SuppressWarnings("unused") @@ -550,7 +547,8 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter setTitle("[" + DebuggerResources.TITLE_PROVIDER_REGISTERS + "]"); setWindowGroup("Debugger.Core.disconnected"); setIntraGroupPosition(WindowPosition.STACK); - mainPanel.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 2)); + mainPanel.setBorder(BorderFactory + .createLineBorder(new GColor("color.border.provider.disconnected"), 2)); setTransient(); } else { diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java index 5a876a4208..d4f7a275b6 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java @@ -441,7 +441,7 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest assertNotNull("Cannot get cursor bounds", cursor); Color actual = new Color(image.getRGB(locFP.x + cursor.x - 1, locFP.y + cursor.y + cursor.height * 3 / 2 + yAdjust)); - assertEquals(expected, actual); + assertEquals(expected.getRGB(), actual.getRGB()); }); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java index 461d2526a0..76bf66db00 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java @@ -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(); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java index 5531d1f9f4..2b9480cb00 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java @@ -17,7 +17,6 @@ package ghidra.app.plugin.core.debug.gui.copying; import static org.junit.Assert.*; -import java.awt.Color; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.*; @@ -26,6 +25,7 @@ import javax.swing.JCheckBox; import org.junit.Test; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.assembler.Assembler; import ghidra.app.plugin.assembler.Assemblers; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; @@ -615,7 +615,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); BookmarkManager bookmarks = view.getBookmarkManager(); - bookmarks.defineType("TestType", DebuggerResources.ICON_DEBUGGER, Color.BLUE, 1); + bookmarks.defineType("TestType", DebuggerResources.ICON_DEBUGGER, Palette.BLUE, 1); bookmarks.setBookmark(tb.addr(0x55550123), "TestType", "TestCategory", "Test Comment"); } @@ -644,7 +644,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { assertEquals("Test Comment", bm.getComment()); assertEquals(DebuggerResources.ICON_DEBUGGER, type.getIcon()); - assertEquals(Color.BLUE, type.getMarkerColor()); + assertEquals(Palette.BLUE, type.getMarkerColor()); assertEquals(1, type.getMarkerPriority()); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index 4a22950b87..e8345c6468 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -17,7 +17,6 @@ package ghidra.app.plugin.core.debug.gui.listing; import static org.junit.Assert.*; -import java.awt.Color; import java.io.IOException; import java.math.BigInteger; import java.nio.ByteBuffer; @@ -31,6 +30,7 @@ import docking.menu.ActionState; import docking.menu.MultiStateDockingAction; import docking.widgets.EventTrigger; import generic.test.category.NightlyCategory; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; import ghidra.app.plugin.core.debug.DebuggerCoordinates; @@ -637,7 +637,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI // While we're here, ensure static view didn't track anywhere assertEquals(cur, codePlugin.getCurrentLocation().getAddress()); - assertListingBackgroundAt(Color.WHITE, codePlugin.getListingPanel(), + assertListingBackgroundAt(Colors.BACKGROUND, codePlugin.getListingPanel(), ss.getAddress(0x00601234), 0); } @@ -774,7 +774,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI assertListingBackgroundAt(DebuggerResources.DEFAULT_COLOR_BACKGROUND_STALE, listingProvider.getListingPanel(), tb.addr(0x00401233), 0); - assertListingBackgroundAt(Color.WHITE, listingProvider.getListingPanel(), + assertListingBackgroundAt(Colors.BACKGROUND, listingProvider.getListingPanel(), tb.addr(0x00401234), 0); assertListingBackgroundAt(DebuggerResources.DEFAULT_COLOR_BACKGROUND_ERROR, listingProvider.getListingPanel(), tb.addr(0x00401235), 0); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java index 5b365e68bc..2e7d420145 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.debug.gui.memory; -import static ghidra.lifecycle.Unfinished.TODO; +import static ghidra.lifecycle.Unfinished.*; import static org.junit.Assert.*; import java.awt.*; @@ -434,7 +434,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge } Rectangle cursor = component.getCursorBounds(); Color actual = new Color(image.getRGB(cursor.x + 8, cursor.y)); - assertEquals(expected, actual); + assertEquals(expected.getRGB(), actual.getRGB()); }); } diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AgentWindow.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AgentWindow.java index 78207f1d58..5e1c7a995a 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AgentWindow.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/agent/AgentWindow.java @@ -73,6 +73,7 @@ public class AgentWindow extends JFrame implements WindowListener, LogListener { @Override public void messageLogged(String message, boolean isError) { + Swing.runIfSwingOrRunLater(() -> { MutableAttributeSet attributes = new SimpleAttributeSet(); if (isError) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/bookmark/DBTraceBookmarkManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/bookmark/DBTraceBookmarkManager.java index e8d2df46ba..3745a39f12 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/bookmark/DBTraceBookmarkManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/bookmark/DBTraceBookmarkManager.java @@ -21,7 +21,7 @@ import java.util.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; -import javax.swing.ImageIcon; +import javax.swing.Icon; import db.DBHandle; import ghidra.program.model.address.*; @@ -236,7 +236,7 @@ public class DBTraceBookmarkManager extends AbstractDBTraceSpaceBasedManager bookmarkView; - public DBTraceBookmarkType(DBTraceBookmarkManager manager, String name, ImageIcon icon, + public DBTraceBookmarkType(DBTraceBookmarkManager manager, String name, Icon icon, Color color, int priority) { this.manager = manager; this.name = name; @@ -62,7 +63,7 @@ public class DBTraceBookmarkType implements TraceBookmarkType { } @Override - public ImageIcon getIcon() { + public Icon getIcon() { return icon; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java index 87e223097c..1b4ec34311 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java @@ -19,7 +19,7 @@ import java.awt.Color; import java.util.*; import java.util.function.Predicate; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.apache.commons.collections4.IteratorUtils; @@ -52,7 +52,7 @@ public class DBTraceProgramViewBookmarkManager implements TraceProgramViewBookma } @Override - public BookmarkType defineType(String type, ImageIcon icon, Color color, int priority) { + public BookmarkType defineType(String type, Icon icon, Color color, int priority) { return bookmarkManager.defineBookmarkType(type, icon, color, priority); } @@ -284,11 +284,11 @@ public class DBTraceProgramViewBookmarkManager implements TraceProgramViewBookma * {@link IteratorUtils#filteredIterator(Iterator, org.apache.commons.collections4.Predicate)}. * * This one understands that the predicate will be testing things of the (possibly - * more-specific) type of elements in the original iterator, not thatof the returned iterator. + * more-specific) type of elements in the original iterator, not that of the returned iterator. * - * @param it - * @param predicate - * @return + * @param it the iterator + * @param predicate the predicate + * @return the iterator */ @SuppressWarnings("unchecked") protected static Iterator filteredIterator(Iterator it, diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/bookmark/TraceBookmarkManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/bookmark/TraceBookmarkManager.java index ff7601f29d..07a5175dc0 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/bookmark/TraceBookmarkManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/bookmark/TraceBookmarkManager.java @@ -18,7 +18,7 @@ package ghidra.trace.model.bookmark; import java.awt.Color; import java.util.Collection; -import javax.swing.ImageIcon; +import javax.swing.Icon; import ghidra.program.model.address.AddressSpace; import ghidra.trace.model.stack.TraceStackFrame; @@ -45,7 +45,7 @@ public interface TraceBookmarkManager extends TraceBookmarkOperations { * the same location * @return the newly-defined type */ - TraceBookmarkType defineBookmarkType(String name, ImageIcon icon, Color color, int priority); + TraceBookmarkType defineBookmarkType(String name, Icon icon, Color color, int priority); /** * Get the defined bookmark types. diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java index c2141c5c6f..68b746630f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java @@ -17,7 +17,6 @@ package ghidra.trace.database; import static org.junit.Assert.*; -import java.awt.Color; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; @@ -29,6 +28,7 @@ import java.nio.file.Path; import java.util.Collection; import db.DBHandle; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.pcode.exec.*; import ghidra.pcode.exec.trace.TraceSleighUtils; @@ -168,7 +168,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { /** * Get the named register * - * @param the platform + * @param platform the platform * @param name the name * @return the register or null if it doesn't exist */ @@ -190,7 +190,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { /** * Create an address in the given language's default space * - * @param lang the langauge + * @param lang the language * @param offset the offset * @return the address */ @@ -252,7 +252,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { } /** - * Create an address range: shortcut for {@link new AddressRangeImpl(start, end)} + * Create an address range: shortcut for {@link AddressRangeImpl} * * @param start the start address * @param end the end address @@ -444,7 +444,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { */ public DBTraceBookmarkType getOrAddBookmarkType(String name) { DBTraceBookmarkManager manager = trace.getBookmarkManager(); - return manager.defineBookmarkType(name, null, Color.red, 1); + return manager.defineBookmarkType(name, null, Messages.ERROR, 1); } /** @@ -477,7 +477,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { * * @param snap the starting snap * @param threadName the name of the thread - * @param registerName the name of the regsiter + * @param registerName the name of the register * @param typeName the name of its type * @param category the category * @param comment an optional comment @@ -549,11 +549,12 @@ public class ToyDBTraceBuilder implements AutoCloseable { public DBTraceInstruction addInstruction(long snap, Address start, TracePlatform platform) throws CodeUnitInsertionException { DBTraceCodeManager code = trace.getCodeManager(); - Language language = platform.getLanguage(); - Disassembler dis = Disassembler.getDisassembler(language, language.getAddressFactory(), - new ConsoleTaskMonitor(), msg -> Msg.info(this, "Listener: " + msg)); + Language platformLanguage = platform.getLanguage(); + Disassembler dis = + Disassembler.getDisassembler(platformLanguage, platformLanguage.getAddressFactory(), + new ConsoleTaskMonitor(), msg -> Msg.info(this, "Listener: " + msg)); RegisterValue defaultContextValue = trace.getRegisterContextManager() - .getDefaultContext(language) + .getDefaultContext(platformLanguage) .getDefaultDisassemblyContext(); MemBuffer memBuf = platform.getMappedMemBuffer(snap, platform.mapHostToGuest(start)); @@ -725,10 +726,10 @@ public class ToyDBTraceBuilder implements AutoCloseable { } /** - * Get the language with the given ID, as in {@link LangaugeID} + * Get the language with the given ID, as in {@link LanguageID} * * @param id the ID - * @return the langauge + * @return the language * @throws LanguageNotFoundException if the language does not exist */ public Language getLanguage(String id) throws LanguageNotFoundException { @@ -742,7 +743,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { * @param compID the compiler ID as in {@link CompilerSpecID} * @return the compiler spec * @throws CompilerSpecNotFoundException if the compiler spec does not exist - * @throws LanguageNotFoundException if the langauge does not exist + * @throws LanguageNotFoundException if the language does not exist */ public CompilerSpec getCompiler(String langID, String compID) throws CompilerSpecNotFoundException, LanguageNotFoundException { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java index 13dd374b27..7a5ccf36cf 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/framework/options/AutoOptions.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ImmutableList; import generic.ComparableTupleRecord; +import generic.theme.GColor; import ghidra.framework.options.annotation.*; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; @@ -165,6 +166,7 @@ public interface AutoOptions { catch (IllegalArgumentException | IllegalAccessException e) { throw new AssertionError(e); } + OptionType type = annotation.type(); if (type == OptionType.NO_TYPE) { type = OptionType.getOptionType(defaultValue); @@ -175,6 +177,7 @@ public interface AutoOptions { "Could not determine option type from default value: " + f + " = " + defaultValue); } + String description = annotation.description(); Class editorClass = annotation.editor(); final PropertyEditor editor; @@ -191,9 +194,28 @@ public interface AutoOptions { "editor class must have accessible default constructor", e); } } - options.registerOption(key.getName(), type, defaultValue, help, description, editor); - // TODO: Wish Ghidra would do this upon any option registration - options.putObject(key.getName(), defaultValue, type); + + if (defaultValue instanceof GColor gColor) { + options.registerThemeColorBinding(key.getName(), gColor.getId(), help, description); + } + /* + else if ( is font option ) { + + // Note: there is no font value to check against for fonts in the new Theme system. + // If annotation fonts are needed, then they should be bound by String id. Likely, + // annotation fonts are not needed now that have themes. We also probably no + // longer need annotation colors either. + + options.registerThemeFontBinding(description, fontId, help, description); + } + */ + else { + options.registerOption(key.getName(), type, defaultValue, help, description, + editor); + // TODO: Wish Ghidra would do this upon any option registration + options.putObject(key.getName(), defaultValue, type); + } + } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UIManagerWrapper.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UIManagerWrapper.java deleted file mode 100644 index e149b6ef50..0000000000 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UIManagerWrapper.java +++ /dev/null @@ -1,60 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.util; - -import java.awt.Color; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.*; -import javax.swing.border.Border; - -public class UIManagerWrapper { - - private static Map colorMap = new HashMap<>(); - private static Map borderMap = new HashMap<>(); - - static { - colorMap.put("Table[Enabled+Selected].textForeground", new Color(255, 255, 255)); - colorMap.put("Table[Enabled+Selected].textBackground", new Color(57, 105, 138)); - colorMap.put("Table.textForeground", new Color(35, 35, 36)); - colorMap.put("Table.alternateRowColor", new Color(237, 243, 254)); - colorMap.put("Table:\"Table.cellRenderer\".background", new Color(255, 255, 255)); - - borderMap.put("Table.focusCellHighlightBorder", - BorderFactory.createEmptyBorder(2, 5, 2, 5)); - borderMap.put("Table.cellNoFocusBorder", BorderFactory.createEmptyBorder(2, 5, 2, 5)); - } - - public static Color getColor(String text) { - UIDefaults uiDefaults = UIManager.getDefaults(); - Color color = uiDefaults.getColor(text); - if (color == null) { - color = colorMap.get(text); - } - return color; - } - - public static Border getBorder(String text) { - UIDefaults uiDefaults = UIManager.getDefaults(); - Border border = uiDefaults.getBorder(text); - if (border == null) { - border = borderMap.get(text); - } - return border; - } - -} diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java index a67cd90c76..e38175c4ae 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java @@ -17,7 +17,6 @@ package ghidra.util.database.spatial; import static org.junit.Assert.*; -import java.awt.Color; import java.awt.Graphics; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -41,6 +40,8 @@ import com.google.common.collect.Iterators; import db.DBHandle; import db.DBRecord; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.util.ColorUtils; import ghidra.util.LockHold; import ghidra.util.database.*; import ghidra.util.database.annot.*; @@ -565,13 +566,13 @@ public class RStarTreeMapTest { public void selectColor(Graphics g, NodeType type) { if (type.isLeaf()) { - g.setColor(new Color(1, 0, 0, 0.5f).darker()); + g.setColor(ColorUtils.getColor(179, 0, 0, 128)); } else if (type.isLeafParent()) { - g.setColor(new Color(0, 1, 0, 0.5f).darker()); + g.setColor(ColorUtils.getColor(0, 179, 0, 128)); } else { - g.setColor(new Color(0, 0, 1, 0.5f).darker()); + g.setColor(ColorUtils.getColor(0, 0, 179, 128)); } } @@ -581,14 +582,14 @@ public class RStarTreeMapTest { return; } drawPath(g, getParentOf(nr)); - g.setColor(Color.BLACK); + g.setColor(Palette.BLACK); drawRect(g, nr.getShape(), false); } public void drawPath(Graphics g, DBIntRectStringDataRecord dr) { System.out.println("Selected: " + dr); drawPath(g, getParentOf(dr)); - g.setColor(Color.BLACK); + g.setColor(Palette.BLACK); drawRect(g, dr.getBounds(), false); } @@ -609,7 +610,7 @@ public class RStarTreeMapTest { @Override protected VisitResult visitData(DBIntRectNodeRecord parent, DBIntRectStringDataRecord d, boolean included) { - g.setColor(new Color(0, 0, 0, 0.5f)); + g.setColor(ColorUtils.getColor(0, 0, 0, 128)); drawRect(g, d.getShape(), true); return VisitResult.NEXT; } @@ -875,7 +876,6 @@ public class RStarTreeMapTest { List> entries = generateRandom(rect(0, 100, 0, 100), 10, 10, 1000); Consumer>> inserter = list -> { try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRandom")) { - int i = 0; for (Entry ent : list) { obj.map.put(ent.getKey(), ent.getValue()); // Note, underlying tree is not synchronized, but map is diff --git a/Ghidra/Extensions/SampleTablePlugin/certification.manifest b/Ghidra/Extensions/SampleTablePlugin/certification.manifest index b9b2c11b56..dc315f04e3 100644 --- a/Ghidra/Extensions/SampleTablePlugin/certification.manifest +++ b/Ghidra/Extensions/SampleTablePlugin/certification.manifest @@ -3,6 +3,7 @@ ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||reviewed||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/sampletableplugin.theme.properties||GHIDRA||||END| extension.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END| diff --git a/Ghidra/Extensions/SampleTablePlugin/data/sampletableplugin.theme.properties b/Ghidra/Extensions/SampleTablePlugin/data/sampletableplugin.theme.properties new file mode 100644 index 0000000000..b001219c91 --- /dev/null +++ b/Ghidra/Extensions/SampleTablePlugin/data/sampletableplugin.theme.properties @@ -0,0 +1,3 @@ +[Defaults] +icon.sample.plugin.action.show.options = table.png +icon.sample.plugin.action.save = disk.png \ No newline at end of file diff --git a/Ghidra/Extensions/SampleTablePlugin/src/main/help/help/shared/Frontpage.css b/Ghidra/Extensions/SampleTablePlugin/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Extensions/SampleTablePlugin/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Extensions/SampleTablePlugin/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java b/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java index 6d071a29a7..530d0f762b 100644 --- a/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java +++ b/Ghidra/Extensions/SampleTablePlugin/src/main/java/ghidra/examples/SampleTableProvider.java @@ -27,6 +27,7 @@ import docking.action.*; import docking.widgets.checkbox.GCheckBox; import docking.widgets.filechooser.GhidraFileChooserPanel; import docking.widgets.table.GFilterTable; +import generic.theme.GIcon; import ghidra.framework.options.OptionsChangeListener; import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -34,7 +35,6 @@ import ghidra.framework.plugintool.util.OptionsService; import ghidra.util.*; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.layout.MiddleLayout; -import resources.ResourceManager; public class SampleTableProvider extends ComponentProviderAdapter implements OptionsChangeListener { @@ -154,7 +154,7 @@ public class SampleTableProvider extends ComponentProviderAdapter implements Opt } }; - ImageIcon icon = ResourceManager.loadImage("images/table.png"); + Icon icon = new GIcon("icon.sample.plugin.action.show.options"); optionsAction.setToolBarData(new ToolBarData(icon)); DockingAction saveTableDataAction = new DockingAction("Save Table Data", plugin.getName()) { @@ -189,7 +189,7 @@ public class SampleTableProvider extends ComponentProviderAdapter implements Opt return SwingUtilities.isDescendingFrom((Component) sourceObject, filterTable); } }; - icon = ResourceManager.loadImage("images/disk.png"); + icon = new GIcon("icons.sample.plugin.action.save"); saveTableDataAction.setToolBarData(new ToolBarData(icon)); saveTableDataAction.setPopupMenuData(new MenuData(new String[] { "Save Data" })); diff --git a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java index 89f3407db2..6231750e8c 100644 --- a/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java +++ b/Ghidra/Extensions/SleighDevTools/src/main/java/ghidra/app/util/disassemble/ExternalDisassemblyFieldFactory.java @@ -15,13 +15,14 @@ */ package ghidra.app.util.disassemble; -import java.awt.Color; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors.Messages; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.field.*; import ghidra.app.util.viewer.format.FieldFormatModel; @@ -130,7 +131,7 @@ public class ExternalDisassemblyFieldFactory extends FieldFactory { if (disassembly == null) { return null; } - AttributedString text = new AttributedString(disassembly, Color.black, getMetrics()); + AttributedString text = new AttributedString(disassembly, Palette.BLACK, getMetrics()); FieldElement fieldElement = new TextFieldElement(text, 0, 0); return ListingTextField.createSingleLineTextField(this, proxy, fieldElement, startX + varWidth, width, hlProvider); @@ -162,7 +163,7 @@ public class ExternalDisassemblyFieldFactory extends FieldFactory { if (message == null) { message = e.toString(); } - AttributedString errorText = new AttributedString(message, Color.red, getMetrics()); + AttributedString errorText = new AttributedString(message, Messages.ERROR, getMetrics()); FieldElement fieldElement = new TextFieldElement(errorText, 0, 0); return ListingTextField.createSingleLineTextField(this, proxy, fieldElement, startX + varWidth, width, hlProvider); diff --git a/Ghidra/Extensions/sample/certification.manifest b/Ghidra/Extensions/sample/certification.manifest index f76dd9c0ce..0f1a49b26c 100644 --- a/Ghidra/Extensions/sample/certification.manifest +++ b/Ghidra/Extensions/sample/certification.manifest @@ -3,6 +3,7 @@ ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||reviewed||END| data/README.txt||GHIDRA||||END| +data/sample.theme.properties||GHIDRA||||END| extension.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END| diff --git a/Ghidra/Extensions/sample/data/sample.theme.properties b/Ghidra/Extensions/sample/data/sample.theme.properties new file mode 100644 index 0000000000..02d966ddc8 --- /dev/null +++ b/Ghidra/Extensions/sample/data/sample.theme.properties @@ -0,0 +1,13 @@ +[Defaults] +icon.sample.provider = erase16.png +icon.sample.provider.graph = color_swatch.png +icon.sample.provider.hello.world = information.png + +icon.sample.action.hello.world = information.png +icon.sample.kitchen.sink.action.hellow.world = left.png +icon.sample.kitchen.sink.action.hellow.program = right.png + +icon.sample.action.show.graph = applications-development.png + +icon.sample.graph.dependency.layout = color_swatch.png +icon.sample.hello.world.action.clear = erase16.png \ No newline at end of file diff --git a/Ghidra/Extensions/sample/src/main/help/help/shared/Frontpage.css b/Ghidra/Extensions/sample/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Extensions/sample/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Extensions/sample/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/HelloWorldComponentProvider.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/HelloWorldComponentProvider.java index 415543874b..f0701444f8 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/HelloWorldComponentProvider.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/HelloWorldComponentProvider.java @@ -24,14 +24,13 @@ import docking.ActionContext; import docking.WindowPosition; import docking.action.*; import docking.widgets.EmptyBorderButton; +import generic.theme.GIcon; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; import ghidra.util.Msg; -import resources.ResourceManager; public class HelloWorldComponentProvider extends ComponentProviderAdapter { - private final static String PREV_IMAGE = "images/information.png"; private final static HelpLocation HELP = new HelpLocation("SampleHelpTopic", "SampleHelpTopic_Anchor_Name"); private MyButton activeButtonObj; @@ -41,7 +40,7 @@ public class HelloWorldComponentProvider extends ComponentProviderAdapter { public HelloWorldComponentProvider(PluginTool tool, String name) { super(tool, name, name); buildMainPanel(); - setIcon(ResourceManager.loadImage("images/erase16.png")); + setIcon(new GIcon("icon.sample.provider")); setHelpLocation(HELP); setDefaultWindowPosition(WindowPosition.WINDOW); setTitle("Hello World Component"); @@ -64,13 +63,13 @@ public class HelloWorldComponentProvider extends ComponentProviderAdapter { // put in Menu called "Hello", with Menu item of "World". Since this will be a local action // the menu item will appear on the local toolbar drop down. - ImageIcon prevImage = ResourceManager.loadImage(PREV_IMAGE); - action.setMenuBarData(new MenuData(new String[] { "Misc", "Hello World" }, prevImage)); + Icon icon = new GIcon("icon.sample.action.hello.world"); + action.setMenuBarData(new MenuData(new String[] { "Misc", "Hello World" }, icon)); action.setKeyBindingData(new KeyBindingData(KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_MASK))); // puts the action on the local toolbar. - action.setToolBarData(new ToolBarData(prevImage)); + action.setToolBarData(new ToolBarData(icon)); action.setDescription("Hello World"); // set the help URL for the action @@ -123,7 +122,7 @@ public class HelloWorldComponentProvider extends ComponentProviderAdapter { panel.setBorder(BorderFactory.createTitledBorder("Example of a Component")); activeButtonObj = new MyButton("Hello World"); Font f = activeButtonObj.getFont(); - activeButtonObj.setFont(new Font(f.getFontName(), Font.BOLD, 14)); + activeButtonObj.setFont(f.deriveFont(Font.BOLD, 14)); panel.add(activeButtonObj); mainPanel.add(panel, BorderLayout.CENTER); } diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/KitchenSinkPlugin.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/KitchenSinkPlugin.java index dcfd61bd58..36ab7f00e7 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/KitchenSinkPlugin.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/KitchenSinkPlugin.java @@ -15,6 +15,14 @@ */ package ghidra.examples; +import java.awt.Event; +import java.awt.event.KeyEvent; + +import javax.swing.*; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.app.ExamplesPluginPackage; import ghidra.app.events.ProgramLocationPluginEvent; import ghidra.app.plugin.PluginCategoryNames; @@ -28,15 +36,6 @@ import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import ghidra.util.Msg; -import java.awt.Event; -import java.awt.event.KeyEvent; - -import javax.swing.*; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - /** * Class description goes here * @@ -54,120 +53,120 @@ import docking.action.*; ) //@formatter:on public class KitchenSinkPlugin extends ProgramPlugin { - private final static String NEXT_IMAGE = "images/right.png"; - private final static String PREV_IMAGE = "images/left.png"; - private DockingAction helloProgramAction; - private Program program; + private DockingAction helloProgramAction; + private Program program; - /** - * Constructor - */ - public KitchenSinkPlugin(PluginTool tool) { + /** + * Constructor + */ + public KitchenSinkPlugin(PluginTool tool) { - super(tool); + super(tool); - // set up list of services. - setupServices(); + // set up list of services. + setupServices(); - // set up list of actions. - setupActions(); - } - - private void setupServices() { - registerServiceProvided(HelloWorldService.class, - new HelloWorldService() { - public void sayHello() { - announce("Hello"); - } - }); - } - - private void setupActions() { - DockingAction action = new DockingAction("Hello World", getName() ) { - @Override - public void actionPerformed( ActionContext context ) { - Msg.info(this, "Hello World:: action"); - announce("Hello World"); - } - }; - action.setEnabled( true ); - String helloGroup = "Hello"; - ImageIcon prevImage = ResourceManager.loadImage(PREV_IMAGE); - action.setMenuBarData( new MenuData( new String[] {"Misc", "Hello World"}, prevImage, helloGroup ) ); - action.setPopupMenuData( new MenuData( new String[] {"Hello World"}, prevImage, helloGroup ) ); - action.setKeyBindingData( new KeyBindingData( KeyStroke.getKeyStroke('H', Event.CTRL_MASK ) ) ); - action.setToolBarData( new ToolBarData( prevImage, helloGroup ) ); - action.setDescription("Hello World"); - action.setHelpLocation(new HelpLocation("SampleHelpTopic", "KS_Hello_World")); - - tool.addAction(action); - - action = new DockingAction("Hello Program", getName() ) { - @Override - public void actionPerformed( ActionContext context ) { - Msg.info(this, "Hello Program:: action"); - sayHelloProgram(); - } - }; - action.setEnabled(false); - ImageIcon nextImage = ResourceManager.loadImage(NEXT_IMAGE); - action.setMenuBarData( new MenuData( new String[]{"Misc", "Hello Program"}, nextImage, helloGroup ) ); - action.setKeyBindingData( new KeyBindingData( KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK ) ) ); - action.setToolBarData( new ToolBarData( nextImage, helloGroup ) ); - action.setDescription("Hello Program"); - action.setHelpLocation(new HelpLocation("SampleHelpTopic", "KS_Hello_Program")); - tool.addAction(action); - - // remember this action so I can enable/disable it later - helloProgramAction = action; - } - - @Override - protected void programActivated(Program activatedProgram) { - helloProgramAction.setEnabled(true); - this.program = activatedProgram; + // set up list of actions. + setupActions(); } + + private void setupServices() { + registerServiceProvided(HelloWorldService.class, + new HelloWorldService() { + public void sayHello() { + announce("Hello"); + } + }); + } + + private void setupActions() { + DockingAction action = new DockingAction("Hello World", getName()) { + @Override + public void actionPerformed(ActionContext context) { + Msg.info(this, "Hello World:: action"); + announce("Hello World"); + } + }; + action.setEnabled(true); + String helloGroup = "Hello"; + Icon prevImage = new GIcon("icon.sample.kitchen.sink.action.hello.world"); + action.setMenuBarData( + new MenuData(new String[] { "Misc", "Hello World" }, prevImage, helloGroup)); + action.setPopupMenuData( + new MenuData(new String[] { "Hello World" }, prevImage, helloGroup)); + action.setKeyBindingData(new KeyBindingData(KeyStroke.getKeyStroke('H', Event.CTRL_MASK))); + action.setToolBarData(new ToolBarData(prevImage, helloGroup)); + action.setDescription("Hello World"); + action.setHelpLocation(new HelpLocation("SampleHelpTopic", "KS_Hello_World")); + + tool.addAction(action); + + action = new DockingAction("Hello Program", getName()) { + @Override + public void actionPerformed(ActionContext context) { + Msg.info(this, "Hello Program:: action"); + sayHelloProgram(); + } + }; + action.setEnabled(false); + Icon nextImage = new GIcon("icon.sample.kitchen.sink.action.hello.program"); + action.setMenuBarData( + new MenuData(new String[] { "Misc", "Hello Program" }, nextImage, helloGroup)); + action.setKeyBindingData( + new KeyBindingData(KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK))); + action.setToolBarData(new ToolBarData(nextImage, helloGroup)); + action.setDescription("Hello Program"); + action.setHelpLocation(new HelpLocation("SampleHelpTopic", "KS_Hello_Program")); + tool.addAction(action); + + // remember this action so I can enable/disable it later + helloProgramAction = action; + } + @Override - protected void programDeactivated(Program deactivatedProgram) { + protected void programActivated(Program activatedProgram) { + helloProgramAction.setEnabled(true); + this.program = activatedProgram; + } + + @Override + protected void programDeactivated(Program deactivatedProgram) { if (this.program == deactivatedProgram) { helloProgramAction.setEnabled(false); this.program = null; } } - protected void sayHelloProgram() { - if (program == null) { - return; - } + protected void sayHelloProgram() { - announce("Hello " + program.getName()); - } + if (program == null) { + return; + } - protected void announce(String message) { - JOptionPane.showMessageDialog(null,message,"Hello World", - JOptionPane.INFORMATION_MESSAGE); - } - - /** + announce("Hello " + program.getName()); + } + + protected void announce(String message) { + JOptionPane.showMessageDialog(null, message, "Hello World", + JOptionPane.INFORMATION_MESSAGE); + } + + /** * If your plugin maintains configuration state, you must save that state information - * to the SaveState object in this method. For example, the Code Browser can be configured - * to show fields in different colors. This is the method where that type - * information is saved. + * to the SaveState object in this method. For example, the Code Browser can be configured + * to show fields in different colors. This is the method where that type + * information is saved. */ - @Override - public void writeConfigState(SaveState saveState) { - } + @Override + public void writeConfigState(SaveState saveState) { + } + /** * If your plugin maintains configuration state, this is where you read it - * back in. + * back in. */ - @Override - public void readConfigState(SaveState saveState) { - } + @Override + public void readConfigState(SaveState saveState) { + } } - - - - - diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/ShowInfoComponentProvider.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/ShowInfoComponentProvider.java index c1b5de8566..6e61ae6b17 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/ShowInfoComponentProvider.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/ShowInfoComponentProvider.java @@ -23,15 +23,15 @@ import docking.ActionContext; import docking.WindowPosition; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.listing.*; import ghidra.program.util.ProgramLocation; -import resources.ResourceManager; public class ShowInfoComponentProvider extends ComponentProviderAdapter { - private final static ImageIcon CLEAR_ICON = ResourceManager.loadImage("images/erase16.png"); - private final static ImageIcon INFO_ICON = ResourceManager.loadImage("images/information.png"); + private final static Icon CLEAR_ICON = new GIcon("icon.sample.hello.world.action.clear"); + private final static Icon PROVIDER_ICON = new GIcon("icon.sample.provider.hello.world"); private JPanel panel; private JTextArea textArea; @@ -42,7 +42,7 @@ public class ShowInfoComponentProvider extends ComponentProviderAdapter { public ShowInfoComponentProvider(PluginTool tool, String name) { super(tool, name, name); create(); - setIcon(INFO_ICON); + setIcon(PROVIDER_ICON); setDefaultWindowPosition(WindowPosition.BOTTOM); setTitle("Show Info"); setVisible(true); diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphPlugin.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphPlugin.java index 8b5bb9b706..8ce17a82d1 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphPlugin.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphPlugin.java @@ -15,17 +15,17 @@ */ package ghidra.examples.graph; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.ExamplesPluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * Sample plugin to demonstrate a plugin with a dockable GUI graph component @@ -64,8 +64,7 @@ public class SampleGraphPlugin extends Plugin { showProvider(); } }; - - ImageIcon icon = ResourceManager.loadImage("images/applications-development.png"); + Icon icon = new GIcon("icon.sample.action.show.graph"); showProviderAction.setToolBarData(new ToolBarData(icon, "View")); showProviderAction.setHelpLocation(DEFAULT_HELP); tool.addAction(showProviderAction); @@ -75,7 +74,6 @@ public class SampleGraphPlugin extends Plugin { provider.setVisible(true); } - @Override protected void dispose() { provider.dispose(); diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphLayoutProvider.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphLayoutProvider.java index 8bb3a27ec5..9e09fefab3 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphLayoutProvider.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphLayoutProvider.java @@ -21,12 +21,12 @@ import java.util.Collection; import javax.swing.Icon; import edu.uci.ics.jung.algorithms.layout.Layout; +import generic.theme.GIcon; import ghidra.examples.graph.*; import ghidra.graph.viewer.layout.AbstractLayoutProvider; import ghidra.graph.viewer.layout.VisualGraphLayout; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * The layout provider for the {@link SampleGraphPlugin}. @@ -34,7 +34,7 @@ import resources.ResourceManager; public abstract class SampleGraphLayoutProvider extends AbstractLayoutProvider { - private static final Icon DEFAULT_ICON = ResourceManager.loadImage("images/color_swatch.png"); + private static final Icon DEFAULT_ICON = new GIcon("icon.sample.provider.graph"); @Override public abstract VisualGraphLayout getLayout(SampleGraph g, diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphPluginDependencyLayoutProvider.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphPluginDependencyLayoutProvider.java index 612f7a18cb..14b7bd72a7 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphPluginDependencyLayoutProvider.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/layout/SampleGraphPluginDependencyLayoutProvider.java @@ -17,12 +17,12 @@ package ghidra.examples.graph.layout; import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.examples.graph.*; import ghidra.graph.viewer.layout.AbstractLayoutProvider; import ghidra.graph.viewer.layout.VisualGraphLayout; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * A layout provider for the {@link SampleGraphPlugin} @@ -31,7 +31,7 @@ public class SampleGraphPluginDependencyLayoutProvider extends AbstractLayoutProvider { private static final String NAME = "Plugin Dependency Layout"; - private static final Icon DEFAULT_ICON = ResourceManager.loadImage("images/color_swatch.png"); + private static final Icon DEFAULT_ICON = new GIcon("icon.sample.graph.dependency.layout"); @Override public VisualGraphLayout getLayout(SampleGraph g, TaskMonitor monitor) diff --git a/Ghidra/Features/Base/build.gradle b/Ghidra/Features/Base/build.gradle index e5340b1370..0ea023e9e2 100644 --- a/Ghidra/Features/Base/build.gradle +++ b/Ghidra/Features/Base/build.gradle @@ -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' } diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 614ae99c4f..11ab2393b2 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -16,7 +16,10 @@ data/ElfFunctionsThatDoNotReturn||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| data/MachOFunctionsThatDoNotReturn||GHIDRA||||END| data/PEFunctionsThatDoNotReturn||GHIDRA||||END| -data/file_extension_icons.xml||GHIDRA||||END| +data/base.icons.theme.properties||GHIDRA||||END| +data/base.listing.theme.properties||GHIDRA||||END| +data/base.programgraph.theme.properties||GHIDRA||||END| +data/base.theme.properties||GHIDRA||||END| data/functionTags.xml||GHIDRA||||END| data/ms_pe_rich_products.xml||GHIDRA||||END| data/noReturnFunctionConstraints.xml||GHIDRA||||END| @@ -77,6 +80,7 @@ data/symbols/win64/mfc80u.exports||GHIDRA||||END| data/symbols/win64/mfc90.exports||GHIDRA||||END| data/symbols/win64/mfc90u.exports||GHIDRA||||END| data/symbols/win64/msvcrt.hints||GHIDRA||||END| +data/typeinfo/base.file.extensions.icons.theme.properties||GHIDRA||||END| data/typeinfo/generic/generic_clib.gdt||GHIDRA||||END| data/typeinfo/generic/generic_clib_64.gdt||GHIDRA||||END| data/typeinfo/mac_10.9/mac_osx.gdt||GHIDRA||||END| @@ -998,8 +1002,6 @@ src/main/resources/images/cloudbar.jpg||GHIDRA||reviewed||END| src/main/resources/images/cloudbarReversed.jpg||GHIDRA||reviewed||END| src/main/resources/images/codeInView.gif||GHIDRA||||END| src/main/resources/images/codeNotInView.gif||GHIDRA||||END| -src/main/resources/images/collapse.gif||GHIDRA||||END| -src/main/resources/images/collapse_all.png||GHIDRA||||END| src/main/resources/images/conflictKeep.png||GHIDRA||||END| src/main/resources/images/conflictRename.png||GHIDRA||||END| src/main/resources/images/conflictReplace.png||GHIDRA||||END| @@ -1029,8 +1031,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/expand.gif||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| @@ -1049,7 +1049,6 @@ src/main/resources/images/famfamfam_silk_icons_v013/cup.png||FAMFAMFAM Icons - C src/main/resources/images/famfamfam_silk_icons_v013/database.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/famfamfam_silk_icons_v013/door.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/famfamfam_silk_icons_v013/door_open.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| -src/main/resources/images/famfamfam_silk_icons_v013/drive.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/famfamfam_silk_icons_v013/folder_brick.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/famfamfam_silk_icons_v013/folder_table.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/famfamfam_silk_icons_v013/html.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| @@ -1070,6 +1069,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| @@ -1089,11 +1090,7 @@ src/main/resources/images/ledgreen.png||Nuvola Icons - LGPL 2.1|||Nuvola icon se src/main/resources/images/ledred.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| src/main/resources/images/ledyellow.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| src/main/resources/images/link.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| -src/main/resources/images/list-remove.png||Oxygen Icons - LGPL 3.0||||END| -src/main/resources/images/locationIn.gif||GHIDRA||||END| -src/main/resources/images/locationOut.gif||GHIDRA||||END| src/main/resources/images/lock.gif||GHIDRA||||END| -src/main/resources/images/lock.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/magnifier.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/media-flash.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/media-playback-stop.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| @@ -1101,6 +1098,7 @@ src/main/resources/images/mem_chip3.png||GHIDRA||reviewed||END| src/main/resources/images/memory16.gif||GHIDRA||||END| src/main/resources/images/menu16.gif||GHIDRA||||END| src/main/resources/images/move.png||GHIDRA||||END| +src/main/resources/images/no_small.png||GHIDRA||||END| src/main/resources/images/notF.gif||GHIDRA||||END| src/main/resources/images/notes.gif||GHIDRA||||END| src/main/resources/images/nuvola/16x16/cdimage.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| @@ -1134,7 +1132,6 @@ src/main/resources/images/oxygen/16x16/text-x-bibtex.png||Oxygen Icons - LGPL 3. src/main/resources/images/oxygen/16x16/text-x-c++src.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/oxygen/16x16/text-x-chdr.png||Oxygen Icons - LGPL 3.0||||END| src/main/resources/images/oxygen/16x16/text-x-csharp.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/resources/images/oxygen/16x16/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/oxygen/16x16/text-x-pascal.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/oxygen/16x16/text-xml.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/oxygen/48x48/multimedia-player-apple-ipod.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| @@ -1142,14 +1139,12 @@ 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| src/main/resources/images/pin.png||GHIDRA||||END| src/main/resources/images/pinkX.gif||GHIDRA||||END| -src/main/resources/images/plasma.png||Oxygen Icons - LGPL 3.0||||END| -src/main/resources/images/play.png||GHIDRA||||END| src/main/resources/images/play_again.png||GHIDRA||||END| src/main/resources/images/preferences-system.png||Tango Icons - Public Domain|||tango|END| src/main/resources/images/question_zero.png||GHIDRA||||END| @@ -1172,10 +1167,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| @@ -1193,15 +1189,11 @@ src/main/resources/images/view-sort-ascending.png||Oxygen Icons - LGPL 3.0|||Oxy src/main/resources/images/view-sort-descending.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/viewedCode.gif||GHIDRA||||END| src/main/resources/images/viewmag.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| -src/main/resources/images/viewmagfit.png||Nuvola Icons - LGPL 2.1|||Nuvola|END| src/main/resources/images/warning.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/resources/images/wizard.png||Nuvola Icons - LGPL 2.1|||nuvola|END| src/main/resources/images/x-office-document-template.png||Tango Icons - Public Domain|||tango icon set|END| src/main/resources/images/x.gif||GHIDRA||||END| src/main/resources/images/xor.png||GHIDRA||||END| -src/main/resources/images/zoom.png||FAMFAMFAM Icons - CC 2.5|||silk|END| -src/main/resources/images/zoom_in.png||FAMFAMFAM Icons - CC 2.5|||silk|END| -src/main/resources/images/zoom_out.png||FAMFAMFAM Icons - CC 2.5|||silk|END| src/main/resources/pcodetest/chunk1.hinc||GHIDRA||||END| src/main/resources/pcodetest/chunk2.hinc||GHIDRA||||END| src/main/resources/pcodetest/chunk3.hinc||GHIDRA||||END| diff --git a/Ghidra/Features/Base/data/base.icons.theme.properties b/Ghidra/Features/Base/data/base.icons.theme.properties new file mode 100644 index 0000000000..9eac0906ca --- /dev/null +++ b/Ghidra/Features/Base/data/base.icons.theme.properties @@ -0,0 +1,401 @@ + +[Defaults] + +icon.base.delete = icon.delete +icon.base.plus = icon.add +icon.base.edit.bytes = editbytes.gif +icon.base.pinned = pin.png +icon.base.hover.off = hoverOff.gif +icon.base.hover.on = hoverOn.gif +icon.base.lock = lock.gif +icon.base.unlock = unlock.gif +icon.base.source.c = text-x-csrc.png + +icon.base.search.marker = searchm_obj.gif + +icon.base.application.home = GhidraIcon16.png +icon.base.application.16 = GhidraIcon16.png +icon.base.application.24 = GhidraIcon24.png +icon.base.application.32 = GhidraIcon32.png +icon.base.application.40 = GhidraIcon40.png +icon.base.application.48 = GhidraIcon48.png +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 +icon.plugin.datatypes.built.in.disabled = package_development.png [disabled] +icon.plugin.datatypes.default = defaultDt.gif +icon.plugin.datatypes.default.disabled = disabledCode.gif +icon.plugin.datatypes.enum = enum.png +icon.plugin.datatypes.pointer = fingerPointer.png +icon.plugin.datatypes.function = functionDef.png +icon.plugin.datatypes.union = cUnion.png +icon.plugin.datatypes.typedef = typedef.png +icon.plugin.datatypes.structure = cstruct.png + +icon.plugin.assembler.question = question_zero.png + +icon.plugin.bookmark.add = icon.check +icon.plugin.bookmark.delete = icon.base.delete +icon.plugin.bookmark.select = text_align_justify.png +icon.plugin.bookmark.type.note = notes.gif +icon.plugin.bookmark.type.info = icon.information +icon.plugin.bookmark.type.warning = icon.warning +icon.plugin.bookmark.type.error = icon.base.delete +icon.plugin.bookmark.type.analysis = applications-system.png +icon.plugin.bookmark.type.default = unknown.gif + +icon.plugin.calltree.function = FunctionScope.gif +icon.plugin.calltree.recursive = arrow_rotate_clockwise.png +icon.plugin.calltree.refresh = icon.refresh +icon.plugin.calltree.refresh.not.needed = icon.plugin.calltree.refresh [disabled] +icon.plugin.calltree.filter.duplicates = application_double.png +icon.plugin.calltree.filter.select.source = text_align_justify.png +icon.plugin.calltree.node.dead.end = stopNode.png +icon.plugin.calltree.node.external = package.png + +icon.plugin.checksum.compute = icon.refresh +icon.plugin.checksum.select = NextSelectionBlock16.gif +icon.plugin.checksum.show.hex = hexData.png +icon.plugin.checksum.xor = xor.png +icon.plugin.checksum.carry = carry.png +icon.plugin.checksum.ones.complement = onesComplement.png +icon.plugin.checksum.twos.complement = twosComplement.png + +icon.plugin.clipboard.copy = icon.copy +icon.plugin.clipboard.paste = icon.paste + +icon.plugin.codebrowser.cursor.location = cursor_arrow_flipped.gif +icon.plugin.codebrowser.cursor.marker = searchm_obj.gif +icon.plugin.codebrowser.format.collapse =field.header.up.png +icon.plugin.codebrowser.format.expand = field.header.down.png +icon.plugin.codebrowser.hover.off = icon.base.hover.off +icon.plugin.codebrowser.hover.on = icon.base.hover.on +icon.plugin.codebrowser.provider = Browser.gif +icon.plugin.codebrowser.mark.and.select.armed = MarkSelection.png {media-playback-start.png[size(12,12)][move(4,4)]} +icon.plugin.codebrowser.mark.and.select.unarmed = MarkSelection.png {media-playback-stop.png[size(12,12)][move(4,4)]} + +icon.plugin.composite.editor.provider = accessories-text-editor.png +icon.plugin.composite.editor.provider.structure = icon.plugin.datatypes.structure +icon.plugin.composite.editor.provider.union = cUnion.png +icon.plugin.composite.editor.apply = disk.png +icon.plugin.composite.editor.array = Array.png +icon.plugin.composite.editor.bit.field.dialog.add = icon.base.plus +icon.plugin.composite.editor.bit.field.dialog.delete = icon.base.delete +icon.plugin.composite.editor.bit.field.dialog.edit = move.png +icon.plugin.composite.editor.bit.field.editor.decrement = Minus.png +icon.plugin.composite.editor.bit.field.editor.increment = icon.base.plus +icon.plugin.composite.editor.clear = icon.clear +icon.plugin.composite.editor.create = icon.plugin.datatypes.structure +icon.plugin.composite.editor.delete = icon.base.delete +icon.plugin.composite.editor.duplicate = DuplicateData.png +icon.plugin.composite.editor.duplicate.multiple = MultiDuplicateData.png +icon.plugin.composite.editor.insert.undefined = icon.base.plus +icon.plugin.composite.editor.move.down = down.png +icon.plugin.composite.editor.move.up = up.png +icon.plugin.composite.editor.search.next = go-down.tango.16.png [size(16,16)] +icon.plugin.composite.editor.search.previous = go-up.tango.16.png [size(16,16)] +icon.plugin.composite.editor.show.type = icon.home +icon.plugin.composite.editor.unpackage = Unpackage.gif + +icon.plugin.enum.editor.provider = icon.plugin.datatypes.enum +icon.plugin.enum.editor.add = icon.base.plus +icon.plugin.enum.editor.apply = icon.save +icon.plugin.enum.editor.delete = icon.base.delete +icon.plugin.enum.editor.home = icon.home + +icon.plugin.console.provider = icon.console +icon.plugin.console.clear = icon.clear +icon.plugin.console.scroll.lock = lock.png + +icon.plugin.datatypes.provider = dataTypes.png +icon.plugin.datatypes.commit.single.type = smallRightArrow.png +icon.plugin.datatypes.associate.single.type = smallLeftArrow.png +icon.plugin.datatypes.conflict.mode.rename.and.add = conflictRename.png +icon.plugin.datatypes.conflict.mode.use.existing = conflictKeep.png +icon.plugin.datatypes.conflict.mode.replace.existing = conflictReplace.png +icon.plugin.datatypes.conflict.mode.replace.or.rename = conflictReplaceOrRename.png +icon.plugin.datatypes.filter.arrays.off = Array.png +icon.plugin.datatypes.filter.arrays.on = FilterArrays.png +icon.plugin.datatypes.filter.pointers.off = fingerPointer.png +icon.plugin.datatypes.filter.pointers.on = FilterPointers.png +icon.plugin.datatypes.archive.built.in.closed = closedBookBrown.png +icon.plugin.datatypes.archive.built.in.open = openBookBrown.png +icon.plugin.datatypes.archive.file.closed = closedBookGreen.png +icon.plugin.datatypes.archive.file.open = openBookGreen.png +icon.plugin.datatypes.archive.invalid =closedFolderInvalid.png +icon.plugin.datatypes.archive.program.closed = closedBookRed.png +icon.plugin.datatypes.archive.program.open = openBookRed.png +icon.plugin.datatypes.archive.project.closed = closedBookBlue.png +icon.plugin.datatypes.archive.project.open = openBookBlue.png + +icon.plugin.datatypes.tree.conflict = doubleArrow.png +icon.plugin.datatypes.tree.change.local = smallRightArrow.png +icon.plugin.datatypes.tree.change.source = smallLeftArrow.png +icon.plugin.datatypes.tree.missing = redQuestionMark.png +icon.plugin.datatypes.tree.node.archive.file.checked.out = icon.check +icon.plugin.datatypes.tree.node.archive.file.checked.out.exclusive = checkex.png +icon.plugin.datatypes.tree.node.archive.file.checked.out.not.latest = checkNotLatest.gif +icon.plugin.datatypes.tree.node.archive.file.hijacked = small_hijack.gif +icon.plugin.datatypes.tree.node.archive.file.read.only = user-busy.png [size(10,10)] + +icon.plugin.datatypes.util.root = BookShelf.png +icon.plugin.datatypes.util.open.root = BookShelfOpen.png +icon.plugin.datatypes.util.open.archive = openFolderArchive.png +icon.plugin.datatypes.util.open.folder = openFolder.png +icon.plugin.datatypes.util.open.folder.disabled = disabledOpenFolder.png +icon.plugin.datatypes.util.open.folder.locked = openFolderCheckedOut.png +icon.plugin.datatypes.util.closed.archive = closedFolderArchive.png +icon.plugin.datatypes.util.closed.folder = closedFolder.png +icon.plugin.datatypes.util.closed.folder.disabled = disabledClosedFolder.png +icon.plugin.datatypes.util.closed.folder.locked = closedFolderCheckedOut.png +icon.plugin.datatypes.util.favorite = emblem-favorite.png +icon.plugin.datatypes.util.favorite.disabled = emblem-favorite.png [disabled] + +icon.plugin.datawindow.provider = dataW.gif + +icon.plugin.functiontags.add = 2rightarrow.png [size(16,16)] +icon.plugin.functiontags.remove = 2leftarrow.png [size(16,16)] + +icon.plugin.functioncompare.new = page_white_c.png {bullet_star.png [size(16,16)][move(4,-4)]} +icon.plugin.functioncompare.function.next = arrow_down.png [move(3,1)] {FunctionScope.gif [move(-5,-2)]} +icon.plugin.functioncompare.function.previous = arrow_up.png [move(3,1)] {FunctionScope.gif [move(-5,-2)]} +icon.plugin.functioncompare.function.remove = edit-delete.png [move(3,3)] {FunctionScope.gif [move(-5,-2)]} +icon.plugin.functioncompare.open.function.table = page_white_c.png {icon.add [size(10,10)][move(10,10)]} +icon.plugin.functioncompare.scroll.lock = icon.base.lock +icon.plugin.functioncompare.scroll.unlock = icon.base.unlock + +icon.plugin.functionwindow.provider = functions.gif + +icon.plugin.instructiontable.address = DOSA_A.png +icon.plugin.instructiontable.scalar = DOSA_S.png +icon.plugin.instructiontable.operand = DOSA_O.png +icon.plugin.instructiontable.undefined = DOSA_D.png +icon.plugin.instructiontable.manual.entry = icon.base.edit.bytes +icon.plugin.instructiontable.binary = binaryData.gif +icon.plugin.instructiontable.hex = hexData.png + +icon.plugin.interpreter.provider = icon.console + +icon.plugin.locationreferences.highlight = tag_yellow.png + +icon.plugin.memorymap.provider = memory16.gif +icon.plugin.memorymap.add = icon.add +icon.plugin.memorymap.move = move.png +icon.plugin.memorymap.split = verticalSplit.png +icon.plugin.memorymap.expand.up = icon.toggle.collapse +icon.plugin.memorymap.expand.down = icon.toggle.expand +icon.plugin.memorymap.merge = Merge.png +icon.plugin.memorymap.delete = icon.delete +icon.plugin.memorymap.image.base = house.png + +icon.plugin.merge = Merge.png +icon.plugin.merge.changed = changed16.gif +icon.plugin.merge.conflict.collapse = icon.toggle.collapse +icon.plugin.merge.conflict.expand = icon.toggle.expand +icon.plugin.merge.conflict.lock = lock.gif +icon.plugin.merge.conflict.unlock = unlock.gif +icon.plugin.merge.status.pending = bullet_green.png +icon.plugin.merge.status.in.progress = right.png +icon.plugin.merge.status.complete = checkmark_green.gif + +icon.plugin.myprogramchanges.merge = vcMerge.png +icon.plugin.myprogramchanges.checkin = vcCheckIn.png + +icon.plugin.navigation.bookmark = B.gif [size(16,16)] +icon.plugin.navigation.bookmark.analysis = applications-system.png +icon.plugin.navigation.bookmark.error = icon.error +icon.plugin.navigation.bookmark.info = icon.information +icon.plugin.navigation.bookmark.note = notes.gif +icon.plugin.navigation.bookmark.warning = icon.warning +icon.plugin.navigation.bookmark.unknown = unknown.gif +icon.plugin.navigation.bytes = V.png +icon.plugin.navigation.data = D.gif +icon.plugin.navigation.function = F.gif +icon.plugin.navigation.instruction = I.gif +icon.plugin.navigation.label = L.gif +icon.plugin.navigation.undefined = U.gif +icon.plugin.navigation.highlight.range.next = NextHighlightBlock16.gif +icon.plugin.navigation.highlight.range.previous = PreviousHighlightBlock16.gif +icon.plugin.navigation.selection.range.next = NextSelectionBlock16.gif +icon.plugin.navigation.selection.range.previous = PreviousSelectionBlock16.gif +icon.plugin.navigation.location.next = icon.right +icon.plugin.navigation.location.previous = icon.left + +icon.plugin.bundlemanager.disable = media-playback-stop.png +icon.plugin.bundlemanager.enable = media-playback-start.png + +icon.plugin.overview.provider = x-office-document-template.png + +icon.plugin.programmanager.empty.small = empty8x16.png +icon.plugin.programmanager.close = x.gif +icon.plugin.programmanager.close.highlight = pinkX.gif +icon.plugin.programmanager.list = VCRFastForward.gif +icon.plugin.programmanager.transient = link.png +icon.plugin.programmanager.busy = icon.base.edit.bytes + +icon.plugin.programtree.docs = openBookBlue.png +icon.plugin.programtree.fragment = codeNotInView.gif +icon.plugin.programtree.fragment.empty = emptyFragment.gif +icon.plugin.programtree.fragment.viewed = codeInView.gif +icon.plugin.programtree.fragment.viewed.empty = emptyFragmentInView.gif +icon.plugin.programtree.fragment.closed.folder = closedFolderInView.png +icon.plugin.programtree.fragment.open.folder = openFolderInView.png +icon.plugin.programtree.fragment.viewed.closed.folder.with.description = closedDescendantsInView.png +icon.plugin.programtree.closed.folder = closedFolder.png +icon.plugin.programtree.open.folder = openFolder.png +icon.plugin.programtree.open.tree = icon.folder.open +icon.plugin.programtree.new.tree = layout_add.png +icon.plugin.programtree.drag.copy = dragMoveCursor.gif +icon.plugin.programtree.drag.move = dragCopyCursor.gif + +icon.plugin.reachability.provider = function_graph_curvey.png [rotate(90)] + +icon.plugin.register = registerIcon.png +icon.plugin.register.group = registerGroup.png +icon.plugin.register.provider = icon.plugin.register.group + +icon.plugin.scalartable.provider = dataW.gif + +icon.plugin.scriptmanager.provider = icon.run +icon.plugin.scriptmanager.run = icon.run +icon.plugin.scriptmanager.run.again = play_again.png +icon.plugin.scriptmanager.edit = accessories-text-editor.png +icon.plugin.scriptmanager.edit.eclipse = eclipse.png +icon.plugin.scriptmanager.keybinding = key.png +icon.plugin.scriptmanager.delete = icon.delete +icon.plugin.scriptmanager.rename = icon.rename +icon.plugin.scriptmanager.new = script_add.png +icon.plugin.scriptmanager.manage = text_list_bullets.png +icon.plugin.scriptmanager.api = red-cross.png + +icon.plugin.stringtable.provider = kmessedwords.png +icon.plugin.stringtable.defined = font.png +icon.plugin.stringtable.defined.partial = dialog-warning.png +icon.plugin.stringtable.undefined = icon.search +icon.plugin.stringtable.words = view-filter.png +icon.plugin.stringtable.conflicts = dialog-warning_red.png + +icon.plugin.symboltree.provider = sitemap_color.png +icon.plugin.symboltree.goto = icon.base.search.marker +icon.plugin.symboltree.set.external = icon.base.edit.bytes +icon.plugin.symboltree.node.root = bullet_green.png +icon.plugin.symboltree.node.class = class.png +icon.plugin.symboltree.node.code = label.png +icon.plugin.symboltree.node.code.pinned = icon.base.pinned +icon.plugin.symboltree.node.code.external = ExternalData.gif +icon.plugin.symboltree.node.function = FunctionScope.gif +icon.plugin.symboltree.node.function.external = ExternalFunction.gif +icon.plugin.symboltree.node.function.thunk = ThunkFunction.gif +icon.plugin.symboltree.node.library = package.png +icon.plugin.symboltree.node.local.variable = LocalVariable.gif +icon.plugin.symboltree.node.parameter = Parameter.gif +icon.plugin.symboltree.node.namespace = Namespace.gif +icon.plugin.symboltree.node.organization.closed = closedFolderGroup.png +icon.plugin.symboltree.node.organization.open = openFolderGroup.png +icon.plugin.symboltree.node.category.classes.closed = closedFolderClasses.png +icon.plugin.symboltree.node.category.classes.open = openFolderClasses.png +icon.plugin.symboltree.node.category.function.closed = closedFolderFunctions.png +icon.plugin.symboltree.node.category.function.open = openFolderFunctions.png +icon.plugin.symboltree.node.category.exports.closed = closedFolder.png +icon.plugin.symboltree.node.category.exports.open = openFolder.png +icon.plugin.symboltree.node.category.imports.closed = closedFolderExternals.png +icon.plugin.symboltree.node.category.imports.open = openFolderExternals.png +icon.plugin.symboltree.node.category.label.closed = closedFolderLabels.png +icon.plugin.symboltree.node.category.label.open = openFolderLabels.png +icon.plugin.symboltree.node.category.namespace.closed = closedFolderNamespaces.png +icon.plugin.symboltree.node.category.namespace.open = openFolderNamespaces.png +icon.plugin.symboltree.node.group.folder.closed = closedFolderGroup.png +icon.plugin.symboltree.node.group.folder.open = openFolderGroup.png + +icon.plugin.symboltable.provider = table.png +icon.plugin.symboltable.references.to =references_to.gif +icon.plugin.symboltable.instructions.from = I.gif +icon.plugin.symboltable.data.from = D.gif +icon.plugin.symboltable.referencetable.provider = table_go.png + +icon.plugin.table.service = icon.search +icon.plugin.table.service.marker = icon.base.search.marker +icon.plugin.table.delete.row = table_delete.png + +icon.plugin.totd.provider = help-hint.png + +icon.plugin.viewstrings.provider = dataW.gif + +icon.plugin.debug.dbviewer.provider = zoom.png +icon.plugin.debug.domaineventviewer.provider = icon.console +icon.plugin.debug.propertymanager.provider = document-properties.png +icon.plugin.debug.propertymanager.marker = searchm_pink.gif + +icon.plugin.fsbrowser.copy = icon.copy +icon.plugin.fsbrowser.cut = icon.cut +icon.plugin.fsbrowser.delete = page_delete.png +icon.plugin.fsbrowser.font = icon.font +icon.plugin.fsbrowser.locked = icon.base.lock +icon.plugin.fsbrowser.new = page_add.png +icon.plugin.fsbrowser.paste = icon.paste +icon.plugin.fsbrowser.redo = icon.redo +icon.plugin.fsbrowser.rename = icon.rename +icon.plugin.fsbrowser.refresh = icon.refresh +icon.plugin.fsbrowser.save = icon.save +icon.plugin.fsbrowser.save.as = icon.save.as +icon.plugin.fsbrowser.undo = icon.undo +icon.plugin.fsbrowser.unlocked = icon.base.unlock +icon.plugin.fsbrowser.close = images/famfamfam_silk_icons_v013/door.png +icon.plugin.fsbrowser.collapse.all = images/famfamfam_silk_icons_v013/arrow_in.png +icon.plugin.fsbrowser.compress = images/famfamfam_silk_icons_v013/compress.png +icon.plugin.fsbrowser.create.firmware = media-flash.png +icon.plugin.fsbrowser.expand.all = images/famfamfam_silk_icons_v013/arrow_inout.png +icon.plugin.fsbrowser.extract = package_green.png +icon.plugin.fsbrowser.info = icon.information +icon.plugin.fsbrowser.open = images/famfamfam_silk_icons_v013/door_open.png +icon.plugin.fsbrowser.open.as.binary = images/famfamfam_silk_icons_v013/controller.png +icon.plugin.fsbrowser.open.in.listing = images/famfamfam_silk_icons_v013/folder_table.png +icon.plugin.fsbrowser.open.file.system = images/famfamfam_silk_icons_v013/folder_brick.png +icon.plugin.fsbrowser.photo = images/famfamfam_silk_icons_v013/photo.png +icon.plugin.fsbrowser.view.as.image = images/oxygen/16x16/games-config-background.png +icon.plugin.fsbrowser.view.as.text = format-text-bold.png +icon.plugin.fsbrowser.eclipse = eclipse.png +icon.plugin.fsbrowser.jar = images/famfamfam_silk_icons_v013/page_white_cup.png +icon.plugin.fsbrowser.import = images/famfamfam_silk_icons_v013/application_get.png +icon.plugin.fsbrowser.ios = images/famfamfam_silk_icons_v013/phone.png +icon.plugin.fsbrowser.open.all = images/famfamfam_silk_icons_v013/application_cascade.png +icon.plugin.fsbrowser.list.mounted = downArrow.png + +icon.base.util.fixed.bit.size.field = icon.pulldown + +icon.base.util.viewer.fieldfactory.label = icon.base.pinned [move(0,4)] +icon.base.util.viewer.fieldfactory.openclose.closed = small_plus.png +icon.base.util.viewer.fieldfactory.openclose.open = small_minus.png +icon.base.util.viewer.fieldfactory.variable = icon.warning + +icon.base.util.listingcompare.provider = table_relationship.png +icon.base.util.listingcompare.cursor = cursor_arrow_flipped.gif +icon.base.util.listingcompare.diff.next = view-sort-ascending.png +icon.base.util.listingcompare.previous.next = view-sort-descending.png +icon.base.util.listingcompare.area.markers.all = text_list_bullets.png +icon.base.util.listingcompare.area.markers.unmatched = icon.navigate.in +icon.base.util.listingcompare.area.markers.diff = table_relationship.png +icon.base.util.listingcompare.hover.off = icon.base.hover.off +icon.base.util.listingcompare.hover.on = icon.base.hover.on + +icon.base.util.listingdiff.diffs.not = no_small.png +icon.base.util.listingdiff.diffs.byte = binaryData.gif +icon.base.util.listingdiff.diffs.constants = class.png +icon.base.util.listingdiff.diffs.registers = registerGroup.png + +icon.base.util.xml.functions.bookmark = imported_bookmark.gif + +icon.base.util.datatree.version.control.archive.dt.checkout.undo = vcUndoCheckOut.png + + + + + + +[Dark Defaults] \ No newline at end of file diff --git a/Ghidra/Features/Base/data/base.listing.theme.properties b/Ghidra/Features/Base/data/base.listing.theme.properties new file mode 100644 index 0000000000..aa2a699135 --- /dev/null +++ b/Ghidra/Features/Base/data/base.listing.theme.properties @@ -0,0 +1,146 @@ +[Defaults] + +color.bg.listing = color.bg +color.bg.currentline.listing = color.bg.currentline +color.bg.selection.listing = color.bg.selection +color.bg.highlight.listing = color.bg.highlight + +color.bg.listing.tabs.selected = #788CBD +color.bg.listing.tabs.unselected = system.color.bg.application +color.bg.listing.tabs.highlighted = #ABC8FF +color.bg.listing.tabs.list = rgb(255, 255, 230) +color.bg.listing.tabs.more.tabs.hover = rgb(255, 226, 213) +color.fg.listing.tabs.text.selected = black +color.fg.listing.tabs.text.unselected = color.fg +color.fg.listing.tabs.list = black + + +color.bg.listing.header.active.field = rgb(244, 221, 183) +color.fg.listing.header.active.field = color.fg + +color.cursor.focused.listing = color.cursor.focused +color.cursor.unfocused.listing = color.cursor.unfocused + +color.fg.listing.address = color.fg +color.fg.listing.ref.bad = red +color.fg.listing.bytes = blue +color.fg.listing.constant = green +color.fg.listing.label.unreferenced = black +color.fg.listing.entrypoint = magenta +color.fg.listing.comment.auto = lightGray +color.fg.listing.comment.eol = blue +color.fg.listing.comment.repeatable = darkOrange +color.fg.listing.comment.ref.repeatable = cornflowerBlue +color.fg.listing.comment.plate = gray +color.fg.listing.comment.post = blue +color.fg.listing.comment.pre = indigo +color.fg.listing.ref.ext.resolved = teal +color.fg.listing.fieldname = color.fg +color.fg.listing.function.callfixup = fuchsia +color.fg.listing.function.name = blue +color.fg.listing.function.param = black +color.fg.listing.function.tag = mediumVioletRed +color.fg.listing.function.param.auto = gray +color.fg.listing.function.return.type = black +color.fg.listing.function.param.custom = indigo +color.fg.listing.function.param.dynamic = #006666 +color.fg.listing.label.local = green +color.fg.listing.label.non.primary = olive +color.fg.listing.label.primary = darkBlue +color.fg.listing.mnemonic.override = deepPink +color.fg.listing.mnemonic = navy +color.fg.listing.mnemonic.unimplemented = navy + +// TODO +color.fg.listing.flow.arrow.inactive = lightGray +color.fg.listing.flow.arrow.active = color.fg +color.fg.listing.flow.arrow.selected = limeGreen +color.fg.listing.separator = color.fg +color.fg.listing.variable = purple +color.fg.listing.version.tracking = purple +color.fg.listing.xref = darkGreen +color.fg.listing.xref.offcut = gray +color.fg.listing.xref.read = blue +color.fg.listing.xref.write = darkOrange +color.fg.listing.xref.other = color.fg +color.fg.listing.register = olive +color.fg.listing.underline = cornflowerBlue +color.fg.listing.pcode.label = blue +color.fg.listing.pcode.space = blue +color.fg.listing.pcode.varnode = blue +color.fg.listing.pcode.userop = blue + +color.bg.listing.comparison.bytes = chartreuse +color.bg.listing.comparison.mnemonic = chartreuse +color.bg.listing.comparison.operand = chartreuse +color.bg.listing.comparison.code.units.diff = silver +color.bg.listing.comparison.code.units.unmatched = skyblue + +font.listing.base = font.monospaced +font.listing.header = SansSerif-PLAIN-11 + + +[Dark Defaults] + +color.bg.listing.tabs.selected = #788CBD +color.bg.listing.tabs.unselected = system.color.bg.application +color.bg.listing.tabs.highlighted = #ABC8FF +color.bg.listing.tabs.list = rgb(255, 255, 230) +color.fg.listing.tabs.text.selected = black +color.fg.listing.tabs.text.unselected = color.fg +color.fg.listing.tabs.list = black + + +color.bg.listing.header.active.field = rgb(244, 221, 183) +color.fg.listing.header.active.field = black + + + +color.fg.listing.address = color.fg +color.fg.listing.ref.bad = color.palette.red +color.fg.listing.bytes = color.palette.blue +color.fg.listing.constant = color.palette.green +color.fg.listing.label.unreferenced = color.fg +color.fg.listing.entrypoint = color.palette.magenta +color.fg.listing.comment.auto = color.fg +color.fg.listing.comment.eol = color.palette.blue +color.fg.listing.comment.repeatable = color.palette.orange +color.fg.listing.comment.ref.repeatable = color.palette.darkcyan +color.fg.listing.comment.plate = gray +color.fg.listing.comment.post = color.palette.blue +color.fg.listing.comment.pre = color.palette.indigo +color.fg.listing.ref.ext.resolved = color.palette.teal +color.fg.listing.fieldname = color.fg +color.fg.listing.function.callfixup = color.palette.magenta +color.fg.listing.function.name = color.palette.blue +color.fg.listing.function.param = color.fg +color.fg.listing.function.tag = color.palette.violetred +color.fg.listing.function.param.auto = gray +color.fg.listing.function.return.type = color.fg +color.fg.listing.function.param.custom = color.palette.indigo +color.fg.listing.function.param.dynamic = color.palette.teal +color.fg.listing.label.local = color.palette.green +color.fg.listing.label.non.primary = color.palette.olive +color.fg.listing.label.primary = color.palette.cyan +color.fg.listing.mnemonic.override = color.palette.pink +color.fg.listing.mnemonic = color.palette.cyan +color.fg.listing.mnemonic.unimplemented = color.palette.cyan + + +color.fg.listing.flow.arrow.inactive = lightGray +color.fg.listing.flow.arrow.active = color.fg +color.fg.listing.flow.arrow.selected = limeGreen +color.fg.listing.separator = color.fg +color.fg.listing.variable = color.palette.purple +color.fg.listing.version.tracking = color.palette.purple +color.fg.listing.xref = color.palette.darkgreen +color.fg.listing.xref.offcut = gray +color.fg.listing.xref.read = color.palette.blue +color.fg.listing.xref.write = color.palette.orange +color.fg.listing.xref.other = color.fg +color.fg.listing.register = color.palette.olive +color.fg.listing.underline = cornflowerBlue +color.fg.listing.pcode.label = color.palette.blue +color.fg.listing.pcode.space = color.palette.blue +color.fg.listing.pcode.varnode = color.palette.blue +color.fg.listing.pcode.userop = color.palette.blue diff --git a/Ghidra/Features/Base/data/base.programgraph.theme.properties b/Ghidra/Features/Base/data/base.programgraph.theme.properties new file mode 100644 index 0000000000..a460530063 --- /dev/null +++ b/Ghidra/Features/Base/data/base.programgraph.theme.properties @@ -0,0 +1,57 @@ + +[Defaults] + +color.bg.plugin.programgraph.vertex.selection = color.graphdisplay.vertex.selected +color.bg.plugin.programgraph.edge.selection = color.graphdisplay.edge.selected + +color.bg.plugin.programgraph.edge.call.callother.override = red +color.bg.plugin.programgraph.edge.call.computed = cyan +color.bg.plugin.programgraph.edge.call.computed.terminator = purple +color.bg.plugin.programgraph.edge.call.conditional.computed = cyan +color.bg.plugin.programgraph.edge.call.conditional = darkorange +color.bg.plugin.programgraph.edge.call.conditional.terminator = purple +color.bg.plugin.programgraph.edge.call.unconditional = darkorange +color.bg.plugin.programgraph.edge.call.unconditional.override = red +color.bg.plugin.programgraph.edge.jump.callother.override = red +color.bg.plugin.programgraph.edge.jump.conitional.computed = cyan +color.bg.plugin.programgraph.edge.jump.computed = cyan +color.bg.plugin.programgraph.edge.jump.conditional = darkgoldenrod +color.bg.plugin.programgraph.edge.jump.terminator = purple +color.bg.plugin.programgraph.edge.jump.unconditional = darkgreen +color.bg.plugin.programgraph.edge.jump.unconditional.override = red + +color.bg.plugin.programgraph.edge.default = red +color.bg.plugin.programgraph.edge.conditional.terminator = purple +color.bg.plugin.programgraph.edge.data.unknown = black +color.bg.plugin.programgraph.edge.data.indirect = darkorange +color.bg.plugin.programgraph.edge.entry = gray +color.bg.plugin.programgraph.edge.external.ref = purple +color.bg.plugin.programgraph.edge.fall.through = blue +color.bg.plugin.programgraph.edge.indirection = pink +color.bg.plugin.programgraph.edge.param = cyan +color.bg.plugin.programgraph.edge.read = green +color.bg.plugin.programgraph.edge.read.indirect = darkgreen +color.bg.plugin.programgraph.edge.read.write = darkgoldenrod +color.bg.plugin.programgraph.edge.read.write.indirect = brown +color.bg.plugin.programgraph.edge.terminator = purple +color.bg.plugin.programgraph.edge.thunk = blue +color.bg.plugin.programgraph.edge.write = red +color.bg.plugin.programgraph.edge.write.indirect = darkred + + +color.bg.plugin.programgraph.vertex.default = red +color.bg.plugin.programgraph.vertex.body = blue +color.bg.plugin.programgraph.vertex.entry = darkorange +color.bg.plugin.programgraph.vertex.exit = darkmagenta +color.bg.plugin.programgraph.vertex.external = darkgreen +color.bg.plugin.programgraph.vertex.switch = darkcyan +color.bg.plugin.programgraph.vertex.bad = red +color.bg.plugin.programgraph.vertex.data = pink +color.bg.plugin.programgraph.vertex.entry.nexus = wheat +color.bg.plugin.programgraph.vertex.instruction = blue +color.bg.plugin.programgraph.vertex.stack = green + +font.plugin.programgraph = font.graphdisplay.default + +[Dark Defaults] + diff --git a/Ghidra/Features/Base/data/base.theme.properties b/Ghidra/Features/Base/data/base.theme.properties new file mode 100644 index 0000000000..1cd006513a --- /dev/null +++ b/Ghidra/Features/Base/data/base.theme.properties @@ -0,0 +1,213 @@ +[Defaults] + +color.bg.undefined = rgb(220, 220, 220) // bg for clients displaying undefined functions + +color.flowtype.fall.through = red +color.flowtype.jump.conditional = #007C00 // dark green +color.flowtype.jump.unconditional = blue + +color.function.thunk = color.palette.blue +color.fg.function.name = color.palette.blue +color.fg.function.params = color.palette.magenta + +color.bg.table.selection.bundle = [color]textHighlight +color.fg.table.selection.bundle = [color]textHighlightText +color.fg.table.bundle.disabled = darkGray +color.fg.table.bundle.busy = gray +color.fg.table.bundle.inactive = black +color.fg.table.bundle.active = green + +color.fg.table.offcut.selected = pink +color.fg.table.offcut.unselected = color.fg.error + +color.bg.splash.infopanel = color.bg + +color.bg.table.selected.ghidratable = color.bg +color.fg.table.ghidratable.equate.bad = red +color.fg.table.ghidratable.equate = blue +color.fg.table.ghidratable.suggestion = silver + +color.fg.consoletextpane = color.fg +color.fg.error.consoletextpane = color.fg.error + +color.fg.infopanel.version = color.fg + +color.fg.interpreterpanel = color.fg +color.fg.interpreterpanel.error = color.fg.error +color.fg.listing.highlighter.default = yellow +color.fg.listing.highlighter.scoped.read = rgb(204,204, 0) +color.fg.listing.highlighter.scoped.write = green + +color.bg.markerservice = color.bg + +color.bg.search.highlight = rgb(255,255,200) +color.bg.search.current.line.highlight = yellow + +color.bg.tree.renderer.icon.fill = #9F9FFF +color.bg.tree.renderer.icon.line = #8282FF + +color.bg.analysis.options.not.default.enablement = rgb(255, 255, 200) +color.bg.analysis.options.not.default.enablement.selected = rgb(177, 212, 236) +color.fg.analysis.options.prototype = crimson + +color.fg.plugin.assembler.completion.least = rgb(0, 128, 0) +color.fg.plugin.assembler.completion.middle = rgb(0, 0, 128) +color.fg.plugin.assembler.completion.most = blue + +color.bg.plugin.bookmark.analysis = rgb(255, 128, 0) // orange +color.bg.plugin.bookmark.default = rgb(255, 0, 255) // magenta +color.bg.plugin.bookmark.error = rgb(204, 0, 51) // dark red +color.bg.plugin.bookmark.info = rgb(0, 255, 255) // cyan +color.bg.plugin.bookmark.note = rgb(128, 0, 255) // purple +color.bg.plugin.bookmark.warning = rgb(255, 196, 51) // dark yellow + +color.bg.plugin.colorizer.default = #84AFD3 +color.bg.plugin.colorizer.marker = pink + +color.fg.plugin.comments.history.text = blue +color.fg.plugin.comments.history.user = color.fg +color.fg.plugin.comments.history.date = rgb(124, 37, 18) + +color.bg.plugin.programtree = color.bg + +color.bg.plugin.datamgr.edge.default = blue +color.bg.plugin.datamgr.edge.composite = magenta +color.bg.plugin.datamgr.edge.reference = blue +color.bg.plugin.datamgr.icon.highlight = rgb(204, 204, 255) + +color.bg.plugin.editors.compositeeditor.text = color.fg +color.bg.plugin.editors.compositeeditor.line = system.color.border +color.bg.plugin.editors.compositeeditor.line.interior = #D4D4D4 +color.bg.plugin.editors.compositeeditor.byte.header = #DFDFDF +color.bg.plugin.editors.compositeeditor.bit.undefined = #F8F8F8 +color.bg.plugin.editors.compositeeditor.bit.component = #BFBFFF +color.bg.plugin.editors.compositeeditor.bit.active = green +color.bg.plugin.editors.compositeeditor.bit.conflict = yellow +color.bg.plugin.editors.compositeeditor.non.bit = #A0A0FF + +color.fg.plugin.equate.enum = lightskyblue + +color.fg.plugin.function.editor.dialog.thunk = color.function.thunk +color.fg.plugin.function.editor.dialog.textfield.default = color.fg +color.fg.plugin.function.editor.dialog.textfield.error = color.fg.error +color.fg.plugin.function.editor.dialog.textfield.function.name = color.palette.blue +color.fg.plugin.function.editor.dialog.textfield.parameter = color.fg.function.params + +color.bg.plugin.instructionsearch.table.masked.instruction = rgb(237, 243, 254) // faint blue +color.bg.plugin.instructionsearch.table.masked.non.instruction = rgb(255, 242, 214) // tan +color.bg.plugin.instructionsearch.table.not.masked.instruction = rgb(188, 212, 254) // light blue +color.bg.plugin.instructionsearch.table.not.masked.non.instruction = rgb(203, 186, 150) // dark tan +color.bg.plugin.instructionsearch.table.default = rgb(214, 217, 223) +color.bg.plugin.instructionsearch.search.markers = lightgreen + +color.fg.plugin.interpreter.renderer.color.standard.1 = rgb(0,0,0) // black +color.fg.plugin.interpreter.renderer.color.standard.2 = rgb(194, 54, 33) // red +color.fg.plugin.interpreter.renderer.color.standard.3 = rgb(37, 188, 36) // green +color.fg.plugin.interpreter.renderer.color.standard.4 = rgb(173, 173, 39) // yellow +color.fg.plugin.interpreter.renderer.color.standard.5 = rgb(73, 46, 225) // blue +color.fg.plugin.interpreter.renderer.color.standard.6 = rgb(211, 56, 211) // magenta +color.fg.plugin.interpreter.renderer.color.standard.7 = rgb(51, 187, 200) // cyan +color.fg.plugin.interpreter.renderer.color.standard.8 = rgb(203, 204, 205) // white +color.fg.plugin.interpreter.renderer.color.intense.1 = rgb(129, 131, 131) // intense black +color.fg.plugin.interpreter.renderer.color.intense.2 = rgb(252, 57, 31) // intense red +color.fg.plugin.interpreter.renderer.color.intense.3 = rgb(49, 231, 34) // intense green +color.fg.plugin.interpreter.renderer.color.intense.4 = rgb(234, 236, 35) // intense yellow +color.fg.plugin.interpreter.renderer.color.intense.5 = rgb(88, 51, 255) // intense blue +color.fg.plugin.interpreter.renderer.color.intense.6 = rgb(249, 53, 248) // intense magenta +color.fg.plugin.interpreter.renderer.color.intense.7 = rgb(20, 240, 240) // intense cyan +color.fg.plugin.interpreter.renderer.color.intense.8 = rgb(233, 235, 235) // intense white + +color.bg.plugin.locationreferences.highlight = rgb(168, 202, 242) + +color.bg.plugin.myprogramchangesdisplay.markers.changes.unsaved = darkgray +color.bg.plugin.myprogramchangesdisplay.markers.changes.conflicting = color.fg.error +color.bg.plugin.myprogramchangesdisplay.markers.changes.latest.version = blue +color.bg.plugin.myprogramchangesdisplay.markers.changes.not.checked.in = green + +color.bg.plugin.overview.defalt = gray + +color.bg.plugin.overview.address.data = rgb(128, 255, 128) +color.bg.plugin.overview.address.function = rgb(204, 150, 255) +color.bg.plugin.overview.address.external.ref = rgb(255, 150, 150) +color.bg.plugin.overview.address.instruction = rgb(192, 192, 255) +color.bg.plugin.overview.address.undefined = rgb(255, 51, 102) +color.bg.plugin.overview.address.uninitialized = black + +color.bg.plugin.overview.entropy.knot.1 = red +color.bg.plugin.overview.entropy.knot.2 = blue +color.bg.plugin.overview.entropy.knot.3 = green +color.bg.plugin.overview.entropy.knot.4 = yellow +color.bg.plugin.overview.entropy.knot.5 = blue +color.bg.plugin.overview.entropy.uninitialized = blue +color.bg.plugin.overview.entropy.palette.base.low = black +color.bg.plugin.overview.entropy.palette.base.high = white +color.bg.plugin.overview.entropy.palette.text = color.fg + +color.bg.plugin.programdiff.details.address = #009999 +color.bg.plugin.programdiff.details.comment = #009900 +color.bg.plugin.programdiff.details.danger = #FF0000 +color.bg.plugin.programdiff.details.emphasize = #009900 +color.bg.plugin.programdiff.details.program = #990099 + +color.bg.plugin.references.table.active.operand = rgb(205, 205, 205) + +color.bg.plugin.register.marker = rgb(0, 153, 153) + +color.bg.plugin.windowlocation = black +color.bg.plugin.windowlocation.bounds.virtual = red +color.bg.plugin.windowlocation.bounds.visible = green +color.bg.plugin.windowlocation.screens = orange +color.bg.plugin.windowlocation.window.selected = rgba(0, 255, 0, 200) +color.fg.plugin.windowlocation.window.text = gray + +font.print = SansSerif-PLAIN-10 +font.plugin.console = font.monospaced +font.plugin.service.text.editor = font.monospaced +font.plugin.scripts.text.editor = font.monospaced +font.plugin.assembly.dual.text.field = font.monospaced +font.plugin.instruction.table.renderer = courier-plain-14 +font.plugin.entropy.label.knot = SansSerif-BOLD-12 +font.plugin.instruction.info = font.monospaced[14] +font.plugin.tabs = SansSerif-PLAIN-11 +font.plugin.tabs.list = SansSerif-BOLD-9 +font.plugin.tips = Dialog-PLAIN-12 +font.plugin.tips.label = font.plugin.tips[BOLD] + +[Dark Defaults] + +color.bg = rgb(40, 42, 46) // TODO this should be in a more generic module + +color.bg.undefined = #5C4D68 + +color.flowtype.fall.through = rgb(164, 66, 66) +color.flowtype.jump.conditional = rgb(95, 129, 157) +color.flowtype.jump.unconditional = rgb(140, 148, 64) + +color.bg.table.selection.bundle = [color]textHighlight +color.fg.table.selection.bundle = [color]textHighlightText +color.fg.table.bundle.disabled = lightGray +color.fg.table.bundle.busy = gray +color.fg.table.bundle.inactive = lightGray +color.fg.table.bundle.active = limeGreen + + +color.fg.table.ghidratable.equate.bad = indianRed +color.fg.table.ghidratable.equate = royalBlue +color.fg.table.ghidratable.suggestion = darkGray + +color.bg.search.highlight = rgb(189,183,107) +color.bg.search.current.line.highlight = gold + +// TODO: These should probably be "bg" colors +// TODO: I'd be nice if we did have control of the "fg" colors, too +color.fg.listing.highlighter.default = color.palette.bg.blindingyellow +color.fg.listing.highlighter.scoped.read = color.palette.bg.blindingorange +color.fg.listing.highlighter.scoped.write = color.palette.bg.blindinggreen + +color.bg.analysis.options.not.default.enablement = #D1D19E +color.bg.analysis.options.not.default.enablement.selected = rgb(177, 212, 236) +color.fg.analysis.options.prototype = lightcoral + +color.bg.plugin.datamgr.edge.default = deepskyblue +color.bg.plugin.datamgr.edge.composite = plum +color.bg.plugin.datamgr.edge.reference = deepskyblue diff --git a/Ghidra/Features/Base/data/file_extension_icons.xml b/Ghidra/Features/Base/data/file_extension_icons.xml deleted file mode 100644 index 50b56ac3ea..0000000000 --- a/Ghidra/Features/Base/data/file_extension_icons.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Ghidra/Features/Base/data/typeinfo/base.file.extensions.icons.theme.properties b/Ghidra/Features/Base/data/typeinfo/base.file.extensions.icons.theme.properties new file mode 100644 index 0000000000..457230c488 --- /dev/null +++ b/Ghidra/Features/Base/data/typeinfo/base.file.extensions.icons.theme.properties @@ -0,0 +1,42 @@ +[Defaults] + + icon.fsbrowser.file.extension.default = images/famfamfam_silk_icons_v013/page_white.png + icon.fsbrowser.file.extension.apk = images/famfamfam_silk_icons_v013/package.png + icon.fsbrowser.file.extension.c = images/text-x-csrc.png + icon.fsbrowser.file.extension.cpp = images/oxygen/16x16/text-x-c++src.png + icon.fsbrowser.file.extension.class = images/famfamfam_silk_icons_v013/cup.png + icon.fsbrowser.file.extension.cs = images/oxygen/16x16/text-x-csharp.png + icon.fsbrowser.file.extension.css = images/famfamfam_silk_icons_v013/css.png + icon.fsbrowser.file.extension.data = images/famfamfam_silk_icons_v013/database.png + icon.fsbrowser.file.extension.dfu = images/famfamfam_silk_icons_v013/bullet_blue.png + icon.fsbrowser.file.extension.dmg = images/famfamfam_silk_icons_v013/bullet_green.png + icon.fsbrowser.file.extension.f = images/F.gif + icon.fsbrowser.file.extension.h = images/oxygen/16x16/text-x-chdr.png + icon.fsbrowser.file.extension.html = images/famfamfam_silk_icons_v013/html.png + icon.fsbrowser.file.extension.img = images/famfamfam_silk_icons_v013/images.png + icon.fsbrowser.file.extension.img3 = images/famfamfam_silk_icons_v013/bullet_orange.png + icon.fsbrowser.file.extension.index = images/oxygen/16x16/bookmarks.png + icon.fsbrowser.file.extension.ipsw = images/oxygen/16x16/multimedia-player-apple-ipod.png + icon.fsbrowser.file.extension.iso = images/nuvola/16x16/cdimage.png + icon.fsbrowser.file.extension.jar = images/oxygen/16x16/application-x-java-archive.png + icon.fsbrowser.file.extension.java = images/famfamfam_silk_icons_v013/page_white_cup.png + icon.fsbrowser.file.extension.kext = images/famfamfam_silk_icons_v013/bullet_pink.png + icon.fsbrowser.file.extension.lib = images/famfamfam_silk_icons_v013/server.png + icon.fsbrowser.file.extension.obj = images/oxygen/16x16/application-x-subrip.png + icon.fsbrowser.file.extension.p = images/oxygen/16x16/text-x-pascal.png + icon.fsbrowser.file.extension.pdf = images/oxygen/16x16/application-pdf.png + icon.fsbrowser.file.extension.plist = images/oxygen/16x16/insert-table.png + icon.fsbrowser.file.extension.png = images/famfamfam_silk_icons_v013/bullet_red.png + icon.fsbrowser.file.extension.rss = images/famfamfam_silk_icons_v013/rss.png + icon.fsbrowser.file.extension.strings = images/oxygen/16x16/insert-text.png + icon.fsbrowser.file.extension.txt = images/oxygen/16x16/text-x-bibtex.png + icon.fsbrowser.file.extension.usb = images/nuvola/16x16/usb.png + icon.fsbrowser.file.extension.xhtml = images/famfamfam_silk_icons_v013/xhtml.png + icon.fsbrowser.file.extension.xml = images/oxygen/16x16/text-xml.png + icon.fsbrowser.file.extension.zip = images/oxygen/16x16/application-x-bzip.png + + icon.fsbrowser.file.substring.release. = images/famfamfam_silk_icons_v013/bullet_purple.png + + icon.fsbrowser.file.overlay.imported = EMPTY_ICON{images/checkmark_green.gif[size(8,8)][move(8,8)]} // lower right quadrant + icon.fsbrowser.file.overlay.filesystem = EMPTY_ICON{images/nuvola/16x16/ledgreen.png[size(8,8)][move(0,8)]} // lower left quadrant + icon.fsbrowser.file.overlay.missing.password = EMPTY_ICON{images/lock.png[size(8,8)][move(8,0)]} // upper right quadrant \ No newline at end of file diff --git a/Ghidra/Features/Base/ghidra_scripts/AssemblyThrasherDevScript.java b/Ghidra/Features/Base/ghidra_scripts/AssemblyThrasherDevScript.java index d3bb842409..ea96dff9b4 100644 --- a/Ghidra/Features/Base/ghidra_scripts/AssemblyThrasherDevScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/AssemblyThrasherDevScript.java @@ -17,16 +17,16 @@ //NOTE: I do not de-duplicate, since the address of the instruction may affect the output. //@category Assembly -import java.awt.Color; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.HashSet; import java.util.Set; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.apache.commons.lang3.StringUtils; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.assembler.*; import ghidra.app.plugin.assembler.sleigh.sem.*; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; @@ -40,7 +40,7 @@ import ghidra.program.model.listing.Instruction; import ghidra.program.model.mem.ByteMemBufferImpl; import ghidra.program.model.mem.MemBuffer; import ghidra.util.NumericUtilities; -import resources.ResourceManager; +import resources.Icons; public class AssemblyThrasherDevScript extends GhidraScript { public static final String BOOKMARK_FAIL = "AssemblyFailure"; @@ -104,8 +104,8 @@ public class AssemblyThrasherDevScript extends GhidraScript { clearBackgroundColor(currentProgram.getMemory().getAllInitializedAddressSet()); BookmarkManager bm = currentProgram.getBookmarkManager(); - ImageIcon myIcon = ResourceManager.loadImage("images/warning.png"); - bm.defineType(BOOKMARK_FAIL, myIcon, new Color(255, 255, 0), 0); + Icon myIcon = Icons.WARNING_ICON; + bm.defineType(BOOKMARK_FAIL, myIcon, Palette.YELLOW, 0); bm.removeBookmarks(BOOKMARK_FAIL); monitor.setMessage("Constructing Assembler"); @@ -157,7 +157,7 @@ public class AssemblyThrasherDevScript extends GhidraScript { } println("Unique instructions by constructor: " + done.size()); - setBackgroundColor(uniques, new Color(255, 128, 128)); + setBackgroundColor(uniques, Palette.getColor("lightcoral")); } protected PseudoInstruction disassemble(Instruction orig, byte[] ins) { diff --git a/Ghidra/Features/Base/ghidra_scripts/ExampleColorScript.java b/Ghidra/Features/Base/ghidra_scripts/ExampleColorScript.java index 282372d2e3..6bb8555364 100644 --- a/Ghidra/Features/Base/ghidra_scripts/ExampleColorScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/ExampleColorScript.java @@ -16,13 +16,14 @@ // An example of how to color the listing background //@category Examples +import java.awt.Color; + +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.colorizer.ColorizingService; import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; -import java.awt.Color; - public class ExampleColorScript extends GhidraScript { @Override @@ -34,10 +35,10 @@ public class ExampleColorScript extends GhidraScript { } if (currentSelection != null) { - service.setBackgroundColor(currentSelection, new Color(255, 200, 200)); + service.setBackgroundColor(currentSelection, Palette.PINK); } else if (currentAddress != null) { - service.setBackgroundColor(currentAddress, currentAddress, new Color(255, 200, 200)); + service.setBackgroundColor(currentAddress, currentAddress, Palette.PINK); } else { println("No selection or current address to color"); diff --git a/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java b/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java index 237d4b35a1..c6643f7398 100644 --- a/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java @@ -19,12 +19,12 @@ import java.util.ArrayList; import java.util.List; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.script.GhidraScript; import ghidra.app.services.GraphDisplayBroker; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.data.*; import ghidra.service.graph.*; -import ghidra.util.WebColors; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -36,7 +36,7 @@ public class GraphClassesScript extends GhidraScript { private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance"; private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance"; - List classStructures = new ArrayList(); + List classStructures = new ArrayList<>(); @Override public void run() throws Exception { @@ -107,9 +107,8 @@ public class GraphClassesScript extends GhidraScript { } /** - * Method to create a graph using preconfigured information found in class structure descriptions. - * The structure descriptions are created using - * {@link RecoveredClassUtils#createParentStringBuffer(RecoveredClass)} + * Method to create a graph using pre-configured information found in class structure + * descriptions. * @return the newly created graph */ private AttributedGraph createGraph() throws Exception { @@ -290,7 +289,7 @@ public class GraphClassesScript extends GhidraScript { private Structure getParentStructureFromClassStructures(String parentName) throws CancelledException { - List parentStructures = new ArrayList(); + List parentStructures = new ArrayList<>(); for (Structure classStructure : classStructures) { monitor.checkCanceled(); @@ -315,13 +314,13 @@ public class GraphClassesScript extends GhidraScript { display = service.getGraphDisplay(false, TaskMonitor.DUMMY); GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType()) - .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE) - .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN) - .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED) - .edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN) - .edge(VIRTUAL_INHERITANCE, WebColors.ORANGE) - .defaultVertexColor(WebColors.PURPLE) - .defaultEdgeColor(WebColors.PURPLE) + .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, Palette.BLUE) + .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, Palette.GREEN) + .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, Palette.RED) + .edge(NON_VIRTUAL_INHERITANCE, Palette.LIME) + .edge(VIRTUAL_INHERITANCE, Palette.ORANGE) + .defaultVertexColor(Palette.PURPLE) + .defaultEdgeColor(Palette.PURPLE) .defaultLayoutAlgorithm("Compact Hierarchical") .maxNodeCount(1000) .build(); @@ -330,7 +329,6 @@ public class GraphClassesScript extends GhidraScript { "Recovered Classes Graph", false, TaskMonitor.DUMMY); } - private String getClassName(String description) { int indexOfColon = getIndexOfFirstSingleColon(description); diff --git a/Ghidra/Features/Base/ghidra_scripts/SearchGuiMulti.java b/Ghidra/Features/Base/ghidra_scripts/SearchGuiMulti.java index 581cdf6f3d..7108bc886d 100644 --- a/Ghidra/Features/Base/ghidra_scripts/SearchGuiMulti.java +++ b/Ghidra/Features/Base/ghidra_scripts/SearchGuiMulti.java @@ -26,6 +26,9 @@ import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; + public class SearchGuiMulti extends SearchBaseExtended { private JScrollPane jScrollPane1; @@ -65,39 +68,19 @@ public class SearchGuiMulti extends SearchBaseExtended { frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); mnemonicButton.setText("Mnemonic"); - mnemonicButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - mnemonicButtonActionPerformed(evt); - } - }); + mnemonicButton.addActionListener(evt -> mnemonicButtonActionPerformed(evt)); mnemonicButton.setVisible(false); op1Button.setText("Operand 1"); - op1Button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - op1ButtonActionPerformed(evt); - } - }); + op1Button.addActionListener(evt -> op1ButtonActionPerformed(evt)); op1Button.setVisible(false); op2Button.setText("Operand 2"); - op2Button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - op2ButtonActionPerformed(evt); - } - }); + op2Button.addActionListener(evt -> op2ButtonActionPerformed(evt)); op2Button.setVisible(false); searchButton.setText("Search"); - searchButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - searchButtonActionPerformed(evt); - } - }); + searchButton.addActionListener(evt -> searchButtonActionPerformed(evt)); fillTable(); tableModel = new DefaultTableModel(tableContentsDO, columnIdentifiers) { @@ -122,12 +105,7 @@ public class SearchGuiMulti extends SearchBaseExtended { Color backgroundColor = dataObject.getBackgroundColor(); if (backgroundColor != null) { - if (isSelected) { - theRenderer.setBackground(backgroundColor.darker()); - } - else { - theRenderer.setBackground(backgroundColor); - } + theRenderer.setBackground(backgroundColor); } return theRenderer; @@ -152,45 +130,47 @@ public class SearchGuiMulti extends SearchBaseExtended { GroupLayout layout = new GroupLayout(frame.getContentPane()); frame.getContentPane().setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) // - .addGroup(layout.createSequentialGroup() // - .addContainerGap(15, Short.MAX_VALUE) // - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) // - .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() // - .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 357, - GroupLayout.PREFERRED_SIZE) // - .addContainerGap() // - ) // - .addGroup(GroupLayout.Alignment.CENTER, layout.createSequentialGroup() // - .addComponent(mnemonicButton) // - .addGap(39, 39, 39) // - .addComponent(op1Button) // - .addGap(42, 42, 42) // - .addComponent(op2Button) // - .addGap(40, 40, 40) // - ) // + .addGroup(layout.createSequentialGroup() // + .addContainerGap(15, Short.MAX_VALUE) // + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) // + .addGroup(GroupLayout.Alignment.TRAILING, layout + .createSequentialGroup() // + .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 357, + GroupLayout.PREFERRED_SIZE) // + .addContainerGap() // + ) // + .addGroup(GroupLayout.Alignment.CENTER, + layout.createSequentialGroup() // + .addComponent(mnemonicButton) // + .addGap(39, 39, 39) // + .addComponent(op1Button) // + .addGap(42, 42, 42) // + .addComponent(op2Button) // + .addGap(40, 40, 40) // + ) // + ) // + ) // + .addGroup(layout.createSequentialGroup() // + .addGap(153, 153, 153) // + .addComponent(searchButton) // + .addContainerGap(164, Short.MAX_VALUE) // ) // - ) // - .addGroup(layout.createSequentialGroup() // - .addGap(153, 153, 153) // - .addComponent(searchButton) // - .addContainerGap(164, Short.MAX_VALUE) // - ) // ); layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) // - .addGroup(layout.createSequentialGroup() // - .addGap(23, 23, 23) // - .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) // - .addComponent(op1Button) // - .addComponent(op2Button) // - .addComponent(mnemonicButton) // + .addGroup(layout.createSequentialGroup() // + .addGap(23, 23, 23) // + .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) // + .addComponent(op1Button) // + .addComponent(op2Button) // + .addComponent(mnemonicButton) // + ) // + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) // + .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 402, + GroupLayout.PREFERRED_SIZE) // + .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) // + .addComponent(searchButton) // + .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) // ) // - .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) // - .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 402, - GroupLayout.PREFERRED_SIZE) // - .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED) // - .addComponent(searchButton) // - .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) // - ) // ); frame.pack(); @@ -205,7 +185,7 @@ public class SearchGuiMulti extends SearchBaseExtended { if (column == 0) { tableContentsDO[mnemonic][column] = - new DataObject(mnemonics.get(mnemonic).textRep, Color.green); + new DataObject(mnemonics.get(mnemonic).textRep, Palette.GREEN); } else { OperandCase temp = null; @@ -217,10 +197,10 @@ public class SearchGuiMulti extends SearchBaseExtended { } if (temp != null) { tableContentsDO[mnemonic][column] = - new DataObject(temp.textRep, Color.red.brighter()); + new DataObject(temp.textRep, Palette.PINK); } else { - tableContentsDO[mnemonic][column] = new DataObject("", Color.white); + tableContentsDO[mnemonic][column] = new DataObject("", Palette.WHITE); } } @@ -239,13 +219,13 @@ public class SearchGuiMulti extends SearchBaseExtended { throw new IndexOutOfBoundsException(); } - if (tableContentsDO[rowSelection][columnSelection].getBackgroundColor().equals( - Color.green)) { - tableContentsDO[rowSelection][columnSelection].setBackgroundColor(Color.red); + if (tableContentsDO[rowSelection][columnSelection].getBackgroundColor() + .equals(Palette.GREEN)) { + tableContentsDO[rowSelection][columnSelection].setBackgroundColor(Palette.RED); } - else if (tableContentsDO[rowSelection][columnSelection].getBackgroundColor().equals( - Color.red)) { - tableContentsDO[rowSelection][columnSelection].setBackgroundColor(Color.green); + else if (tableContentsDO[rowSelection][columnSelection].getBackgroundColor() + .equals(Palette.RED)) { + tableContentsDO[rowSelection][columnSelection].setBackgroundColor(Palette.GREEN); } else { //TODO Determine what to do if the cell is white when clicked on. White cell means that there isn't an operand or mnemonic in that position. @@ -258,10 +238,10 @@ public class SearchGuiMulti extends SearchBaseExtended { int selectedRow = jTable1.getSelectedRow(); if (mnemonicButton.isSelected()) { - tableContentsDO[selectedRow][0].setBackgroundColor(Color.red); + tableContentsDO[selectedRow][0].setBackgroundColor(Palette.RED); } else {//off when clicked, turn on and update the table to reflect being enabled - tableContentsDO[selectedRow][0].setBackgroundColor(Color.green); + tableContentsDO[selectedRow][0].setBackgroundColor(Palette.GREEN); } jTable1.repaint(); } @@ -271,10 +251,10 @@ public class SearchGuiMulti extends SearchBaseExtended { int selectedRow = jTable1.getSelectedRow(); if (op1Button.isSelected()) { - tableContentsDO[selectedRow][1].setBackgroundColor(Color.red); + tableContentsDO[selectedRow][1].setBackgroundColor(Palette.RED); } else {//off when clicked, turn on and update the table to reflect being enabled - tableContentsDO[selectedRow][1].setBackgroundColor(Color.green); + tableContentsDO[selectedRow][1].setBackgroundColor(Palette.GREEN); } jTable1.repaint(); } @@ -284,10 +264,10 @@ public class SearchGuiMulti extends SearchBaseExtended { int selectedRow = jTable1.getSelectedRow(); if (op2Button.isSelected()) { - tableContentsDO[selectedRow][2].setBackgroundColor(Color.red); + tableContentsDO[selectedRow][2].setBackgroundColor(Palette.RED); } else {//off when clicked, turn on and update the table to reflect being enabled - tableContentsDO[selectedRow][2].setBackgroundColor(Color.green); + tableContentsDO[selectedRow][2].setBackgroundColor(Palette.GREEN); } jTable1.repaint(); } @@ -300,14 +280,14 @@ public class SearchGuiMulti extends SearchBaseExtended { for (int row = 0; row < mnemonics.size(); row++) { SLMaskControl temp = new SLMaskControl(); - if (tableContentsDO[row][0].getBackgroundColor().equals(Color.green)) { + if (tableContentsDO[row][0].getBackgroundColor().equals(Palette.GREEN)) { temp.useMnemonic = true; } else { temp.useMnemonic = false; } - if (tableContentsDO[row][1].getBackgroundColor().equals(Color.green)) { + if (tableContentsDO[row][1].getBackgroundColor().equals(Palette.GREEN)) { temp.useOp1 = true; if (ops.get(0).get(mnemonics.get(row)).constant) { temp.useConst = true; @@ -317,7 +297,7 @@ public class SearchGuiMulti extends SearchBaseExtended { temp.useOp1 = false; } - if (tableContentsDO[row][2].getBackgroundColor().equals(Color.green)) { + if (tableContentsDO[row][2].getBackgroundColor().equals(Palette.GREEN)) { temp.useOp2 = true; if (ops.get(1).get(mnemonics.get(row)).constant) { temp.useConst = true; @@ -336,7 +316,7 @@ public class SearchGuiMulti extends SearchBaseExtended { private class DataObject { private String data; - private Color background = Color.white; + private Color background = Colors.BACKGROUND; public DataObject(String data, Color color) { this.data = data; diff --git a/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml b/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml index 076b46b713..4c44167d9b 100644 --- a/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml +++ b/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml @@ -49,10 +49,7 @@ - + @@ -67,6 +64,7 @@ + @@ -382,11 +380,11 @@ - + - + diff --git a/Ghidra/Features/Base/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/Base/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/Base/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/Base/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm index 75d88be43f..fda1271536 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/AutoAnalysisPlugin/AutoAnalysis.htm @@ -165,7 +165,7 @@ with the analyzer.

-

+

Note that multi-user merge does not currently support merging of Program Options (including Analysis Options). Options stored in shared Program database following a conflicting checkin may not reflect option settings specified prior to checkin. @@ -182,9 +182,9 @@ the current program. -

+

Access to stored configurations is not currently - aupported across different versions of Ghidra. + supported across different versions of Ghidra.

@@ -452,7 +452,7 @@

-

+

When using an external GNU demangler, please understand the risks associated with using that version of the software. The demangler_gnu_v2_24 version of the diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataPlugin/Data.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataPlugin/Data.htm index 103809ad82..4319372e67 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/DataPlugin/Data.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/DataPlugin/Data.htm @@ -23,7 +23,7 @@

Data Types

-

Data is created by applying Data Types to bytes in +

Data is created by applying Data Types to bytes in memory.  Data Types interpret bytes as values and provide a visual interpretation of those bytes based on the Data Type used, e.g., a four byte IEEE floating point number or a two byte little endian @@ -583,7 +583,7 @@

 Regardless of how a data type is applied, data is only created if the data type will fit within the available undefined bytes.  

-

Drag from Data Type Manager

+

Drag from Data Type Manager

Use the

Cycle Groups

+ "Cycle__float_double"> Cycle Groups

Cycle Groups are an easy way to apply basic data types (byte, word, float, @@ -679,7 +678,7 @@

-

Favorites

+

Favorites

A Favorite data type is a data type that you use frequently and want to apply @@ -703,7 +702,7 @@ Shortcut.  Key Bindings allow you to assign "hot keys" to any menu item.

-

Recently Used Data Type

+

Recently Used Data Type

The last applied data type is always available at the bottom of the data menu.  By diff --git a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end.htm b/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end.htm index 6c8abbef53..db73da2d09 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/FrontEndPlugin/Ghidra_Front_end.htm @@ -448,12 +448,11 @@ - + - + - + diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm b/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm index 93025be9bf..0e488d20e4 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm @@ -25,7 +25,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-

 

-

A

+

A

Action

@@ -97,7 +97,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

B

+

B

Back Reference

@@ -197,7 +197,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

C

+

C

Call Block Model

@@ -319,7 +319,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

D

+

D

Data (item)

@@ -436,7 +436,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

E

+

E

ELF

@@ -491,7 +491,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

F

+

F

Fall Through Address

@@ -555,7 +555,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

G

+

G

Ghidra

@@ -606,7 +606,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

H

+

H

Hex Integer

@@ -636,7 +636,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

I

+

I

IDA Pro

@@ -688,7 +688,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

K

+

K

Key Binding

@@ -698,7 +698,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

L

+

L

Label 

@@ -756,7 +756,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

M

+

M

@@ -848,7 +848,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

N

+

N

Name Space

@@ -865,7 +865,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

O

+

O

Offcut

@@ -906,7 +906,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

P

+

P

Partitioned Code Model

@@ -1058,7 +1058,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

R

+

R

Read-Only Project

@@ -1108,7 +1108,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

S

+

S

Scalar

@@ -1239,7 +1239,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

T

+

T

Tabbed Window

@@ -1297,7 +1297,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

U

+

U

Unconditional Call

@@ -1352,7 +1352,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

V

+

V

Version Control

@@ -1383,7 +1383,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

W

+

W

Workspace

@@ -1394,7 +1394,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
-

X

+

X

XREF

diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm b/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm index 1b28628dec..4719feaa67 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm @@ -294,16 +294,11 @@
File StatusFile StatusSample Icon in Project Data - TreeSample IconDescriptionDescription
- - - - + - + @@ -398,15 +393,11 @@
-

Tool Options

-
OptionOptionDescriptionDescription
- - - - + - + @@ -445,7 +436,7 @@ of the UI. Doing this effectively creates a Dark Theme, which some users find less visually straining.

-
+

As a prototype feature, this feature has many known issues, including:

diff --git a/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java index 476d3c14c1..f55db72821 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/GhidraOptions.java @@ -15,9 +15,9 @@ */ package ghidra; -import java.awt.Color; import java.awt.event.MouseEvent; +import generic.theme.GColor; import ghidra.framework.options.Options; /** @@ -156,7 +156,7 @@ public interface GhidraOptions { final String HIGHLIGHT_CURSOR_LINE_COLOR = "Cursor." + HIGHLIGHT_CURSOR_LINE_COLOR_OPTION_NAME; - final Color DEFAULT_CURSOR_LINE_COLOR = new Color(232, 242, 254); + final GColor DEFAULT_CURSOR_LINE_COLOR = new GColor("color.bg.currentline.listing"); final String HIGHLIGHT_CURSOR_LINE_OPTION_NAME = "Highlight Cursor Line"; @@ -176,6 +176,7 @@ public interface GhidraOptions { public static enum CURSOR_MOUSE_BUTTON_NAMES { LEFT(MouseEvent.BUTTON1), MIDDLE(MouseEvent.BUTTON2), RIGHT(MouseEvent.BUTTON3); + private int mouseEventID; CURSOR_MOUSE_BUTTON_NAMES(int mouseEventID) { @@ -190,10 +191,9 @@ public interface GhidraOptions { // end cursor highlight final String OPTION_SELECTION_COLOR = "Selection Colors.Selection Color"; - final Color DEFAULT_SELECTION_COLOR = new Color(180, 255, 180); + final GColor DEFAULT_SELECTION_COLOR = new GColor("color.bg.selection.listing"); final String OPTION_HIGHLIGHT_COLOR = "Selection Colors.Highlight Color"; - final Color DEFAULT_HIGHLIGHT_COLOR = new Color(255, 255, 180); + final GColor DEFAULT_HIGHLIGHT_COLOR = new GColor("color.bg.highlight.listing"); final String APPLY_ENABLED = "apply.enabled"; - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/GhidraRun.java b/Ghidra/Features/Base/src/main/java/ghidra/GhidraRun.java index b7e5951772..22ad3f23f7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/GhidraRun.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/GhidraRun.java @@ -38,7 +38,6 @@ import ghidra.program.database.ProgramDB; import ghidra.util.*; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskLauncher; -import ghidra.util.task.TaskMonitorAdapter; /** * Main Ghidra application class. Creates @@ -73,7 +72,6 @@ public class GhidraRun implements GhidraLaunchable { Runnable mainTask = () -> { GhidraApplicationConfiguration configuration = new GhidraApplicationConfiguration(); - configuration.setTaskMonitor(new StatusReportingTaskMonitor()); Application.initializeApplication(layout, configuration); log = LogManager.getLogger(GhidraRun.class); @@ -243,15 +241,3 @@ public class GhidraRun implements GhidraLaunchable { // this exists just to allow access to the constructor } } - -class StatusReportingTaskMonitor extends TaskMonitorAdapter { - @Override - public synchronized void setCancelEnabled(boolean enable) { - // Not permitted - } - - @Override - public void setMessage(String message) { - SplashScreen.updateSplashScreenStatus(message); - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeConstants.java index 520d1c6360..b6975fff0a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeConstants.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeConstants.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,36 +17,37 @@ package ghidra.app.merge; import java.awt.Color; +import generic.theme.GThemeDefaults.Colors.Palette; public interface MergeConstants { - public static final int RESULT = 0; - public static final int LATEST = 1; - public static final int MY = 2; - public static final int ORIGINAL = 3; - public static final String RESULT_TITLE = "Result"; - public static final String ORIGINAL_TITLE = "Original"; - public static final String LATEST_TITLE = "Latest"; - public static final String MY_TITLE = "Checked Out"; - - public Color CONFLICT_COLOR = new Color(140, 0, 0); - public static final Color HIGHLIGHT_COLOR = new Color(230,230,230); - - // The following are standardized names for use in passing resolve - // information between individual merge managers. - // For example: - // the data type merger knows what data type in the result is equivalent - // to a given data type from my checked out program. The code unit and - // function mergers need to be able to get this information so they - // don't unknowingly re-introduce a data type that was already eliminated - // by a data type conflict. - public static final String RESOLVED_LATEST_DTS = "ResolvedLatestDataTypes"; - public static final String RESOLVED_MY_DTS = "ResolvedMyDataTypes"; - public static final String RESOLVED_ORIGINAL_DTS = "ResolvedOriginalDataTypes"; - public static final String RESOLVED_CODE_UNITS = "ResolvedCodeUnits"; - public static final String PICKED_LATEST_CODE_UNITS = "PickedLatestCodeUnits"; - public static final String PICKED_MY_CODE_UNITS = "PickedMyCodeUnits"; - public static final String PICKED_ORIGINAL_CODE_UNITS = "PickedOriginalCodeUnits"; - public static final String RESOLVED_LATEST_SYMBOLS = "ResolvedLatestSymbols"; - public static final String RESOLVED_MY_SYMBOLS = "ResolvedMySymbols"; - public static final String RESOLVED_ORIGINAL_SYMBOLS = "ResolvedOriginalSymbols"; + public static final int RESULT = 0; + public static final int LATEST = 1; + public static final int MY = 2; + public static final int ORIGINAL = 3; + public static final String RESULT_TITLE = "Result"; + public static final String ORIGINAL_TITLE = "Original"; + public static final String LATEST_TITLE = "Latest"; + public static final String MY_TITLE = "Checked Out"; + + public Color CONFLICT_COLOR = Palette.MAROON; + public static final Color HIGHLIGHT_COLOR = Palette.LIGHT_GRAY; + + // The following are standardized names for use in passing resolve + // information between individual merge managers. + // For example: + // the data type merger knows what data type in the result is equivalent + // to a given data type from my checked out program. The code unit and + // function mergers need to be able to get this information so they + // don't unknowingly re-introduce a data type that was already eliminated + // by a data type conflict. + public static final String RESOLVED_LATEST_DTS = "ResolvedLatestDataTypes"; + public static final String RESOLVED_MY_DTS = "ResolvedMyDataTypes"; + public static final String RESOLVED_ORIGINAL_DTS = "ResolvedOriginalDataTypes"; + public static final String RESOLVED_CODE_UNITS = "ResolvedCodeUnits"; + public static final String PICKED_LATEST_CODE_UNITS = "PickedLatestCodeUnits"; + public static final String PICKED_MY_CODE_UNITS = "PickedMyCodeUnits"; + public static final String PICKED_ORIGINAL_CODE_UNITS = "PickedOriginalCodeUnits"; + public static final String RESOLVED_LATEST_SYMBOLS = "ResolvedLatestSymbols"; + public static final String RESOLVED_MY_SYMBOLS = "ResolvedMySymbols"; + public static final String RESOLVED_ORIGINAL_SYMBOLS = "ResolvedOriginalSymbols"; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java index d323b5a605..ef1f0e0736 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java @@ -26,6 +26,7 @@ import docking.options.editor.ButtonPanelFactory; import docking.util.image.ToolIconURL; import docking.widgets.OptionDialog; import docking.widgets.label.*; +import generic.theme.GIcon; import ghidra.app.context.ListingActionContext; import ghidra.app.merge.tool.ListingMergePanel; import ghidra.app.nav.Navigatable; @@ -36,7 +37,6 @@ import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.program.util.ProgramLocation; import ghidra.util.HelpLocation; import ghidra.util.layout.VerticalLayout; -import resources.ResourceManager; /** * Component that displays merge components as needed. @@ -59,7 +59,7 @@ class MergeManagerProvider extends ComponentProviderAdapter { private JButton cancelButton; private boolean wasCanceled; - private ImageIcon MERGE_ICON = ResourceManager.loadImage("images/Merge.png"); + private Icon MERGE_ICON = new GIcon("icon.plugin.merge"); private JPanel mainPanel; public MergeManagerProvider(MergeManagerPlugin plugin, String title) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeProgressPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeProgressPanel.java index 500cdd1164..4528cdd672 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeProgressPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeProgressPanel.java @@ -16,17 +16,18 @@ package ghidra.app.merge; import java.awt.BorderLayout; -import java.awt.Color; import java.util.HashMap; +import java.util.Map; import javax.swing.*; import javax.swing.border.Border; import docking.widgets.label.GIconLabel; import docking.widgets.label.GLabel; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.util.Msg; import ghidra.util.layout.VerticalLayout; -import resources.ResourceManager; /** * The MergeProgressPanel displays the name of each merge phase along with an icon indicating @@ -34,11 +35,10 @@ import resources.ResourceManager; */ public class MergeProgressPanel extends JPanel { - public static ImageIcon DEFINED_ICON = ResourceManager.loadImage("images/bullet_green.png"); - public static ImageIcon IN_PROGRESS_ICON = ResourceManager.loadImage("images/right.png"); - public static ImageIcon COMPLETED_ICON = - ResourceManager.loadImage("images/checkmark_green.gif"); - private HashMap imageMap = new HashMap<>(); + public static Icon DEFINED_ICON = new GIcon("icon.plugin.merge.status.pending"); + public static Icon IN_PROGRESS_ICON = new GIcon("icon.plugin.merge.status.in.progress"); + public static Icon COMPLETED_ICON = new GIcon("icon.plugin.merge.status.complete"); + private Map imageMap = new HashMap<>(); private static int INDENT_IN_PIXELS = 20; /** @@ -52,7 +52,7 @@ public class MergeProgressPanel extends JPanel { private JPanel getProgressTitlePanel() { JPanel phasesTitlePanel = new JPanel(); Border insideBorder = BorderFactory.createEmptyBorder(0, 0, 2, 0); - Border outsideBorder = BorderFactory.createMatteBorder(0, 0, 2, 0, Color.BLUE); + Border outsideBorder = BorderFactory.createMatteBorder(0, 0, 2, 0, Palette.BLUE); Border compoundBorder = BorderFactory.createCompoundBorder(outsideBorder, insideBorder); phasesTitlePanel.setBorder(compoundBorder); BoxLayout bl = new BoxLayout(phasesTitlePanel, BoxLayout.X_AXIS); @@ -139,9 +139,6 @@ public class MergeProgressPanel extends JPanel { return buf.toString(); } - /** - * @param args - */ public static void main(String[] args) { MergeProgressPanel panel = new MergeProgressPanel(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/PhaseProgressPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/PhaseProgressPanel.java index 8d0247b923..a1ea20516b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/PhaseProgressPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/PhaseProgressPanel.java @@ -17,14 +17,12 @@ package ghidra.app.merge; import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import javax.swing.*; import docking.widgets.label.GDLabel; import docking.widgets.label.GIconLabel; -import resources.ResourceManager; +import resources.Icons; /** * The PhaseProgressPanel provides a title, progress bar and message for the current phase that is @@ -33,7 +31,7 @@ import resources.ResourceManager; public class PhaseProgressPanel extends JPanel { private final static String DEFAULT_INFO = "Merge programs in progress..."; - private ImageIcon INFORM_ICON = ResourceManager.loadImage("images/information.png"); + private Icon INFORM_ICON = Icons.INFO_ICON; private JLabel titleLabel; private JProgressBar progressBar; @@ -105,12 +103,7 @@ public class PhaseProgressPanel extends JPanel { doSetMessage(DEFAULT_INFO); // Sets up the timer for updating the GUI. - updateTimer = new Timer(250, new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - update(); - } - }); + updateTimer = new Timer(250, e -> update()); } // Method for use by the timer to update the progress bar or message. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergePanel.java index 98f2478ddc..fc6004f353 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergePanel.java @@ -30,7 +30,7 @@ import ghidra.app.merge.MergeConstants; import ghidra.app.merge.util.ConflictCountPanel; import ghidra.framework.data.DomainObjectMergeManager; import ghidra.program.model.data.*; -import resources.ResourceManager; +import resources.Icons; /** * Panel to select a data type in order to resolve a conflict. @@ -86,9 +86,6 @@ class DataTypeMergePanel extends JPanel { buttonGroup.add(originalRB); } - /** - * - */ int getSelectedOption() { if (latestRB.isSelected()) { return DataTypeMergeManager.OPTION_LATEST; @@ -105,13 +102,10 @@ class DataTypeMergePanel extends JPanel { private void create() { buttonGroup = new ButtonGroup(); - ItemListener listener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - mergeManager.clearStatusText(); - mergeManager.setApplyEnabled(true); - } + ItemListener listener = e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + mergeManager.clearStatusText(); + mergeManager.setApplyEnabled(true); } }; @@ -180,7 +174,7 @@ class DataTypeMergePanel extends JPanel { private JPanel createInfoPanel() { - Icon icon = ResourceManager.loadImage("images/information.png"); + Icon icon = Icons.INFO_ICON; JLabel imageLabel = new GIconLabel(icon); MultiLineLabel label = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java index 66b337e14e..f18266061d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypePanel.java @@ -23,6 +23,7 @@ import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.text.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.merge.MergeConstants; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsDefinition; @@ -39,8 +40,7 @@ import ghidra.util.UniversalID; */ class DataTypePanel extends JPanel { - private static final long serialVersionUID = 1L; - public Color SOURCE_COLOR = new Color(0, 140, 0); + public Color SOURCE_COLOR = Palette.GREEN; private DataType dataType; private JTextPane textPane; private StyledDocument doc; @@ -110,28 +110,28 @@ class DataTypePanel extends JPanel { offsetAttrSet = new SimpleAttributeSet(); offsetAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced"); offsetAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); - offsetAttrSet.addAttribute(StyleConstants.Foreground, Color.BLACK); + offsetAttrSet.addAttribute(StyleConstants.Foreground, Palette.BLACK); contentAttrSet = new SimpleAttributeSet(); contentAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced"); contentAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); - contentAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE); + contentAttrSet.addAttribute(StyleConstants.Foreground, Palette.BLUE); fieldNameAttrSet = new SimpleAttributeSet(); fieldNameAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced"); fieldNameAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); - fieldNameAttrSet.addAttribute(StyleConstants.Foreground, new Color(204, 0, 204)); + fieldNameAttrSet.addAttribute(StyleConstants.Foreground, Palette.MAGENTA); commentAttrSet = new SimpleAttributeSet(); commentAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced"); commentAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); - commentAttrSet.addAttribute(StyleConstants.Foreground, new Color(0, 204, 51)); + commentAttrSet.addAttribute(StyleConstants.Foreground, Palette.LIME); deletedAttrSet = new SimpleAttributeSet(); deletedAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); deletedAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); deletedAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); - deletedAttrSet.addAttribute(StyleConstants.Foreground, Color.RED); + deletedAttrSet.addAttribute(StyleConstants.Foreground, Palette.RED); setDataType(dataType); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchiveMergePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchiveMergePanel.java index 1fd2d12f61..0130697b7c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchiveMergePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchiveMergePanel.java @@ -30,7 +30,7 @@ import ghidra.app.merge.MergeConstants; import ghidra.app.merge.util.ConflictCountPanel; import ghidra.framework.data.DomainObjectMergeManager; import ghidra.program.model.data.SourceArchive; -import resources.ResourceManager; +import resources.Icons; /** * Panel to select a source archive in order to resolve a conflict. @@ -104,13 +104,10 @@ class SourceArchiveMergePanel extends JPanel { private void create() { buttonGroup = new ButtonGroup(); - ItemListener listener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - mergeManager.clearStatusText(); - mergeManager.setApplyEnabled(true); - } + ItemListener listener = e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + mergeManager.clearStatusText(); + mergeManager.setApplyEnabled(true); } }; @@ -175,7 +172,7 @@ class SourceArchiveMergePanel extends JPanel { private JPanel createInfoPanel() { - Icon icon = ResourceManager.loadImage("images/information.png"); + Icon icon = Icons.INFO_ICON; JLabel imageLabel = new GIconLabel(icon); MultiLineLabel label = new MultiLineLabel( diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchivePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchivePanel.java index 9a8afdf1a8..be7b60743e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchivePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/SourceArchivePanel.java @@ -15,17 +15,18 @@ */ package ghidra.app.merge.datatypes; -import ghidra.program.model.data.ArchiveType; -import ghidra.program.model.data.SourceArchive; - import java.awt.BorderLayout; -import java.awt.Color; import java.util.Date; import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.text.*; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.program.model.data.ArchiveType; +import ghidra.program.model.data.SourceArchive; +import ghidra.util.Msg; + /** * Panel to show the contents of a Source Archive. */ @@ -37,47 +38,47 @@ class SourceArchivePanel extends JPanel { private SimpleAttributeSet headingAttrSet; private SimpleAttributeSet valueAttrSet; private SimpleAttributeSet deletedAttrSet; - + SourceArchivePanel() { super(new BorderLayout()); create(); } - + public void setSourceArchive(SourceArchive sourceArchive) { this.sourceArchive = sourceArchive; textPane.setText(""); - formatSourceArchive(); + formatSourceArchive(); textPane.setCaretPosition(0); } - + private void create() { - textPane = new JTextPane(); + textPane = new JTextPane(); doc = textPane.getStyledDocument(); add(textPane, BorderLayout.CENTER); textPane.setEditable(false); - + headingAttrSet = new SimpleAttributeSet(); headingAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced"); - headingAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12)); - headingAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE); - + headingAttrSet.addAttribute(StyleConstants.FontSize, 12); + headingAttrSet.addAttribute(StyleConstants.Foreground, Palette.BLUE); + valueAttrSet = new SimpleAttributeSet(); valueAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); - valueAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11)); + valueAttrSet.addAttribute(StyleConstants.FontSize, 11); valueAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); deletedAttrSet = new SimpleAttributeSet(); deletedAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); - deletedAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12)); + deletedAttrSet.addAttribute(StyleConstants.FontSize, 12); deletedAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); - deletedAttrSet.addAttribute(StyleConstants.Foreground, Color.RED); - + deletedAttrSet.addAttribute(StyleConstants.Foreground, Palette.RED); + setSourceArchive(null); } - + private void formatSourceArchive() { if (sourceArchive == null) { - insertString("\n\nDeleted", deletedAttrSet); + insertString("\n\nDeleted", deletedAttrSet); return; } // formatArchiveID(); @@ -87,62 +88,55 @@ class SourceArchivePanel extends JPanel { formatSyncTime(); formatDirtyFlag(); } - + @SuppressWarnings("unused") private void formatArchiveID() { insertString(" Archive ID: ", headingAttrSet); insertString(sourceArchive.getSourceArchiveID().getValue() + "\n", valueAttrSet); } - + private void formatName() { insertString("Name: ", headingAttrSet); insertString(sourceArchive.getName() + "\n", valueAttrSet); } - + @SuppressWarnings("unused") private void formatFileID() { insertString(" File ID: ", headingAttrSet); insertString(sourceArchive.getDomainFileID() + "\n", valueAttrSet); } - + @SuppressWarnings("unused") private void formatType() { ArchiveType archiveType = sourceArchive.getArchiveType(); String typeString = (archiveType == ArchiveType.FILE) ? "File Archive" : (archiveType == ArchiveType.PROGRAM) ? "Program" - : (archiveType == ArchiveType.PROJECT) ? "Project Archive" - : (archiveType == ArchiveType.BUILT_IN) ? "Built-In" - : "Invalid"; + : (archiveType == ArchiveType.PROJECT) ? "Project Archive" + : (archiveType == ArchiveType.BUILT_IN) ? "Built-In" + : "Invalid"; insertString(" Type: ", headingAttrSet); insertString(typeString + "\n", valueAttrSet); } - + private void formatSyncTime() { String syncTime = new Date(sourceArchive.getLastSyncTime()).toString(); insertString("Last Sync Time: ", headingAttrSet); insertString(syncTime + "\n", valueAttrSet); } - + private void formatDirtyFlag() { insertString("Changed Since Last Sync? ", headingAttrSet); insertString((sourceArchive.isDirty() ? "yes" : "no") + "\n", valueAttrSet); } - -// private String pad(String str, int length) { -// StringBuffer sb = new StringBuffer(str); -// int len = length - str.length(); -// for (int i=0; i" + value + ""); + buf.append("" + value + ""); } private void addAddress(StringBuffer buf, Address addr) { buf.append( - "" + HTMLUtilities.escapeHTML(addr.toString()) + ""); + "" + HTMLUtilities.escapeHTML(addr.toString()) + + ""); } private void updateWest() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalAddConflictPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalAddConflictPanel.java index 09c68737e8..0a22b15bcc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalAddConflictPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalAddConflictPanel.java @@ -26,6 +26,7 @@ import docking.widgets.button.GRadioButton; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.label.GIconLabel; +import generic.theme.GIcon; import ghidra.app.merge.MergeConstants; import ghidra.app.merge.MergeManager; import ghidra.app.merge.util.ConflictCountPanel; @@ -45,7 +46,6 @@ import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.ExternalLocation; -import resources.ResourceManager; import resources.icons.EmptyIcon; /** @@ -60,8 +60,8 @@ class ExternalAddConflictPanel extends JPanel implements CodeFormatService { public static final String MERGE_BOTH_BUTTON_NAME = ExternalFunctionMerger.MERGE_BOTH_BUTTON_NAME; - private static Icon hideIcon = ResourceManager.loadImage("images/collapse.gif"); - private static Icon showIcon = ResourceManager.loadImage("images/expand.gif"); + 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 DomainObjectMergeManager mergeManager; private int totalConflicts; @@ -291,18 +291,18 @@ class ExternalAddConflictPanel extends JPanel implements CodeFormatService { class ShowHeaderButton extends EmptyBorderButton { ShowHeaderButton() { - super(showIcon); + super(SHOW_ICON); setFocusable(false); setToolTipText("Toggle Format Header"); addActionListener(e -> { if (isSelected()) { setSelected(false); - setIcon(showIcon); + setIcon(SHOW_ICON); latestPanel.showHeader(false); } else { setSelected(true); - setIcon(hideIcon); + setIcon(HIDE_ICON); latestPanel.showHeader(true); } }); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalConflictInfoPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalConflictInfoPanel.java index 8dd01a4d7c..8c386b1c90 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalConflictInfoPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalConflictInfoPanel.java @@ -21,6 +21,7 @@ import javax.swing.*; import javax.swing.border.TitledBorder; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.merge.util.ConflictUtility; /** @@ -103,11 +104,11 @@ public class ExternalConflictInfoPanel extends JPanel { } private void addCount(StringBuffer buf, int value) { - buf.append("" + value + ""); + buf.append("" + value + ""); } private void addName(StringBuffer buf, String name) { - buf.append("" + name + ""); + buf.append("" + name + ""); } private void updateWest() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionTagMerger.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionTagMerger.java index 07ab588388..03ccec54df 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionTagMerger.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionTagMerger.java @@ -15,15 +15,14 @@ */ package ghidra.app.merge.listing; -import java.awt.Color; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.*; import javax.swing.SwingUtilities; -import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.merge.*; import ghidra.app.util.HelpTopics; import ghidra.program.database.function.FunctionManagerDB; @@ -102,7 +101,6 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { // the middle of resolving multiple conflicts. private long currentlyMergingTagID; - /** * Constructor. * @@ -160,7 +158,6 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { } } - @Override public void merge(TaskMonitor monitor) throws Exception { autoMerge(); @@ -270,7 +267,7 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { // If the source program tag doesn't exist then the user has chosen to // keep a deleted tag, so make sure the corresponding tag in Result // is deleted as well. - if (tag == null ) { + if (tag == null) { if (resultTag != null) { resultTag.delete(); } @@ -279,8 +276,9 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { // If the source tag exists, but the Result tag doesn't, we have to create a new // one in Result. else if (resultTag == null) { - functionManagerDBResult.getFunctionTagManager().createFunctionTag(tag.getName(), - tag.getComment()); + functionManagerDBResult.getFunctionTagManager() + .createFunctionTag(tag.getName(), + tag.getComment()); } // If the source tag exists and Result tag exists, just update the tag @@ -409,7 +407,7 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { functionTag.setName(tagMy.getName()); functionTag.setComment(tagMy.getComment()); } - + } } } @@ -574,37 +572,29 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { private void showMergePanel(long id, TaskMonitor monitor) { try { - final ChangeListener changeListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - conflictOption = conflictPanel.getSelectedOptions(); - if (conflictOption == ASK_USER || conflictOption == CANCELED) { - if (mergeManager != null) { - mergeManager.setApplyEnabled(false); - } - return; - } + final ChangeListener changeListener = e -> { + conflictOption = conflictPanel.getSelectedOptions(); + if (conflictOption == ASK_USER || conflictOption == CANCELED) { if (mergeManager != null) { - mergeManager.clearStatusText(); + mergeManager.setApplyEnabled(false); } - try { - merge(conflictOption, monitor); - if (mergeManager != null) { - mergeManager.setApplyEnabled(true); - } - } - catch (CancelledException e1) { - // user cancel - no need to log + return; + } + if (mergeManager != null) { + mergeManager.clearStatusText(); + } + try { + merge(conflictOption, monitor); + if (mergeManager != null) { + mergeManager.setApplyEnabled(true); } + } + catch (CancelledException e1) { + // user cancel - no need to log + } - } }; - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - setupConflictPanel(id, changeListener, monitor); - } - }); + SwingUtilities.invokeAndWait(() -> setupConflictPanel(id, changeListener, monitor)); } catch (InterruptedException | InvocationTargetException e) { Msg.error(this, "Unexpected error showing merge panel for tag " + id, e); @@ -712,19 +702,20 @@ public class FunctionTagMerger implements MergeResolver, ListingMergeConstants { * @return */ private String getConflictInfo(TaskMonitor monitor) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append( "
" + "Resolving conflict " + (monitor.getProgress() + 1) + " of " + tagConflicts.size() + "
"); buf.append(HTMLUtilities.HTML_NEW_LINE); buf.append("Tag Id:"); buf.append(HTMLUtilities.spaces(21)); - buf.append(HTMLUtilities.colorString(Color.BLUE, String.valueOf(currentlyMergingTagID))); + buf.append( + HTMLUtilities.colorString(Messages.NORMAL, String.valueOf(currentlyMergingTagID))); buf.append(HTMLUtilities.HTML_NEW_LINE); buf.append("Reason for Conflict:"); buf.append(HTMLUtilities.spaces(1)); buf.append( - HTMLUtilities.colorString(Color.BLUE, tagConflicts.get(currentlyMergingTagID))); + HTMLUtilities.colorString(Messages.NORMAL, tagConflicts.get(currentlyMergingTagID))); buf.append(HTMLUtilities.HTML_NEW_LINE); buf.append(HTMLUtilities.HTML_NEW_LINE); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VariousChoicesPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VariousChoicesPanel.java index fc9a0f6435..db28e89df4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VariousChoicesPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VariousChoicesPanel.java @@ -15,22 +15,12 @@ */ package ghidra.app.merge.listing; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; +import java.awt.*; +import java.awt.event.*; import java.util.ArrayList; import java.util.Iterator; -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.SwingConstants; +import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeListener; @@ -39,6 +29,7 @@ import docking.widgets.button.GRadioButton; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GDHtmlLabel; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.app.merge.util.ConflictUtility; import ghidra.util.HTMLUtilities; import ghidra.util.layout.MaximizeSpecificColumnGridLayout; @@ -55,7 +46,7 @@ public class VariousChoicesPanel extends ConflictPanel { private final static long serialVersionUID = 1; private static final Border UNDERLINE_BORDER = - BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK); + BorderFactory.createMatteBorder(0, 0, 1, 0, Java.BORDER); private JPanel rowPanel; private GDHtmlLabel headerLabel; @@ -76,7 +67,7 @@ public class VariousChoicesPanel extends ConflictPanel { /** * Constructor for a various choices panel. - * @param isDoubleBuffered + * @param isDoubleBuffered true if double buffered */ public VariousChoicesPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); @@ -199,17 +190,14 @@ public class VariousChoicesPanel extends ConflictPanel { MyRadioButton[] rb = new MyRadioButton[choices.length]; final int row = rows.size(); final ChoiceRow choiceRow = new ChoiceRow(titleComp, rb); - ItemListener itemListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - adjustUseForAllEnablement(); - if (listener != null) { - Object source = e.getSource(); - if (((MyRadioButton) source).isSelected()) { - ResolveConflictChangeEvent re = - new ResolveConflictChangeEvent(source, row, choiceRow.getChoice()); - listener.stateChanged(re); - } + ItemListener itemListener = e -> { + adjustUseForAllEnablement(); + if (listener != null) { + Object source = e.getSource(); + if (((MyRadioButton) source).isSelected()) { + ResolveConflictChangeEvent re = + new ResolveConflictChangeEvent(source, row, choiceRow.getChoice()); + listener.stateChanged(re); } } }; @@ -246,15 +234,12 @@ public class VariousChoicesPanel extends ConflictPanel { MyCheckBox[] cb = new MyCheckBox[choices.length]; final int row = rows.size(); final ChoiceRow choiceRow = new ChoiceRow(titleComp, cb); - ItemListener itemListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - adjustUseForAllEnablement(); - if (listener != null) { - ResolveConflictChangeEvent re = - new ResolveConflictChangeEvent(e.getSource(), row, choiceRow.getChoice()); - listener.stateChanged(re); - } + ItemListener itemListener = e -> { + adjustUseForAllEnablement(); + if (listener != null) { + ResolveConflictChangeEvent re = + new ResolveConflictChangeEvent(e.getSource(), row, choiceRow.getChoice()); + listener.stateChanged(re); } }; for (int i = 0; i < choices.length; i++) { @@ -291,8 +276,8 @@ public class VariousChoicesPanel extends ConflictPanel { rowPanel.add(choiceRow.titleLabel); - for (int i = 0; i < choiceRow.rb.length; i++) { - rowPanel.add(choiceRow.rb[i]); + for (JComponent element : choiceRow.rb) { + rowPanel.add(element); } if (row == 0) { add(rowPanel, BorderLayout.CENTER); @@ -303,8 +288,8 @@ public class VariousChoicesPanel extends ConflictPanel { ChoiceRow cr = rows.get(rowNum); rowPanel.remove(cr.titleLabel); JComponent[] comps = cr.rb; - for (int i = 0; i < comps.length; i++) { - rowPanel.remove(comps[i]); + for (JComponent comp : comps) { + rowPanel.remove(comp); } rows.remove(rowNum); } @@ -404,8 +389,7 @@ public class VariousChoicesPanel extends ConflictPanel { } private void removeListeners(ChoiceRow cr) { - for (int i = 0; i < cr.rb.length; i++) { - JComponent comp = cr.rb[i]; + for (JComponent comp : cr.rb) { if (comp instanceof MyRadioButton) { MyRadioButton rb = (MyRadioButton) comp; ItemListener[] listeners = rb.getItemListeners(); @@ -496,8 +480,8 @@ public class VariousChoicesPanel extends ConflictPanel { } boolean hasChoices() { - for (int i = 0; i < rb.length; i++) { - if ((rb[i] instanceof MyRadioButton) || (rb[i] instanceof MyCheckBox)) { + for (JComponent element : rb) { + if ((element instanceof MyRadioButton) || (element instanceof MyCheckBox)) { return true; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VerticalChoicesPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VerticalChoicesPanel.java index 2976a74aee..b131ab07e7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VerticalChoicesPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/VerticalChoicesPanel.java @@ -15,27 +15,12 @@ */ package ghidra.app.merge.listing; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Insets; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; +import java.awt.*; +import java.awt.event.*; import java.util.ArrayList; -import java.util.Iterator; import java.util.ListIterator; -import javax.swing.BorderFactory; -import javax.swing.ButtonGroup; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.SwingConstants; +import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeListener; @@ -44,6 +29,7 @@ import docking.widgets.button.GRadioButton; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GDHtmlLabel; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.app.merge.util.ConflictUtility; import ghidra.util.HTMLUtilities; import ghidra.util.datastruct.LongArrayList; @@ -88,17 +74,11 @@ public class VerticalChoicesPanel extends ConflictPanel { private Insets textVsButtonInsets; private Insets textVsCheckBoxInsets; - /** - * Creates an empty VerticalChoicesPanel - */ public VerticalChoicesPanel() { super(); init(); } - /** - * @param isDoubleBuffered - */ public VerticalChoicesPanel(boolean isDoubleBuffered) { super(isDoubleBuffered); init(); @@ -179,8 +159,8 @@ public class VerticalChoicesPanel extends ConflictPanel { JComponent[] headerComps = getRowComponents(0); if (headerComps != null) { // remove the header - for (int i = 0; i < headerComps.length; i++) { - rowPanel.remove(headerComps[i]); + for (JComponent headerComp : headerComps) { + rowPanel.remove(headerComp); } headerComps = null; if (rowComps.isEmpty()) { @@ -196,7 +176,8 @@ public class VerticalChoicesPanel extends ConflictPanel { else { rowTypes.set(0, (long) HEADER); } - if ((items != null) && (items.length > 0)) { + + if (items.length > 0) { if (rows.isEmpty()) { rows.add(0, items); } @@ -209,7 +190,7 @@ public class VerticalChoicesPanel extends ConflictPanel { headerComps[i] = new MyLabel(items[i]); headerComps[i].setName(getComponentName(0, i)); setRowComponent(headerComps[i], 0, i, defaultInsets); - headerComps[i].setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK)); + headerComps[i].setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Java.BORDER)); } } rowPanel.validate(); @@ -278,14 +259,11 @@ public class VerticalChoicesPanel extends ConflictPanel { final MyRadioButton firstComp = new MyRadioButton(items[0], conflictOption); group.add(firstComp); firstComp.setName(name); - ItemListener itemListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (listener != null && ((JRadioButton) e.getSource()).isSelected()) { - ResolveConflictChangeEvent event = - new ResolveConflictChangeEvent(firstComp, row, getSelectedOptions()); - listener.stateChanged(event); - } + ItemListener itemListener = e -> { + if (listener != null && ((JRadioButton) e.getSource()).isSelected()) { + ResolveConflictChangeEvent event = + new ResolveConflictChangeEvent(firstComp, row, getSelectedOptions()); + listener.stateChanged(event); } }; firstComp.addItemListener(itemListener); @@ -315,12 +293,9 @@ public class VerticalChoicesPanel extends ConflictPanel { rows.add(items); MyCheckBox firstComp = new MyCheckBox(items[0], conflictOption); firstComp.setName(name); - ItemListener itemListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (listener != null) { - listener.stateChanged(null); - } + ItemListener itemListener = e -> { + if (listener != null) { + listener.stateChanged(null); } }; firstComp.addItemListener(itemListener); @@ -432,9 +407,6 @@ public class VerticalChoicesPanel extends ConflictPanel { return count; } - /** - * @return - */ protected int getSelectedOptions() { int option = 0; for (int row = 0; row < rows.size(); row++) { @@ -449,11 +421,6 @@ public class VerticalChoicesPanel extends ConflictPanel { return option; } - /** - * @param row - * @param i - * @return - */ private JComponent getComponent(int row, int column) { JComponent[] comps = getRowComponents(row); if (column < comps.length) { @@ -639,8 +606,7 @@ public class VerticalChoicesPanel extends ConflictPanel { int rowCount = rowComps.size(); for (int row = 0; row < rowCount; row++) { JComponent[] comps = getRowComponents(row); - for (int i = 0; i < comps.length; i++) { - JComponent component = comps[i]; + for (JComponent component : comps) { if (component instanceof MyRadioButton && ((MyRadioButton) component).isSelected()) { conflictOption |= ((MyRadioButton) component).option; @@ -666,8 +632,8 @@ public class VerticalChoicesPanel extends ConflictPanel { */ @Override public boolean hasChoice() { - for (Iterator iterator = rowTypes.iterator(); iterator.hasNext();) { - long rowType = iterator.next().longValue(); + for (Long rowType2 : rowTypes) { + long rowType = rowType2.longValue(); if (rowType == RADIO_BUTTON || rowType == CHECK_BOX) { return true; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ListingMergePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ListingMergePanel.java index 7786c510cc..4d31877284 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ListingMergePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ListingMergePanel.java @@ -28,6 +28,7 @@ import docking.widgets.checkbox.GCheckBox; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.fieldpanel.support.BackgroundColorModel; +import generic.theme.GIcon; import ghidra.app.merge.MergeConstants; import ghidra.app.nav.Navigatable; import ghidra.app.plugin.core.codebrowser.hover.*; @@ -54,12 +55,11 @@ import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import ghidra.util.exception.NotYetImplementedException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class ListingMergePanel extends JPanel implements MergeConstants, FocusListener, CodeFormatService { - private static Icon hideIcon = ResourceManager.loadImage("images/collapse.gif"); - private static Icon showIcon = ResourceManager.loadImage("images/expand.gif"); + 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; @@ -297,9 +297,8 @@ public class ListingMergePanel extends JPanel } /** - * Color the background of all 4 listings to the indicated color for - * the indicated addresses. - * @param addrSet + * Color the background of all 4 listings to the indicated color for the indicated addresses. + * @param addrSet the addresses */ public void paintAllBackgrounds(AddressSetView addrSet) { backgroundColorModel.setAddressSet(addrSet); @@ -509,18 +508,18 @@ public class ListingMergePanel extends JPanel private class ShowHeaderButton extends EmptyBorderButton { ShowHeaderButton() { - super(showIcon); + super(SHOW_ICON); setFocusable(false); setToolTipText("Toggle Format Header"); addActionListener(e -> { if (isSelected()) { setSelected(false); - setIcon(showIcon); + setIcon(SHOW_ICON); listingPanels[RESULT].showHeader(false); } else { setSelected(true); - setIcon(hideIcon); + setIcon(HIDE_ICON); listingPanels[RESULT].showHeader(true); } }); @@ -616,14 +615,12 @@ public class ListingMergePanel extends JPanel } class LockComponent extends GCheckBox { - private static final Icon lock = ResourceManager.loadImage("images/lock.gif"); - private static final Icon unlock = ResourceManager.loadImage("images/unlock.gif"); LockComponent() { - super(unlock); + super(new GIcon("icon.plugin.merge.conflict.unlock")); setToolTipText("Lock/Unlock with other views"); setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0)); - setSelectedIcon(lock); + setSelectedIcon(new GIcon("icon.plugin.merge.conflict.lock")); setSelected(true); } @@ -635,26 +632,3 @@ class LockComponent extends GCheckBox { setSelected(lock); } } -/*** -// class LockComponent extends ToolbarButton { -// private static final Icon lock = ResourceManager.loadImage("images/lock.gif"); -// private static final Icon unlock = ResourceManager.loadImage("images/unlock.gif"); -// LockComponent() { -// super(unlock); -// setBorder(BorderFactory.createEmptyBorder(0,2,0,2)); -// setSelectedIcon(lock); -// setSelected(true); -// addActionListener(new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// setSelected(!isSelected()); -// } -// }); -// } -// boolean isLocked() { -// return isSelected(); -// } -// void setLocked(boolean lock) { -// setSelected(lock); -// } -// } - ***/ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ViewInstructionDetailsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ViewInstructionDetailsAction.java index c1da04e5b4..97910b13c5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ViewInstructionDetailsAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tool/ViewInstructionDetailsAction.java @@ -15,15 +15,8 @@ */ package ghidra.app.merge.tool; -import ghidra.app.context.ListingActionContext; -import ghidra.app.context.ListingContextAction; -import ghidra.app.merge.listing.CodeUnitDetails; -import ghidra.program.model.address.Address; -import ghidra.program.model.listing.*; -import ghidra.program.util.ProgramLocation; -import ghidra.util.HelpLocation; - -import java.awt.*; +import java.awt.Dimension; +import java.awt.Insets; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; @@ -33,6 +26,14 @@ import docking.DialogComponentProvider; import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.fieldpanel.FieldPanel; +import generic.theme.Gui; +import ghidra.app.context.ListingActionContext; +import ghidra.app.context.ListingContextAction; +import ghidra.app.merge.listing.CodeUnitDetails; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.*; +import ghidra.program.util.ProgramLocation; +import ghidra.util.HelpLocation; public class ViewInstructionDetailsAction extends ListingContextAction { @@ -47,8 +48,8 @@ public class ViewInstructionDetailsAction extends ListingContextAction { setKeyBindingData(new KeyBindingData(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); setEnabled(true); - setDescription("Display a dialog indicating details, such as references, for the " - + "instruction at the current cursor location."); + setDescription("Display a dialog indicating details, such as references, for the " + + "instruction at the current cursor location."); setHelpLocation(HELP_LOCATION); } @@ -87,13 +88,11 @@ public class ViewInstructionDetailsAction extends ListingContextAction { } private JScrollPane createDetailsPane(String details) { - Font font = new Font("Monospaced", Font.PLAIN, 12); - JTextArea textArea = new JTextArea(); + Gui.registerFont(textArea, "font.monospaced"); textArea.setLineWrap(false); textArea.setEditable(false); textArea.setMargin(new Insets(5, 5, 5, 5)); - textArea.setFont(font); textArea.setOpaque(true); textArea.setCaretPosition(0); textArea.setText(details); @@ -102,8 +101,10 @@ public class ViewInstructionDetailsAction extends ListingContextAction { JViewport vp = scrolledDetails.getViewport(); vp.add(textArea); - scrolledDetails.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrolledDetails.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + scrolledDetails + .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrolledDetails + .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); return scrolledDetails; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/NameConflictsPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/NameConflictsPanel.java index a1195cd901..0240c47d96 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/NameConflictsPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/NameConflictsPanel.java @@ -16,7 +16,6 @@ package ghidra.app.merge.tree; import java.awt.BorderLayout; -import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.*; @@ -27,7 +26,7 @@ import docking.widgets.label.GDLabel; import docking.widgets.label.GIconLabel; import ghidra.app.merge.MergeConstants; import ghidra.program.model.listing.Program; -import resources.ResourceManager; +import resources.Icons; /** * Panel to get user input to resolve name conflicts when private name of tree @@ -129,7 +128,7 @@ class NameConflictsPanel extends JPanel { iconPanel.setLayout(new BoxLayout(iconPanel, BoxLayout.X_AXIS)); conflictsLabel = new GDLabel("'My' name already exists in Latest Version"); - ImageIcon icon = ResourceManager.loadImage("images/information.png"); + Icon icon = Icons.INFO_ICON; iconPanel.add(new GIconLabel(icon)); iconPanel.add(Box.createHorizontalStrut(5)); iconPanel.add(conflictsLabel); @@ -158,12 +157,9 @@ class NameConflictsPanel extends JPanel { panel.add(rbPanel, BorderLayout.CENTER); add(panel); - ItemListener itemListener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (listener != null) { - listener.stateChanged(null); - } + ItemListener itemListener = e -> { + if (listener != null) { + listener.stateChanged(null); } }; keepOtherRB.addItemListener(itemListener); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/TreeChangePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/TreeChangePanel.java index 9bc47d765d..09b03e4193 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/TreeChangePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/tree/TreeChangePanel.java @@ -21,8 +21,11 @@ import javax.swing.*; import docking.widgets.label.GDLabel; import docking.widgets.label.GIconLabel; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.layout.PairLayout; -import resources.ResourceManager; +import resources.Icons; /** * Panel to show whether tree name and tree structure changed. @@ -39,11 +42,10 @@ class TreeChangePanel extends JPanel { private JLabel nameIconLabel; private JLabel structureIconLabel; - private final static ImageIcon CHANGED_ICON = ResourceManager.loadImage("images/changed16.gif"); - private final static ImageIcon NO_CHANGE_ICON = - ResourceManager.loadImage("images/EmptyIcon16.gif"); - private final static Color CHANGED_COLOR = Color.BLACK; - private final static Color NO_CHANGE_COLOR = Color.GRAY; + private final static Icon CHANGED_ICON = new GIcon("icon.plugin.merge.changed"); + private final static Icon NO_CHANGE_ICON = Icons.EMPTY_ICON; + private final static Color CHANGED_COLOR = Colors.FOREGROUND; + private final static Color NO_CHANGE_COLOR = Messages.HINT; TreeChangePanel(String title) { super(new BorderLayout()); @@ -73,7 +75,7 @@ class TreeChangePanel extends JPanel { treeNameLabel = new GDLabel("Tree Name"); Font font = treeNameLabel.getFont(); - font = new Font(font.getName(), Font.BOLD, font.getSize()); + font = font.deriveFont(Font.BOLD); treeNameLabel.setFont(font); nameLabel = new GDLabel("Name Changed"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/util/ConflictCountPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/util/ConflictCountPanel.java index 970ebc0632..66b513876e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/util/ConflictCountPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/util/ConflictCountPanel.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +16,13 @@ package ghidra.app.merge.util; import java.awt.BorderLayout; -import java.awt.Color; import javax.swing.*; import javax.swing.text.*; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.merge.MergeConstants; +import ghidra.util.Msg; /** * Panel that shows the current conflict number and the total number of @@ -45,6 +45,7 @@ public class ConflictCountPanel extends JPanel { super(new BorderLayout()); create(); } + /** * Update the counts, e.g., Conflict # 1 of 3. * @param currentCount current @@ -52,39 +53,41 @@ public class ConflictCountPanel extends JPanel { */ public void updateCount(int currentCount, int totalCount) { textPane.setText(""); - + int offset = doc.getLength(); try { doc.insertString(offset, "Conflict # ", textAttrSet); offset = doc.getLength(); - doc.insertString(offset, " "+currentCount +" ", countAttrSet); + doc.insertString(offset, " " + currentCount + " ", countAttrSet); offset = doc.getLength(); doc.insertString(offset, " of ", textAttrSet); offset = doc.getLength(); - doc.insertString(offset, " "+totalCount +" ", countAttrSet); - } catch (BadLocationException e) { + doc.insertString(offset, " " + totalCount + " ", countAttrSet); } - + catch (BadLocationException e) { + Msg.debug(this, "Exception updating text", e); + } + } private void create() { - + setBorder(BorderFactory.createTitledBorder("Current Conflict")); textPane = new JTextPane(); textPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 0)); textPane.setEditable(false); add(textPane); - + doc = textPane.getStyledDocument(); - + textPane.setBackground(getBackground()); - + SimpleAttributeSet set = new SimpleAttributeSet(); set.addAttribute(StyleConstants.Bold, Boolean.TRUE); - set.addAttribute(StyleConstants.Foreground, Color.RED); + set.addAttribute(StyleConstants.Foreground, Messages.ERROR); textAttrSet = new SimpleAttributeSet(); - textAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12)); + textAttrSet.addAttribute(StyleConstants.FontSize, 12); countAttrSet = new SimpleAttributeSet(); countAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/DecoratorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/DecoratorPanel.java index 5cdf223f49..35c7ddf2bf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/DecoratorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/DecoratorPanel.java @@ -20,24 +20,24 @@ import java.awt.Color; import javax.swing.*; +import generic.theme.GColor; + public class DecoratorPanel extends JPanel { - + + private static final Color DISCONNECTED = new GColor("color.border.provider.disconnected"); + public DecoratorPanel(JComponent component, boolean isConnected) { setLayout(new BorderLayout()); add(component); - setConnected( isConnected ); - } - - public void setConnected( boolean isConnected ) { - if ( !isConnected ) { - setBorder( BorderFactory.createLineBorder( Color.ORANGE, 2 ) ); - } - else { - setBorder( BorderFactory.createEmptyBorder() ); - } + setConnected(isConnected); } -// public void setNorthPanel(JComponent comp) { -// add(comp, BorderLayout.NORTH); -// } + public void setConnected(boolean isConnected) { + if (!isConnected) { + setBorder(BorderFactory.createLineBorder(DISCONNECTED, 2)); + } + else { + setBorder(BorderFactory.createEmptyBorder()); + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/ListingPanelContainer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/ListingPanelContainer.java index 49190d06f3..5c4061d60a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/ListingPanelContainer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/ListingPanelContainer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +15,18 @@ */ package ghidra.app.nav; -import ghidra.app.util.viewer.util.TitledPanel; - import java.awt.BorderLayout; import java.awt.Color; import javax.swing.*; +import generic.theme.GColor; +import ghidra.app.util.viewer.util.TitledPanel; + public class ListingPanelContainer extends JPanel { + private static final Color DISCONNECTED = new GColor("color.border.provider.disconnected"); + private JSplitPane splitPane; private TitledPanel leftTitlePanel; private TitledPanel rightTitlePanelPanel; @@ -35,7 +37,7 @@ public class ListingPanelContainer extends JPanel { this.leftListingPanel = leftListingPanel; setLayout(new BorderLayout()); add(leftListingPanel); - setConnnected( isConnected ); + setConnnected(isConnected); } public ListingPanelContainer(JComponent leftListingPanel, JComponent rightListingPanel, @@ -46,12 +48,12 @@ public class ListingPanelContainer extends JPanel { setOtherPanel(rightListingPanel, leftTitle, rightTitle); } - public void setConnnected( boolean isConnected ) { - if ( !isConnected ) { - setBorder( BorderFactory.createLineBorder( Color.ORANGE, 2 ) ); + public void setConnnected(boolean isConnected) { + if (!isConnected) { + setBorder(BorderFactory.createLineBorder(DISCONNECTED, 2)); } else { - setBorder( BorderFactory.createEmptyBorder() ); + setBorder(BorderFactory.createEmptyBorder()); } } @@ -59,7 +61,8 @@ public class ListingPanelContainer extends JPanel { removeAll(); leftTitlePanel = new TitledPanel(leftTitle, leftListingPanel, 20); rightTitlePanelPanel = new TitledPanel(rightTitle, rightListingPanel, 20); - splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftTitlePanel, rightTitlePanelPanel); + splitPane = + new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftTitlePanel, rightTitlePanelPanel); splitPane.setDividerLocation(0.5); splitPane.setResizeWeight(0.5); add(splitPane, BorderLayout.CENTER); @@ -83,7 +86,8 @@ public class ListingPanelContainer extends JPanel { } public void setOrientation(boolean isSideBySide) { - splitPane.setOrientation(isSideBySide ? JSplitPane.HORIZONTAL_SPLIT : JSplitPane.VERTICAL_SPLIT); + splitPane.setOrientation( + isSideBySide ? JSplitPane.HORIZONTAL_SPLIT : JSplitPane.VERTICAL_SPLIT); splitPane.setDividerLocation(0.5); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/NavigatableIconFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/NavigatableIconFactory.java index 6285ab7611..8899e862ac 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/NavigatableIconFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/NavigatableIconFactory.java @@ -21,6 +21,8 @@ import java.awt.Point; import javax.swing.Icon; import javax.swing.ImageIcon; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import resources.MultiIcon; import resources.ResourceManager; import resources.icons.OvalColorIcon; @@ -28,8 +30,7 @@ import resources.icons.TranslateIcon; public class NavigatableIconFactory { - private static final ImageIcon SNAPSHOT_ICON = - ResourceManager.loadImage("images/camera-photo.png"); + private static final Icon SNAPSHOT_ICON = new GIcon("icon.provider.clone"); public static ImageIcon createSnapshotOverlayIcon(Icon primaryIcon) { MultiIcon newOuterIcon = new MultiIcon(primaryIcon); @@ -50,7 +51,7 @@ public class NavigatableIconFactory { private static ImageIcon getHighlightIcon(Icon primaryIcon) { int primaryWidth = primaryIcon.getIconWidth(); int primaryHeight = primaryIcon.getIconHeight(); - Color color = new Color(255, 255, 0, 255); + Color color = Palette.YELLOW; return ResourceManager.getImageIcon( new OvalColorIcon(color, primaryWidth + 4, primaryHeight + 4)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java index 0b3b5dd01e..d50651da09 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisEnablementTableModel.java @@ -23,10 +23,11 @@ import javax.swing.JComponent; import javax.swing.JTable; import docking.widgets.table.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; import ghidra.framework.plugintool.ServiceProviderStub; -import ghidra.util.ColorUtils; import ghidra.util.table.column.AbstractGColumnRenderer; import ghidra.util.table.column.GColumnRenderer; @@ -36,8 +37,12 @@ import ghidra.util.table.column.GColumnRenderer; public class AnalysisEnablementTableModel extends GDynamicColumnTableModel { - private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT = new Color(255, 255, 200); - private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT_SELECTED = new Color(177, 212, 236); + private static Color FG_COLOR_PROTOTYPE = new GColor("color.fg.analysis.options.prototype"); + + private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT = + new GColor("color.bg.analysis.options.not.default.enablement"); + private static Color BG_COLOR_NOT_DEFAULT_ENABLEMENT_SELECTED = + new GColor("color.bg.analysis.options.not.default.enablement.selected"); private List analyzerStates; private AnalysisPanel panel; @@ -203,10 +208,10 @@ public class AnalysisEnablementTableModel } String analyzerName = (String) value; - if (analyzerName.endsWith(AnalysisPanel.PROTOTYPE)) { - component.setForeground( - ColorUtils.deriveForeground(component.getBackground(), ColorUtils.HUE_RED)); + if (!data.isSelected()) { + component.setForeground(FG_COLOR_PROTOTYPE); + } } AnalyzerEnablementState state = (AnalyzerEnablementState) data.getRowObject(); @@ -215,10 +220,10 @@ public class AnalysisEnablementTableModel return component; } - // not the default enablement + // not the default enablement + component.setForeground(Palette.BLACK); if (data.isSelected()) { component.setBackground(BG_COLOR_NOT_DEFAULT_ENABLEMENT_SELECTED); - component.setForeground(Color.BLACK); } else { component.setBackground(BG_COLOR_NOT_DEFAULT_ENABLEMENT); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java index 93cb4dbc1d..7af6077bb5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java @@ -25,6 +25,7 @@ import javax.swing.text.html.HTMLEditorKit; import docking.widgets.OptionDialog; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.services.ProgramManager; import ghidra.framework.model.DomainObject; @@ -270,7 +271,7 @@ class AnalyzeAllOpenProgramsTask extends Task { appendTableHeader(buffy); - String specialFontOpen = ""; + String specialFontOpen = ""; String specialFontClose = ""; for (Program program : validList) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/StoredAnalyzerTimesPropertyEditor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/StoredAnalyzerTimesPropertyEditor.java index 488fa252c7..44296a8617 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/StoredAnalyzerTimesPropertyEditor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/StoredAnalyzerTimesPropertyEditor.java @@ -21,6 +21,7 @@ import java.beans.PropertyEditorSupport; import javax.swing.*; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.framework.options.CustomOptionsEditor; import ghidra.util.layout.PairLayout; @@ -86,7 +87,7 @@ public class StoredAnalyzerTimesPropertyEditor extends PropertyEditorSupport } JPanel panel = new JPanel(new PairLayout(6, 10)); - + panel.add(new GDLabel("")); GDLabel label = new GDLabel("seconds", SwingConstants.RIGHT); panel.add(label); @@ -95,8 +96,8 @@ public class StoredAnalyzerTimesPropertyEditor extends PropertyEditorSupport label = new GDLabel(taskName, SwingConstants.RIGHT); label.setToolTipText(taskName); panel.add(label); - - Long timeMS = times.getTime(taskName); + + Long timeMS = times.getTime(taskName); if (timeMS == null) { continue; } @@ -115,12 +116,10 @@ public class StoredAnalyzerTimesPropertyEditor extends PropertyEditorSupport new JTextField(StoredAnalyzerTimes.formatTimeMS(times.getTotalTime())); valueField.setEditable(false); valueField.setHorizontalAlignment(SwingConstants.RIGHT); - valueField.setBorder(BorderFactory.createLineBorder(Color.black, 2)); + valueField.setBorder(BorderFactory.createLineBorder(Java.BORDER, 2)); panel.add(valueField); return panel; } - - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java index 266649b249..16468e6176 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchiveDialog.java @@ -94,7 +94,7 @@ public class ArchiveDialog extends DialogComponentProvider { } }); Font font = archiveBrowse.getFont(); - archiveBrowse.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); + archiveBrowse.setFont(font.deriveFont(Font.BOLD)); archiveBrowse.setName("archiveBrowse"); // Layout the components. @@ -269,8 +269,10 @@ public class ArchiveDialog extends DialogComponentProvider { return true; } - return file.getAbsolutePath().toLowerCase().endsWith( - ArchivePlugin.ARCHIVE_EXTENSION); + return file.getAbsolutePath() + .toLowerCase() + .endsWith( + ArchivePlugin.ARCHIVE_EXTENSION); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java index 8dbf68512f..30dc9cfebd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/RestoreDialog.java @@ -114,7 +114,7 @@ public class RestoreDialog extends DialogComponentProvider { } }); Font font = archiveBrowse.getFont(); - archiveBrowse.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); + archiveBrowse.setFont(font.deriveFont(Font.BOLD)); restoreLabel = new GDLabel(" Restore Directory "); restoreField = new JTextField(); @@ -131,7 +131,7 @@ public class RestoreDialog extends DialogComponentProvider { } }); font = restoreBrowse.getFont(); - restoreBrowse.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); + restoreBrowse.setFont(font.deriveFont(Font.BOLD)); projectNameLabel = new GDLabel(" Project Name "); projectNameField = new JTextField(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java index d1137a7634..2a0068ac4f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/AssemblyDualTextField.java @@ -27,6 +27,8 @@ import docking.EmptyBorderToggleButton; import docking.widgets.autocomplete.*; import docking.widgets.label.GDLabel; import docking.widgets.textfield.TextFieldLinker; +import generic.theme.*; +import generic.theme.GThemeDefaults.Colors; import ghidra.GhidraApplicationLayout; import ghidra.GhidraLaunchable; import ghidra.app.plugin.assembler.Assembler; @@ -41,7 +43,6 @@ import ghidra.program.model.address.Address; import ghidra.program.model.lang.LanguageID; import ghidra.program.model.listing.Instruction; import ghidra.util.NumericUtilities; -import resources.ResourceManager; /** * A pair of text fields suitable for guided assembly @@ -60,6 +61,14 @@ import resources.ResourceManager; * Otherwise, the usual autocompletion behavior is applied automatically. */ public class AssemblyDualTextField { + private static final String FONT_ID = "font.plugin.assembly.dual.text.field"; + private static Color FG_PREFERENCE_MOST = + new GColor("color.fg.plugin.assembler.completion.most"); + private static Color FG_PREFERENCE_MIDDLE = + new GColor("color.fg.plugin.assembler.completion.middle"); + private static Color FG_PREFERENCE_LEAST = + new GColor("color.fg.plugin.assembler.completion.least"); + protected final TextFieldLinker linker = new TextFieldLinker(); protected final JTextField mnemonic = new JTextField(); protected final JTextField operands = new JTextField(); @@ -179,8 +188,8 @@ public class AssemblyDualTextField { public AssemblyInstruction(String text, byte[] data, int preference) { // TODO?: Description to display constructor tree information super("", NumericUtilities.convertBytesToString(data, " "), - preference == 10000 ? Color.BLUE - : preference == 5000 ? new Color(0, 0, 128) : new Color(0, 128, 0), + preference == 10000 ? FG_PREFERENCE_MOST + : preference == 5000 ? FG_PREFERENCE_MIDDLE : FG_PREFERENCE_LEAST, -preference); this.data = data; } @@ -220,7 +229,7 @@ public class AssemblyDualTextField { private String text; public AssemblyError(String text, String desc) { - super(text, desc, Color.RED, 1); + super(text, desc, Colors.ERROR, 1); this.text = text; } @@ -326,7 +335,7 @@ public class AssemblyDualTextField { @Override protected void addContent(JPanel content) { Box controls = Box.createHorizontalBox(); - Icon icon = ResourceManager.loadImage("images/question_zero.png"); + Icon icon = new GIcon("icon.plugin.assembler.question"); EmptyBorderToggleButton button = new EmptyBorderToggleButton(icon); button.setToolTipText("Exhaust unspecified bits, otherwise zero them"); button.addActionListener((e) -> { @@ -442,7 +451,7 @@ public class AssemblyDualTextField { * Set the "existing" instruction used for ordering proposed instructions by "most similar" * * @see #computePreference(AssemblyResolvedPatterns) - * @param existing + * @param existing the existing instruction */ public void setExisting(Instruction existing) { this.existing = existing; @@ -468,6 +477,7 @@ public class AssemblyDualTextField { /** * For single mode: Get the text field containing the full assembly text + * @return the text field */ public JTextField getAssemblyField() { return assembly; @@ -550,18 +560,13 @@ public class AssemblyDualTextField { if (assembly.isVisible()) { throw new AssertionError(); } - else { - return VisibilityMode.DUAL_VISIBLE; - } + return VisibilityMode.DUAL_VISIBLE; } - else { - if (assembly.isVisible()) { - return VisibilityMode.SINGLE_VISIBLE; - } - else { - return VisibilityMode.INVISIBLE; - } + + if (assembly.isVisible()) { + return VisibilityMode.SINGLE_VISIBLE; } + return VisibilityMode.INVISIBLE; } /** @@ -653,8 +658,7 @@ public class AssemblyDualTextField { * @param field the field to configure */ protected void configureField(JTextField field) { - Font mono = new Font(Font.MONOSPACED, Font.PLAIN, 12); // TODO: Font size from options - field.setFont(mono); + Gui.registerFont(field, FONT_ID); } /** @@ -695,7 +699,6 @@ public class AssemblyDualTextField { * one are preferred. Last, the shortest instructions are preferred. * * @param rc a resolved instruction - * @param existing the instruction, if any, currently under the user's cursor * @return a preference */ protected int computePreference(AssemblyResolvedPatterns rc) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java index 4951dbb01b..926057a9a5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchDataAction.java @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.assembler; -import java.awt.Color; import java.awt.Font; import java.awt.event.FocusListener; import java.awt.event.KeyListener; @@ -26,6 +25,7 @@ import docking.action.KeyBindingData; import docking.action.MenuData; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.framework.plugintool.Plugin; import ghidra.program.database.util.ProgramTransaction; import ghidra.program.model.address.*; @@ -56,7 +56,7 @@ public class PatchDataAction extends AbstractPatchAction { setKeyBindingData(new KeyBindingData(KEYBIND_PATCH_DATA)); setHelpLocation(new HelpLocation(owner.getName(), "patch_data")); - input.setBorder(BorderFactory.createLineBorder(Color.RED, 2)); + input.setBorder(BorderFactory.createLineBorder(Colors.ERROR, 2)); init(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchInstructionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchInstructionAction.java index 84b1fbb6d9..48184fbc21 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchInstructionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/assembler/PatchInstructionAction.java @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.assembler; -import java.awt.Color; import java.awt.Font; import java.awt.event.FocusListener; import java.awt.event.KeyListener; @@ -33,6 +32,7 @@ import docking.action.MenuData; import docking.widgets.autocomplete.*; import docking.widgets.fieldpanel.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.assembler.Assembler; import ghidra.app.plugin.assembler.Assemblers; import ghidra.app.plugin.core.assembler.AssemblyDualTextField.*; @@ -146,9 +146,9 @@ public class PatchInstructionAction extends AbstractPatchAction { setKeyBindingData(new KeyBindingData(KEYBIND_PATCH_INSTRUCTION)); setHelpLocation(new HelpLocation(owner.getName(), "patch_instruction")); - input.getMnemonicField().setBorder(BorderFactory.createLineBorder(Color.RED, 2)); - input.getOperandsField().setBorder(BorderFactory.createLineBorder(Color.RED, 2)); - input.getAssemblyField().setBorder(BorderFactory.createLineBorder(Color.RED, 2)); + input.getMnemonicField().setBorder(BorderFactory.createLineBorder(Colors.ERROR, 2)); + input.getOperandsField().setBorder(BorderFactory.createLineBorder(Colors.ERROR, 2)); + input.getAssemblyField().setBorder(BorderFactory.createLineBorder(Colors.ERROR, 2)); input.getAutocompleter().addAutocompletionListener(listenerForAccept); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkNavigator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkNavigator.java index 469c83fc2e..bf29ce1268 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkNavigator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkNavigator.java @@ -17,10 +17,12 @@ package ghidra.app.plugin.core.bookmark; import java.awt.Color; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.apache.commons.lang3.StringUtils; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.app.services.*; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; @@ -28,7 +30,6 @@ import ghidra.program.model.listing.*; import ghidra.program.util.MarkerLocation; import ghidra.util.HTMLUtilities; import ghidra.util.Swing; -import resources.ResourceManager; /** * Handles navigation/display of bookmarks in the browser marker margins. @@ -37,13 +38,12 @@ public class BookmarkNavigator { private static final int BIG_CHANGE = 1000; - final static ImageIcon NOTE_ICON = ResourceManager.loadImage("images/notes.gif"); - final static ImageIcon INFO_ICON = ResourceManager.loadImage("images/information.png"); - final static ImageIcon WARNING_ICON = ResourceManager.loadImage("images/warning.png"); - final static ImageIcon ERROR_ICON = ResourceManager.loadImage("images/edit-delete.png"); - final static ImageIcon ANALYSIS_ICON = - ResourceManager.loadImage("images/applications-system.png"); - final static ImageIcon DEFAULT_ICON = ResourceManager.loadImage("images/unknown.gif"); + final static Icon NOTE_ICON = new GIcon("icon.plugin.bookmark.type.note"); + final static Icon INFO_ICON = new GIcon("icon.plugin.bookmark.type.info"); + final static Icon WARNING_ICON = new GIcon("icon.plugin.bookmark.type.warning"); + final static Icon ERROR_ICON = new GIcon("icon.plugin.bookmark.type.error"); + final static Icon ANALYSIS_ICON = new GIcon("icon.plugin.bookmark.type.analysis"); + final static Icon DEFAULT_ICON = new GIcon("icon.plugin.bookmark.type.default"); final static int NOTE_PRIORITY = MarkerService.BOOKMARK_PRIORITY; final static int ERROR_PRIORITY = MarkerService.BOOKMARK_PRIORITY + BIG_CHANGE; @@ -52,12 +52,12 @@ public class BookmarkNavigator { final static int ANALYSIS_PRIORITY = MarkerService.BOOKMARK_PRIORITY + 6; final static int DEFAULT_PRIORITY = MarkerService.BOOKMARK_PRIORITY + 8; - final static Color NOTE_COLOR = new Color(128, 0, 255); // Purple - final static Color INFO_COLOR = new Color(0, 255, 255); // Cyan - final static Color WARNING_COLOR = new Color(255, 196, 51); // Dark Yellow - final static Color ERROR_COLOR = new Color(204, 0, 51); // Dark Red - final static Color ANALYSIS_COLOR = new Color(255, 128, 0); // Orange - final static Color DEFAULT_COLOR = new Color(255, 0, 255); // Magenta + final static Color NOTE_COLOR = new GColor("color.bg.plugin.bookmark.note"); + final static Color INFO_COLOR = new GColor("color.bg.plugin.bookmark.info"); + final static Color WARNING_COLOR = new GColor("color.bg.plugin.bookmark.warning"); + final static Color ERROR_COLOR = new GColor("color.bg.plugin.bookmark.error"); + final static Color ANALYSIS_COLOR = new GColor("color.bg.plugin.bookmark.analysis"); + final static Color DEFAULT_COLOR = new GColor("color.bg.plugin.bookmark.default"); private String type; private MarkerService markerService; @@ -80,7 +80,7 @@ public class BookmarkNavigator { priority = DEFAULT_PRIORITY; } - ImageIcon icon = bmt.getIcon(); + Icon icon = bmt.getIcon(); if (icon == null) { icon = DEFAULT_ICON; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java index 7759366a64..0fa54915d9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java @@ -26,6 +26,7 @@ import docking.Tool; import docking.action.*; import docking.actions.PopupActionProvider; import docking.widgets.table.GTable; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.PluginCategoryNames; @@ -43,7 +44,8 @@ import ghidra.program.util.*; import ghidra.util.Msg; import ghidra.util.table.SelectionNavigationAction; import ghidra.util.task.SwingUpdateManager; -import resources.*; +import resources.Icons; +import resources.MultiIconBuilder; /** * Plugin to for adding/deleting/editing bookmarks. @@ -115,7 +117,7 @@ public class BookmarkPlugin extends ProgramPlugin tool.addAction(addAction); MultiIconBuilder builder = new MultiIconBuilder(Icons.CONFIGURE_FILTER_ICON); - builder.addLowerRightIcon(ResourceManager.loadImage("images/check.png")); + builder.addLowerRightIcon(new GIcon("icon.plugin.bookmark.add")); Icon filterTypesChanged = builder.build(); Icon filterTypesUnchanged = Icons.CONFIGURE_FILTER_ICON; DockingAction filterAction = new DockingAction("Filter Bookmarks", getName()) { @@ -150,7 +152,7 @@ public class BookmarkPlugin extends ProgramPlugin provider.delete(); } }; - Icon icon = ResourceManager.loadImage("images/edit-delete.png"); + Icon icon = new GIcon("icon.plugin.bookmark.delete"); deleteAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0)); deleteAction.setPopupMenuData(new MenuData(new String[] { "Delete" }, icon)); deleteAction.setDescription("Delete Selected Bookmarks"); @@ -164,7 +166,7 @@ public class BookmarkPlugin extends ProgramPlugin select(provider.getBookmarkLocations()); } }; - icon = ResourceManager.loadImage("images/text_align_justify.png"); + icon = new GIcon("icon.plugin.bookmark.select"); selectionAction.setPopupMenuData( new MenuData(new String[] { "Select Bookmark Locations" }, icon)); selectionAction.setToolBarData(new ToolBarData(icon)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/CreateBookmarkDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/CreateBookmarkDialog.java index ec815e7a67..986bd75627 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/CreateBookmarkDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/CreateBookmarkDialog.java @@ -49,10 +49,6 @@ public class CreateBookmarkDialog extends DialogComponentProvider { private JTextField commentTextField; private JCheckBox selectionCB; - /** - * Creates new CreateBookmarkDialog - * - */ CreateBookmarkDialog(BookmarkPlugin plugin, CodeUnit cu, boolean hasSelection) { super(BookmarkType.NOTE + " Bookmark", true, true, true, false); @@ -71,6 +67,7 @@ public class CreateBookmarkDialog extends DialogComponentProvider { setHelpLocation(new HelpLocation("BookmarkPlugin", "CreateBookmarkDialog")); } + @Override public void dispose() { this.plugin = null; this.program = null; @@ -202,7 +199,7 @@ public class CreateBookmarkDialog extends DialogComponentProvider { gbc.anchor = GridBagConstraints.WEST; mainPanel.add(commentTextField, gbc); - ImageIcon icon = BookmarkNavigator.NOTE_ICON; + Icon icon = BookmarkNavigator.NOTE_ICON; JLabel imageLabel = new GIconLabel(icon); imageLabel.setPreferredSize( new Dimension(icon.getIconWidth() + 20, icon.getIconHeight() + 20)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java index 61a457b56b..797ffd5954 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java @@ -23,6 +23,7 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.context.ListingActionContext; import ghidra.app.plugin.PluginCategoryNames; @@ -37,7 +38,6 @@ import ghidra.program.model.symbol.ReferenceManager; import ghidra.program.util.ProgramLocation; import ghidra.util.HelpLocation; import resources.Icons; -import resources.ResourceManager; /** * Assuming a function foo, this plugin will show all callers of foo and all @@ -58,9 +58,8 @@ import resources.ResourceManager; public class CallTreePlugin extends ProgramPlugin { static final Icon PROVIDER_ICON = Icons.ARROW_DOWN_RIGHT_ICON; - static final Icon FUNCTION_ICON = ResourceManager.loadImage("images/FunctionScope.gif"); - static final Icon RECURSIVE_ICON = - ResourceManager.loadImage("images/arrow_rotate_clockwise.png"); + static final Icon FUNCTION_ICON = new GIcon("icon.plugin.calltree.function"); + static final Icon RECURSIVE_ICON = new GIcon("icon.plugin.calltree.recursive"); private List providers = new ArrayList<>(); private DockingAction showCallTreeFromMenuAction; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java index d39226f30d..52ee26081e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java @@ -33,6 +33,7 @@ import docking.widgets.tree.*; import docking.widgets.tree.support.GTreeSelectionEvent.EventOrigin; import docking.widgets.tree.support.GTreeSelectionListener; import docking.widgets.tree.tasks.GTreeExpandAllTask; +import generic.theme.GIcon; import ghidra.app.events.ProgramLocationPluginEvent; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.services.GoToService; @@ -51,18 +52,18 @@ import ghidra.util.exception.CancelledException; import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.TaskMonitor; import resources.Icons; -import resources.ResourceManager; public class CallTreeProvider extends ComponentProviderAdapter implements DomainObjectListener { static final String EXPAND_ACTION_NAME = "Fully Expand Selected Nodes"; static final String TITLE = "Function Call Trees"; - private static final Icon EMPTY_ICON = ResourceManager.loadImage("images/EmptyIcon16.gif"); + private static final Icon EMPTY_ICON = Icons.EMPTY_ICON; private static final Icon EXPAND_ICON = Icons.EXPAND_ALL_ICON; private static final Icon COLLAPSE_ICON = Icons.COLLAPSE_ALL_ICON; - private static ImageIcon REFRESH_ICON = Icons.REFRESH_ICON; - private static Icon REFRESH_NOT_NEEDED_ICON = ResourceManager.getDisabledIcon(REFRESH_ICON, 60); + private static Icon REFRESH_ICON = new GIcon("icon.plugin.calltree.refresh"); + private static Icon REFRESH_NOT_NEEDED_ICON = + new GIcon("icon.plugin.calltree.refresh.not.needed"); private static final String RECURSE_DEPTH_PROPERTY_NAME = "call.tree.recurse.depth"; private static final String DEFAULT_RECURSE_DEPTH = "5"; @@ -350,8 +351,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain return true; } }; - goToSourceAction.setPopupMenuData( - new MenuData(new String[] { "Go To Call Source" }, goToMenu)); + goToSourceAction + .setPopupMenuData(new MenuData(new String[] { "Go To Call Source" }, goToMenu)); goToSourceAction.setHelpLocation( new HelpLocation(plugin.getName(), "Call_Tree_Context_Action_Goto_Source")); tool.addLocalAction(this, goToSourceAction); @@ -365,12 +366,12 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain doUpdate(); } }; - filterDuplicates.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/application_double.png"), - filterOptionsToolbarGroup, "1")); + filterDuplicates + .setToolBarData(new ToolBarData(new GIcon("icon.plugin.calltree.filter.duplicates"), + filterOptionsToolbarGroup, "1")); filterDuplicates.setSelected(true); - filterDuplicates.setHelpLocation( - new HelpLocation(plugin.getName(), "Call_Tree_Action_Filter")); + filterDuplicates + .setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Filter")); tool.addLocalAction(this, filterDuplicates); // @@ -393,8 +394,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain "Recurse Depth

Limits the depth to " + "which recursing tree operations" + "
will go. Example operations include Expand All and filtering"); recurseIcon = new NumberIcon(recurseDepth.get()); - recurseDepthAction.setToolBarData( - new ToolBarData(recurseIcon, filterOptionsToolbarGroup, "2")); + recurseDepthAction + .setToolBarData(new ToolBarData(recurseIcon, filterOptionsToolbarGroup, "2")); recurseDepthAction.setHelpLocation( new HelpLocation(plugin.getName(), "Call_Tree_Action_Recurse_Depth")); @@ -414,8 +415,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain "Listing to
the source location of the call"); navigationOutgoingAction.setToolBarData(new ToolBarData( Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON, navigationOptionsToolbarGroup, "1")); - navigationOutgoingAction.setHelpLocation( - new HelpLocation(plugin.getName(), "Call_Tree_Action_Navigation")); + navigationOutgoingAction + .setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Navigation")); tool.addLocalAction(this, navigationOutgoingAction); // @@ -503,7 +504,7 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain return true; } }; - ImageIcon icon = ResourceManager.loadImage("images/text_align_justify.png"); + Icon icon = new GIcon("icon.plugin.calltree.filter.select.source"); selectSourceAction.setPopupMenuData( new MenuData(new String[] { "Select Call Source" }, icon, selectionMenuGroup)); selectSourceAction.setHelpLocation( @@ -581,8 +582,7 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain return currentFunction != null; } }; - homeAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/go-home.png"), homeToolbarGroup)); + homeAction.setToolBarData(new ToolBarData(Icons.HOME_ICON, homeToolbarGroup)); homeAction.setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Home")); tool.addLocalAction(this, homeAction); @@ -596,8 +596,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain refreshAction.setEnabled(true); refreshAction.setDescription("Push at any time to refresh the current trees.
" + "This is highlighted when the data may be stale.
"); - refreshAction.setHelpLocation( - new HelpLocation(plugin.getName(), "Call_Tree_Action_Refresh")); + refreshAction + .setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Action_Refresh")); tool.addLocalAction(this, refreshAction); // @@ -671,8 +671,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain "Call_Tree_Context_Action_Show_Call_Tree_For_Function")); newCallTree.setPopupMenuData(new MenuData(new String[] { "Show Call Tree For Function" }, CallTreePlugin.PROVIDER_ICON, newTreeMenu)); - newCallTree.setDescription("Show the Function Call Tree window for the function " + - "selected in the call tree"); + newCallTree.setDescription( + "Show the Function Call Tree window for the function " + "selected in the call tree"); tool.addLocalAction(this, newCallTree); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/DeadEndNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/DeadEndNode.java index 96e19bb588..bce14bc4f6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/DeadEndNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/DeadEndNode.java @@ -15,6 +15,14 @@ */ package ghidra.app.plugin.core.calltree; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.swing.Icon; + +import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; @@ -23,18 +31,9 @@ import ghidra.program.util.ProgramLocation; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.widgets.tree.GTreeNode; - public class DeadEndNode extends CallNode { - private static final Icon ICON = ResourceManager.loadImage("images/stopNode.png"); + private static final Icon ICON = new GIcon("icon.plugin.calltree.node.dead.end"); private final Reference reference; private String name; @@ -100,6 +99,6 @@ public class DeadEndNode extends CallNode { @Override public List generateChildren(TaskMonitor monitor) throws CancelledException { - return new ArrayList(); + return new ArrayList<>(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/ExternalCallNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/ExternalCallNode.java index 8e9fbc8655..d4269e8791 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/ExternalCallNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/ExternalCallNode.java @@ -22,6 +22,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.util.FunctionSignatureFieldLocation; @@ -29,12 +30,11 @@ import ghidra.program.util.ProgramLocation; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.TranslateIcon; public class ExternalCallNode extends CallNode { - private static final Icon EXTERNAL_ICON = ResourceManager.loadImage("images/package.png"); + private static final Icon EXTERNAL_ICON = new GIcon("icon.plugin.calltree.node.external"); private final Icon EXTERNAL_FUNCTION_ICON; private final Icon baseIcon; @@ -77,7 +77,7 @@ public class ExternalCallNode extends CallNode { @Override public List generateChildren(TaskMonitor monitor) throws CancelledException { - return new ArrayList(); + return new ArrayList<>(); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java index fb6304edab..6b06ef4886 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java @@ -16,7 +16,6 @@ package ghidra.app.plugin.core.checksums; import java.awt.BorderLayout; -import java.awt.Color; import java.util.ArrayList; import java.util.List; @@ -25,14 +24,14 @@ import javax.swing.*; import docking.ActionContext; import docking.action.*; import docking.widgets.label.GDLabel; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.context.ProgramContextAction; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.util.HelpLocation; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.table.GhidraTable; import ghidra.util.task.TaskLauncher; -import resources.Icons; -import resources.ResourceManager; /** * Provider to invoke computation of various checksums and display them in a table. @@ -97,7 +96,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { errorStatus = new GDLabel(" "); errorStatus.setName("message"); errorStatus.setHorizontalAlignment(SwingConstants.CENTER); - errorStatus.setForeground(Color.RED); + errorStatus.setForeground(Colors.ERROR); errorStatus.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); main.add(errorStatus, BorderLayout.SOUTH); @@ -233,7 +232,8 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { }; computeAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "compute")); computeAction.setEnabled(true); - computeAction.setToolBarData(new ToolBarData(Icons.REFRESH_ICON, null)); + computeAction + .setToolBarData(new ToolBarData(new GIcon("icon.plugin.checksum.compute"), null)); computeAction.setDescription("Refreshes checksums"); selectionAction = new ToggleDockingAction("On Selection", plugin.getName()) { @@ -251,7 +251,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { selectionAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "On_Selection")); selectionAction.setEnabled(plugin.hasSelection()); selectionAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/NextSelectionBlock16.gif"), null)); + new ToolBarData(new GIcon("icon.plugin.checksum.select"), null)); selectionAction.setDescription("When toggled, generates checksums on " + "selection. Otherwise checksums are generated over the entire program"); @@ -269,7 +269,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { showHexAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "As_Hex")); showHexAction.setEnabled(true); showHexAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/hexData.png"), null)); + new ToolBarData(new GIcon("icon.plugin.checksum.show.hex"), null)); showHexAction.setDescription("Toggle to show the hex values instead of decimal values."); xorAction = new ToggleDockingAction("XOR Checksum Values", plugin.getName()) { @@ -289,7 +289,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { xorAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "xor")); xorAction.setEnabled(true); xorAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/xor.png"), null)); + new ToolBarData(new GIcon("icon.plugin.checksum.xor"), null)); xorAction.setDescription("Toggle to recompute values with a xor operation."); carryAction = new ToggleDockingAction("Carry Checksum Values", plugin.getName()) { @@ -310,7 +310,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { carryAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "carry")); carryAction.setEnabled(true); carryAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/carry.png"), null)); + new ToolBarData(new GIcon("icon.plugin.checksum.carry"), null)); carryAction.setDescription("Toggle to recompute values with a carry operation."); onesCompAction = new ToggleDockingAction("Ones Complement", plugin.getName()) { @@ -330,7 +330,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { onesCompAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "ones_comp")); onesCompAction.setEnabled(true); onesCompAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/onesComplement.png"), null)); + new ToolBarData(new GIcon("icon.plugin.checksum.ones.complement"), null)); onesCompAction.setDescription("Toggle to recompute values with a one's complement."); twosCompAction = new ToggleDockingAction("Twos Complement", plugin.getName()) { @@ -350,7 +350,7 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter { twosCompAction.setHelpLocation(new HelpLocation("ComputeChecksumsPlugin", "twos_comp")); twosCompAction.setEnabled(true); twosCompAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/twosComplement.png"), null)); + new ToolBarData(new GIcon("icon.plugin.checksum.twos.complement"), null)); twosCompAction.setDescription("Toggle to recompute values with a two's complement."); tool.addLocalAction(this, onesCompAction); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/ClipboardPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/ClipboardPlugin.java index 31f5717463..8f37c8a0b0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/ClipboardPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/ClipboardPlugin.java @@ -29,6 +29,7 @@ import javax.swing.event.ChangeListener; import docking.*; import docking.action.*; import docking.dnd.GClipboard; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.context.ListingActionContext; import ghidra.app.plugin.PluginCategoryNames; @@ -43,7 +44,6 @@ import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.task.*; -import resources.ResourceManager; //@formatter:off @PluginInfo( @@ -361,7 +361,7 @@ public class ClipboardPlugin extends ProgramPlugin implements ClipboardOwner, Cl this.clipboardService = clipboardService; setPopupMenuData(new MenuData(new String[] { "Copy" }, "Clipboard")); - setToolBarData(new ToolBarData(ResourceManager.loadImage("images/page_white_copy.png"), + setToolBarData(new ToolBarData(new GIcon("icon.plugin.clipboard.copy"), "Clipboard")); setKeyBindingData(new KeyBindingData(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK)); setHelpLocation(new HelpLocation("ClipboardPlugin", "Copy")); @@ -395,7 +395,7 @@ public class ClipboardPlugin extends ProgramPlugin implements ClipboardOwner, Cl setPopupMenuData(new MenuData(new String[] { "Paste" }, "Clipboard")); setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/page_paste.png"), "Clipboard")); + new ToolBarData(new GIcon("icon.plugin.clipboard.paste"), "Clipboard")); setKeyBindingData(new KeyBindingData(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK)); setHelpLocation(new HelpLocation("ClipboardPlugin", "Paste")); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java index a2e47229dd..0f0ddb2889 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java @@ -20,7 +20,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -30,6 +30,8 @@ import docking.widgets.fieldpanel.*; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldSelection; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.events.ProgramHighlightPluginEvent; import ghidra.app.events.ProgramSelectionPluginEvent; @@ -55,21 +57,27 @@ import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.*; -import resources.ResourceManager; public abstract class AbstractCodeBrowserPlugin

extends Plugin implements CodeViewerService, CodeFormatService, OptionsChangeListener, FormatModelListener, DomainObjectListener, CodeBrowserPluginInterface { - private static final Color CURSOR_LINE_COLOR = GhidraOptions.DEFAULT_CURSOR_LINE_COLOR; - private static final String CURSOR_COLOR = "Cursor.Cursor Color - Focused"; - private static final String UNFOCUSED_CURSOR_COLOR = "Cursor.Cursor Color - Unfocused"; - private static final String BLINK_CURSOR = "Cursor.Blink Cursor"; - private static final String MOUSE_WHEEL_HORIZONTAL_SCROLLING = "Mouse.Horizontal Scrolling"; + private static final String CURSOR_COLOR_OPTIONS_NAME = "Cursor.Cursor Color - Focused"; + private static final String UNFOCUSED_CURSOR_COLOR_OPTIONS_NAME = + "Cursor.Cursor Color - Unfocused"; + private static final String BLINK_CURSOR_OPTIONS_NAME = "Cursor.Blink Cursor"; + private static final String MOUSE_WHEEL_HORIZONTAL_SCROLLING_OPTIONS_NAME = + "Mouse.Horizontal Scrolling"; + + //@formatter:off + private static final GColor FOCUSED_CURSOR_COLOR = new GColor("color.cursor.focused.listing"); + private static final GColor UNFOCUSED_CURSOR_COLOR = new GColor("color.cursor.unfocused.listing"); + private static final GColor CURRENT_LINE_HIGHLIGHT_COLOR = new GColor("color.bg.currentline.listing"); + //@formatter:on // - Icon - - private ImageIcon CURSOR_LOC_ICON = - ResourceManager.loadImage("images/cursor_arrow_flipped.gif"); + private static final Icon CURSOR_LOC_ICON = + new GIcon("icon.plugin.codebrowser.cursor.location"); protected final P connectedProvider; protected List

disconnectedProviders = new ArrayList<>(); protected FormatManager formatMgr; @@ -406,15 +414,15 @@ public abstract class AbstractCodeBrowserPlugin

ex highlightMarkers.setMarkerColor(color); } } - else if (optionName.equals(CURSOR_COLOR)) { + else if (optionName.equals(CURSOR_COLOR_OPTIONS_NAME)) { Color color = ((Color) newValue); fieldPanel.setFocusedCursorColor(color); } - else if (optionName.equals(UNFOCUSED_CURSOR_COLOR)) { + else if (optionName.equals(UNFOCUSED_CURSOR_COLOR_OPTIONS_NAME)) { Color color = ((Color) newValue); fieldPanel.setNonFocusCursorColor(color); } - else if (optionName.equals(BLINK_CURSOR)) { + else if (optionName.equals(BLINK_CURSOR_OPTIONS_NAME)) { Boolean isBlinkCursor = ((Boolean) newValue); fieldPanel.setBlinkCursor(isBlinkCursor); } @@ -430,7 +438,7 @@ public abstract class AbstractCodeBrowserPlugin

ex currentCursorMarkers.setColoringBackground(isHighlightCursorLine); } } - else if (optionName.equals(MOUSE_WHEEL_HORIZONTAL_SCROLLING)) { + else if (optionName.equals(MOUSE_WHEEL_HORIZONTAL_SCROLLING_OPTIONS_NAME)) { fieldPanel.setHorizontalScrollingEnabled((Boolean) newValue); } @@ -547,26 +555,32 @@ public abstract class AbstractCodeBrowserPlugin

ex HelpLocation helpLocation = new HelpLocation(getName(), "Selection Colors"); fieldOptions.getOptions("Selection Colors").setOptionsHelpLocation(helpLocation); - fieldOptions.registerOption(GhidraOptions.OPTION_SELECTION_COLOR, - GhidraOptions.DEFAULT_SELECTION_COLOR, helpLocation, + fieldOptions.registerThemeColorBinding(GhidraOptions.OPTION_SELECTION_COLOR, + GhidraOptions.DEFAULT_SELECTION_COLOR.getId(), helpLocation, "The selection color in the browser."); - fieldOptions.registerOption(GhidraOptions.OPTION_HIGHLIGHT_COLOR, - GhidraOptions.DEFAULT_HIGHLIGHT_COLOR, helpLocation, + fieldOptions.registerThemeColorBinding(GhidraOptions.OPTION_HIGHLIGHT_COLOR, + GhidraOptions.DEFAULT_HIGHLIGHT_COLOR.getId(), helpLocation, "The highlight color in the browser."); - fieldOptions.registerOption(CURSOR_COLOR, Color.RED, helpLocation, + fieldOptions.registerThemeColorBinding(CURSOR_COLOR_OPTIONS_NAME, + FOCUSED_CURSOR_COLOR.getId(), + helpLocation, "The color of the cursor in the browser."); - fieldOptions.registerOption(UNFOCUSED_CURSOR_COLOR, Color.PINK, helpLocation, + fieldOptions.registerThemeColorBinding(UNFOCUSED_CURSOR_COLOR_OPTIONS_NAME, + UNFOCUSED_CURSOR_COLOR.getId(), + helpLocation, "The color of the cursor in the browser when the browser does not have focus."); - fieldOptions.registerOption(BLINK_CURSOR, true, helpLocation, + fieldOptions.registerOption(BLINK_CURSOR_OPTIONS_NAME, true, helpLocation, "When selected, the cursor will blink when the containing window is focused."); - fieldOptions.registerOption(GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR, CURSOR_LINE_COLOR, - helpLocation, "The background color of the line where the cursor is located"); + fieldOptions.registerThemeColorBinding(GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR, + CURRENT_LINE_HIGHLIGHT_COLOR.getId(), helpLocation, + "The background color of the line where the cursor is located"); fieldOptions.registerOption(GhidraOptions.HIGHLIGHT_CURSOR_LINE, true, helpLocation, "Toggles highlighting background color of line containing the cursor"); helpLocation = new HelpLocation(getName(), "Keyboard_Controls_Shift"); - fieldOptions.registerOption(MOUSE_WHEEL_HORIZONTAL_SCROLLING, true, helpLocation, + fieldOptions.registerOption(MOUSE_WHEEL_HORIZONTAL_SCROLLING_OPTIONS_NAME, true, + helpLocation, "Enables horizontal scrolling by holding the Shift key while " + "using the mouse scroll wheel"); @@ -581,28 +595,29 @@ public abstract class AbstractCodeBrowserPlugin

ex } color = - fieldOptions.getColor(GhidraOptions.OPTION_HIGHLIGHT_COLOR, new Color(255, 255, 180)); + fieldOptions.getColor(GhidraOptions.OPTION_HIGHLIGHT_COLOR, + GhidraOptions.DEFAULT_HIGHLIGHT_COLOR); MarkerSet highlightMarkers = getHighlightMarkers(currentProgram); fieldPanel.setHighlightColor(color); if (highlightMarkers != null) { highlightMarkers.setMarkerColor(color); } - color = fieldOptions.getColor(CURSOR_COLOR, Color.RED); + color = fieldOptions.getColor(CURSOR_COLOR_OPTIONS_NAME, FOCUSED_CURSOR_COLOR); fieldPanel.setFocusedCursorColor(color); - color = fieldOptions.getColor(UNFOCUSED_CURSOR_COLOR, Color.PINK); + color = fieldOptions.getColor(UNFOCUSED_CURSOR_COLOR_OPTIONS_NAME, UNFOCUSED_CURSOR_COLOR); fieldPanel.setNonFocusCursorColor(color); - Boolean isBlinkCursor = fieldOptions.getBoolean(BLINK_CURSOR, true); + Boolean isBlinkCursor = fieldOptions.getBoolean(BLINK_CURSOR_OPTIONS_NAME, true); fieldPanel.setBlinkCursor(isBlinkCursor); boolean horizontalScrollingEnabled = - fieldOptions.getBoolean(MOUSE_WHEEL_HORIZONTAL_SCROLLING, true); + fieldOptions.getBoolean(MOUSE_WHEEL_HORIZONTAL_SCROLLING_OPTIONS_NAME, true); fieldPanel.setHorizontalScrollingEnabled(horizontalScrollingEnabled); - cursorHighlightColor = - fieldOptions.getColor(GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR, CURSOR_LINE_COLOR); + cursorHighlightColor = fieldOptions.getColor(GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR, + CURRENT_LINE_HIGHLIGHT_COLOR); isHighlightCursorLine = fieldOptions.getBoolean(GhidraOptions.HIGHLIGHT_CURSOR_LINE, true); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java index 50860c6f18..ed427d83e5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java @@ -15,10 +15,11 @@ */ package ghidra.app.plugin.core.codebrowser; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.builder.ActionBuilder; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; @@ -38,7 +39,6 @@ import ghidra.util.datastruct.Accumulator; import ghidra.util.exception.CancelledException; import ghidra.util.table.*; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Plugin for adding some basic selection actions for Code Browser Listings. @@ -129,7 +129,7 @@ public class CodeBrowserSelectionPlugin extends Plugin { GhidraProgramTableModel

model = createTableModel(program, codeUnits, selection); String title = "Selection Table"; - ImageIcon markerIcon = ResourceManager.loadImage("images/searchm_obj.gif"); + Icon markerIcon = new GIcon("icon.plugin.codebrowser.cursor.marker"); TableComponentProvider
tableProvider = tableService.showTableWithMarkers(title + " " + model.getName(), "Selection", model, PluginConstants.SEARCH_HIGHLIGHT_COLOR, markerIcon, title, null); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java index e506d03b6d..ec4036e92e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java @@ -37,6 +37,7 @@ import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.HoverHandler; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.fieldpanel.support.*; +import generic.theme.GIcon; import ghidra.app.nav.*; import ghidra.app.plugin.core.clipboard.CodeBrowserClipboardProvider; import ghidra.app.plugin.core.codebrowser.actions.*; @@ -47,6 +48,7 @@ import ghidra.app.util.viewer.field.FieldFactory; import ghidra.app.util.viewer.format.*; import ghidra.app.util.viewer.listingpanel.*; import ghidra.app.util.viewer.multilisting.MultiListingLayoutModel; +import ghidra.app.util.viewer.options.ListingDisplayOptionsEditor; import ghidra.app.util.viewer.util.FieldNavigator; import ghidra.framework.options.SaveState; import ghidra.framework.plugintool.NavigatableComponentProviderAdapter; @@ -56,7 +58,6 @@ import ghidra.program.model.listing.*; import ghidra.program.util.*; import ghidra.util.HelpLocation; import ghidra.util.Swing; -import resources.ResourceManager; public class CodeViewerProvider extends NavigatableComponentProviderAdapter implements ProgramLocationListener, ProgramSelectionListener, Draggable, Droppable, @@ -67,12 +68,12 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter private static final String TITLE = NAME + ": "; private static final Icon LISTING_FORMAT_EXPAND_ICON = - ResourceManager.loadImage("images/field.header.down.png"); + new GIcon("icon.plugin.codebrowser.format.expand"); private static final Icon LISTING_FORMAT_COLLAPSE_ICON = - ResourceManager.loadImage("images/field.header.up.png"); + new GIcon("icon.plugin.codebrowser.format.collapse"); - private static final Icon HOVER_ON_ICON = ResourceManager.loadImage("images/hoverOn.gif"); - private static final Icon HOVER_OFF_ICON = ResourceManager.loadImage("images/hoverOff.gif"); + private static final Icon HOVER_ON_ICON = new GIcon("icon.plugin.codebrowser.hover.on"); + private static final Icon HOVER_OFF_ICON = new GIcon("icon.plugin.codebrowser.hover.off"); private static final String HOVER_MODE = "Hover Mode"; private static final String DIVIDER_LOCATION = "DividerLocation"; @@ -128,9 +129,9 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter // note: the owner has not changed, just the name; remove sometime after version 10 String owner = plugin.getName(); ComponentProvider.registerProviderNameOwnerChange(OLD_NAME, owner, NAME, owner); - + registerAdjustableFontId(ListingDisplayOptionsEditor.DEFAULT_FONT_ID); setConnected(isConnected); - setIcon(ResourceManager.loadImage("images/Browser.gif")); + setIcon(new GIcon("icon.plugin.codebrowser.provider")); if (!isConnected) { setTransient(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/LayeredColorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/LayeredColorModel.java index 4f786ec39b..c9735ee369 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/LayeredColorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/LayeredColorModel.java @@ -20,6 +20,7 @@ import java.math.BigInteger; import ghidra.app.util.viewer.listingpanel.ListingBackgroundColorModel; import ghidra.app.util.viewer.listingpanel.ListingPanel; +import ghidra.util.ColorUtils; /** * Class for blending two {@link ListingBackgroundColorModel}s. If neither model has a color @@ -52,10 +53,7 @@ public class LayeredColorModel implements ListingBackgroundColorModel { } private Color blend(Color primary, Color secondary) { - int red = (primary.getRed() * 2 + secondary.getRed()) / 3; - int green = (primary.getGreen() * 2 + secondary.getGreen()) / 3; - int blue = (primary.getBlue() * 2 + secondary.getBlue()) / 3; - return new Color(red, green, blue); + return ColorUtils.blend(primary, secondary, 0.67); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java index ec521a8159..c1f758a93e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java @@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.fieldpanel.field.FieldElement; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.Highlight; +import generic.theme.GColor; import ghidra.GhidraOptions; import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES; import ghidra.app.plugin.processors.generic.PcodeFieldFactory; @@ -51,18 +52,15 @@ import ghidra.util.datastruct.Stack; public class ListingHighlightProvider implements ButtonPressedListener, OptionsChangeListener, HighlightProvider { - - private static final String DISPLAY_HIGHLIGHT_NAME = - CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Enabled"; - - private static final String SCOPED_WRITE_HIGHLIGHT_COLOR = - CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Scoped Write Highlight Color"; - - private static final String SCOPED_READ_HIGHLIGHT_COLOR = - CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Scoped Read Highlight Color"; - - private static final String SCOPE_REGISTER_OPERAND = - CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Scope Register Operand"; + //@formatter:off + private static final GColor DEFAULT_HIGHLIGHT_COLOR = new GColor("color.fg.listing.highlighter.default"); + private static final GColor DEFAULT_SCOPED_READ_COLOR = new GColor("color.fg.listing.highlighter.scoped.read"); + private static final GColor DEFAULT_SCOPED_WRITE_COLOR = new GColor("color.fg.listing.highlighter.scoped.write"); + private static final String DISPLAY_HIGHLIGHT_NAME = CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Enabled"; + private static final String SCOPED_WRITE_HIGHLIGHT_COLOR = CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Scoped Write Highlight Color"; + private static final String SCOPED_READ_HIGHLIGHT_COLOR = CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Scoped Read Highlight Color"; + private static final String SCOPE_REGISTER_OPERAND = CURSOR_HIGHLIGHT_GROUP + DELIMITER + "Scope Register Operand"; + //@formatter:on private static char[] UNDERSCORE_AND_PERIOD_OK = new char[] { '.', '_' }; private static char[] UNDERSCORE_OK = new char[] { '_' }; @@ -146,7 +144,7 @@ public class ListingHighlightProvider Pattern highlightPattern = currentHighlightPattern; Matcher matcher = highlightPattern.matcher(text); - List highlightList = new ArrayList(); + List highlightList = new ArrayList<>(); while (matcher.find()) { int start = matcher.start(); int end = matcher.end() - 1; @@ -481,7 +479,7 @@ public class ListingHighlightProvider } private Set getRegisterSet(Register reg) { - Set regSet = new HashSet(); + Set regSet = new HashSet<>(); regSet.add(reg); Register r = reg.getParentRegister(); while (r != null) { @@ -560,7 +558,7 @@ public class ListingHighlightProvider // and set writeScope, all other instructions upto that point will be // added to read scope Program prog = instr.getProgram(); - Stack
backStack = new Stack
(); + Stack
backStack = new Stack<>(); pushInstructionBackFlows(instr, backStack); while (!backStack.isEmpty()) { Address addr = backStack.pop(); @@ -589,7 +587,7 @@ public class ListingHighlightProvider // follow flow downwards until register is changed // add in each line that has register anywhere Program prog = instr.getProgram(); - Stack
stack = new Stack
(); + Stack
stack = new Stack<>(); pushInstructionFlows(instr, stack); while (!stack.isEmpty()) { Address addr = stack.pop(); @@ -849,7 +847,7 @@ public class ListingHighlightProvider varnodeSize -= intOff; varnodeOffset += intOff; - List varnodes = new ArrayList(); + List varnodes = new ArrayList<>(); for (Varnode v : variableStorage.getVarnodes()) { if (varnodeOffset >= v.getSize()) { varnodeOffset -= v.getSize(); @@ -871,11 +869,14 @@ public class ListingHighlightProvider ToolOptions opt = tool.getOptions(CATEGORY_BROWSER_FIELDS); HelpLocation hl = new HelpLocation("CodeBrowserPlugin", "Cursor_Text_Highlight"); - opt.registerOption(HIGHLIGHT_COLOR_NAME, Color.YELLOW, hl, + opt.registerThemeColorBinding(HIGHLIGHT_COLOR_NAME, + DEFAULT_HIGHLIGHT_COLOR.getId(), hl, "The color to use to highlight text."); - opt.registerOption(SCOPED_WRITE_HIGHLIGHT_COLOR, new Color(204, 204, 0), hl, + opt.registerThemeColorBinding(SCOPED_WRITE_HIGHLIGHT_COLOR, + DEFAULT_SCOPED_WRITE_COLOR.getId(), hl, "The color to use for showing a register being written."); - opt.registerOption(SCOPED_READ_HIGHLIGHT_COLOR, new Color(0, 255, 0), hl, + opt.registerThemeColorBinding(SCOPED_READ_HIGHLIGHT_COLOR, + DEFAULT_SCOPED_READ_COLOR.getId(), hl, "The color to use for showing a register being read."); opt.registerOption(SCOPE_REGISTER_OPERAND, true, hl, @@ -895,11 +896,11 @@ public class ListingHighlightProvider setHighlightString(null, null); } - textMatchingHighlightColor = opt.getColor(HIGHLIGHT_COLOR_NAME, Color.YELLOW); - + textMatchingHighlightColor = opt.getColor(HIGHLIGHT_COLOR_NAME, DEFAULT_HIGHLIGHT_COLOR); scopeWriteHighlightColor = - opt.getColor(SCOPED_WRITE_HIGHLIGHT_COLOR, new Color(204, 204, 0)); - scopeReadHighlightColor = opt.getColor(SCOPED_READ_HIGHLIGHT_COLOR, new Color(0, 255, 0)); + opt.getColor(SCOPED_WRITE_HIGHLIGHT_COLOR, DEFAULT_SCOPED_WRITE_COLOR); + scopeReadHighlightColor = + opt.getColor(SCOPED_READ_HIGHLIGHT_COLOR, DEFAULT_SCOPED_READ_COLOR); ///////////////////////////////////////////////////// diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkAndSelectionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkAndSelectionAction.java index e16ec4d06c..edcfe3a23a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkAndSelectionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkAndSelectionAction.java @@ -16,11 +16,11 @@ package ghidra.app.plugin.core.codebrowser; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.context.NavigatableActionContext; import ghidra.app.nav.Navigatable; import ghidra.app.util.HelpTopics; @@ -28,8 +28,6 @@ import ghidra.program.model.address.Address; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; -import resources.MultiIconBuilder; -import resources.ResourceManager; /** * Actions for creating a selection using two distinct steps. The first time the action @@ -61,17 +59,8 @@ public class MarkAndSelectionAction extends ToggleDockingAction { } private void buildIcons() { - ImageIcon baseImage = ResourceManager.loadImage("images/MarkSelection.png"); - ImageIcon mediaStart = ResourceManager.loadImage("images/media-playback-start.png"); - ImageIcon mediaStop = ResourceManager.loadImage("images/media-playback-stop.png"); - - MultiIconBuilder builder = new MultiIconBuilder(baseImage); - builder.addLowerRightIcon(mediaStart, 12, 12); - unarmedIcon = builder.build(); - - builder = new MultiIconBuilder(baseImage); - builder.addLowerRightIcon(mediaStop, 12, 12); - armedIcon = builder.build(); + unarmedIcon = new GIcon("icon.plugin.codebrowser.mark.and.select.unarmed"); + armedIcon = new GIcon("icon.plugin.codebrowser.mark.and.select.armed"); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java index 3515975d23..d906d9293e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java @@ -19,6 +19,7 @@ import java.awt.Color; import java.math.BigInteger; import docking.widgets.fieldpanel.support.BackgroundColorModel; +import generic.theme.GColor; import ghidra.app.services.MarkerService; import ghidra.app.util.viewer.listingpanel.ListingBackgroundColorModel; import ghidra.app.util.viewer.listingpanel.ListingPanel; @@ -33,7 +34,7 @@ public class MarkerServiceBackgroundColorModel implements ListingBackgroundColor private MarkerService markerService; private Program program; private AddressIndexMap indexMap; - private Color defaultBackgroundColor = Color.WHITE; + private Color defaultBackgroundColor = new GColor("color.bg.markerservice"); public MarkerServiceBackgroundColorModel(MarkerService markerService, Program program, AddressIndexMap indexMap) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/CloneCodeViewerAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/CloneCodeViewerAction.java index 968754cf06..ffec11468f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/CloneCodeViewerAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/CloneCodeViewerAction.java @@ -15,19 +15,17 @@ */ package ghidra.app.plugin.core.codebrowser.actions; - -import ghidra.app.context.ProgramActionContext; -import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; -import ghidra.util.HelpLocation; - import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; -import resources.ResourceManager; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; +import ghidra.app.context.ProgramActionContext; +import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; +import ghidra.util.HelpLocation; public class CloneCodeViewerAction extends DockingAction { @@ -36,27 +34,26 @@ public class CloneCodeViewerAction extends DockingAction { public CloneCodeViewerAction(String owner, CodeViewerProvider provider) { super("Code Viewer Clone", owner); this.provider = provider; - ImageIcon image = ResourceManager.loadImage("images/camera-photo.png"); - setToolBarData( new ToolBarData( image, "zzzz" ) ); + Icon image = new GIcon("icon.provider.clone"); + setToolBarData(new ToolBarData(image, "zzzz")); setDescription("Create a snapshot (disconnected) copy of this Listing window "); setHelpLocation(new HelpLocation("Snapshots", "Snapshots_Start")); - setKeyBindingData( new KeyBindingData( KeyEvent.VK_T, - InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK ) ); + setKeyBindingData(new KeyBindingData(KeyEvent.VK_T, + InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); } - + @Override - public boolean isEnabledForContext( ActionContext context ) { + public boolean isEnabledForContext(ActionContext context) { if (context instanceof ProgramActionContext) { - ProgramActionContext programContext = (ProgramActionContext)context; + ProgramActionContext programContext = (ProgramActionContext) context; return programContext.getProgram() != null; } return false; } - + @Override public void actionPerformed(ActionContext context) { provider.cloneWindow(); } } - diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java index 9705f14050..a8be3b9be8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/hover/DataTypeListingHover.java @@ -19,6 +19,7 @@ import javax.swing.JComponent; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.GhidraOptions; import ghidra.app.plugin.core.hover.AbstractConfigurableHover; import ghidra.app.util.ToolTipUtils; @@ -111,7 +112,8 @@ public class DataTypeListingHover extends AbstractConfigurableHover implements L } if (warningMsg.length() != 0) { String errorText = - "
" + warningMsg + "!

"; + "
" + + warningMsg + "!

"; toolTipText = toolTipText.replace("", errorText); } return createTooltipComponent(toolTipText); @@ -149,7 +151,9 @@ public class DataTypeListingHover extends AbstractConfigurableHover implements L result += "
Missing NULL terminator."; } if (sdi.getStringLength() > dataInstance.getLength()) { - result += "
String exceeds data field."; + result += + "
String exceeds data field."; } } return result; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingPlugin.java index 04de35dbbd..6d893403e1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingPlugin.java @@ -24,6 +24,7 @@ import org.jdom.Element; import docking.ActionContext; import docking.action.DockingAction; import docking.action.MenuData; +import generic.theme.GColor; import ghidra.app.CorePluginPackage; import ghidra.app.context.ListingActionContext; import ghidra.app.plugin.PluginCategoryNames; @@ -41,6 +42,7 @@ import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.program.util.ChangeManager; import ghidra.program.util.ProgramSelection; +import ghidra.util.ColorUtils; import ghidra.util.HelpLocation; import ghidra.util.task.SwingUpdateManager; @@ -61,7 +63,7 @@ public class ColorizingPlugin extends ProgramPlugin implements DomainObjectListe private static final String MARKER_DESCRIPTION = "Shows the location of user-applied colors"; private static final int PRIORITY = MarkerService.CHANGE_PRIORITY - 1; // lowest priority - private static final Color MARKER_COLOR = Color.PINK; + private static final Color MARKER_COLOR = new GColor("color.bg.plugin.colorizer.marker"); private static final String COLOR_HISTORY_XML_NAME = "COLOR_HISTORY"; private static final String COLOR_HISTORY_LIST_XML_NAME = "COLOR_HISTORY"; @@ -80,12 +82,7 @@ public class ColorizingPlugin extends ProgramPlugin implements DomainObjectListe private NextColorRangeAction nextAction; private PreviousColorRangeAction previousAction; - private SwingUpdateManager updateManager = new SwingUpdateManager(1000, new Runnable() { - @Override - public void run() { - doUpdate(); - } - }); + private SwingUpdateManager updateManager = new SwingUpdateManager(1000, () -> doUpdate()); public ColorizingPlugin(PluginTool tool) { super(tool); @@ -108,12 +105,12 @@ public class ColorizingPlugin extends ProgramPlugin implements DomainObjectListe public void readConfigState(SaveState saveState) { Element xmlElement = saveState.getXmlElement(COLOR_HISTORY_XML_NAME); if (xmlElement != null) { - List savedColorHistory = new ArrayList(); + List savedColorHistory = new ArrayList<>(); List colorElements = xmlElement.getChildren("COLOR"); for (Element element : colorElements) { String rgbString = element.getAttributeValue("RGB"); - int rgb = Integer.parseInt(rgbString); - savedColorHistory.add(new Color(rgb, true)); + int rgba = Integer.parseInt(rgbString); + savedColorHistory.add(ColorUtils.getColor(rgba)); } service.setColorHistory(savedColorHistory); @@ -153,15 +150,15 @@ public class ColorizingPlugin extends ProgramPlugin implements DomainObjectListe } @Override - public void serviceAdded(Class interfaceClass, Object service) { + public void serviceAdded(Class interfaceClass, Object newService) { if (interfaceClass.equals(MarkerService.class)) { - markerService = (MarkerService) service; + markerService = (MarkerService) newService; } } @Override - public void serviceRemoved(Class interfaceClass, Object service) { + public void serviceRemoved(Class interfaceClass, Object removedService) { if (interfaceClass.equals(MarkerService.class)) { markerService = null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingServiceProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingServiceProvider.java index 0b7b06eb48..6aab9f2753 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingServiceProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/colorizer/ColorizingServiceProvider.java @@ -20,16 +20,19 @@ import java.util.Collections; import java.util.List; import docking.options.editor.GhidraColorChooser; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.viewer.listingpanel.PropertyBasedBackgroundColorModel; import ghidra.framework.plugintool.PluginTool; import ghidra.program.database.IntRangeMap; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; +import ghidra.util.ColorUtils; import ghidra.util.exception.DuplicateNameException; class ColorizingServiceProvider implements ColorizingService { - private static final Color DEFAULT_COLOR = new Color(0x84AFD3); + private static final Color DEFAULT_COLOR = new GColor("color.bg.plugin.colorizer.default"); static final String COLOR_CHOOSER_TITLE = "Please Select Background Color"; private final PluginTool tool; @@ -86,7 +89,7 @@ class ColorizingServiceProvider implements ColorizingService { public Color getColorFromUser(Color suggestedColor) { if (colorChooser == null) { colorChooser = - new GhidraColorChooser(suggestedColor == null ? Color.WHITE : suggestedColor); + new GhidraColorChooser(suggestedColor == null ? Palette.WHITE : suggestedColor); colorChooser.setTitle(COLOR_CHOOSER_TITLE); if (savedColorHistory != null) { colorChooser.setColorHistory(savedColorHistory); @@ -133,9 +136,9 @@ class ColorizingServiceProvider implements ColorizingService { public Color getBackgroundColor(Address address) { IntRangeMap map = getColorRangeMap(false); if (map != null) { - Integer value = map.getValue(address); - if (value != null) { - return new Color(value, true); + Integer rgba = map.getValue(address); + if (rgba != null) { + return ColorUtils.getColor(rgba); } } return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentHistoryPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentHistoryPanel.java index 22b7668490..1d7f017456 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentHistoryPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/comments/CommentHistoryPanel.java @@ -16,12 +16,12 @@ package ghidra.app.plugin.core.comments; import java.awt.BorderLayout; -import java.awt.Color; import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.text.*; +import generic.theme.GColor; import ghidra.program.model.address.Address; import ghidra.program.model.listing.CommentHistory; import ghidra.program.model.listing.Program; @@ -115,18 +115,22 @@ class CommentHistoryPanel extends JPanel { textAttrSet = new SimpleAttributeSet(); textAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced"); textAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); - textAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE); + textAttrSet.addAttribute(StyleConstants.Foreground, + new GColor("color.fg.plugin.comments.history.text")); userAttrSet = new SimpleAttributeSet(); userAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); userAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12)); userAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); + userAttrSet.addAttribute(StyleConstants.Foreground, + new GColor("color.fg.plugin.comments.history.user")); dateAttrSet = new SimpleAttributeSet(); dateAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); dateAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11)); dateAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE); - dateAttrSet.addAttribute(StyleConstants.Foreground, new Color(124, 37, 18)); + dateAttrSet.addAttribute(StyleConstants.Foreground, + new GColor("color.fg.plugin.comments.history.date")); tabAttrSet = new SimpleAttributeSet(); TabStop tabs = new TabStop(100, StyleConstants.ALIGN_LEFT, TabStop.LEAD_NONE); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java index e427c082ac..6f22a7618a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java @@ -88,7 +88,9 @@ class CommentWindowProvider extends ComponentProviderAdapter { } void programClosed() { - commentModel.reload(null); + if (isVisible()) { + commentModel.reload(null); + } } void dispose() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java index cbae61492c..0f4f4fcefb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java @@ -15,12 +15,12 @@ */ package ghidra.app.plugin.core.compositeeditor; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; +import generic.theme.GIcon; import ghidra.app.util.datatype.EmptyCompositeException; import ghidra.program.model.data.InvalidDataTypeException; -import resources.ResourceManager; /** * ApplyAction is an action for applying editor changes. @@ -29,7 +29,7 @@ public class ApplyAction extends CompositeEditorTableAction { public final static String ACTION_NAME = "Apply Editor Changes"; private final static String GROUP_NAME = BASIC_ACTION_GROUP; - private final static ImageIcon ICON = ResourceManager.loadImage("images/disk.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.apply"); private final static String[] POPUP_PATH = new String[] { "Apply Edits" }; public ApplyAction(CompositeEditorProvider provider) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java index 2f94329ad0..124f21eb65 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java @@ -17,13 +17,13 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.util.exception.UsrException; -import resources.ResourceManager; /** * Action for use in the composite data type editor. @@ -31,7 +31,7 @@ import resources.ResourceManager; */ public class ArrayAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = ResourceManager.loadImage("images/Array.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.array"); public final static String ACTION_NAME = "Create Array"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Create an array"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java index adf37c72ae..e0db5a1d77 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java @@ -23,16 +23,18 @@ import docking.*; import docking.action.*; import docking.menu.DockingCheckboxMenuItemUI; import docking.widgets.OptionDialog; +import generic.theme.GIcon; import ghidra.app.services.DataTypeManagerService; import ghidra.program.model.data.*; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class BitFieldEditorDialog extends DialogComponentProvider { - private static final Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static final Icon EDIT_ICON = ResourceManager.loadImage("images/move.png"); - private static final Icon DELETE_ICON = ResourceManager.loadImage("images/edit-delete.png"); + //@formatter:off + private static final Icon ADD_ICON = new GIcon("icon.plugin.composite.editor.bit.field.dialog.add"); + private static final Icon EDIT_ICON = new GIcon("icon.plugin.composite.editor.bit.field.dialog.edit"); + private static final Icon DELETE_ICON = new GIcon("icon.plugin.composite.editor.bit.field.dialog.delete"); + //@formatter:on private DataTypeManagerService dtmService; private Composite composite; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java index a70cec5916..00fe100de6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java @@ -28,6 +28,8 @@ import docking.ActionContext; import docking.widgets.DropDownSelectionTextField; import docking.widgets.OptionDialog; import docking.widgets.label.GDLabel; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.compositeeditor.BitFieldPlacementComponent.BitAttributes; import ghidra.app.plugin.core.compositeeditor.BitFieldPlacementComponent.BitFieldAllocation; import ghidra.app.services.DataTypeManagerService; @@ -37,7 +39,6 @@ import ghidra.program.model.data.*; import ghidra.program.model.data.Composite; import ghidra.util.data.DataTypeParser.AllowedDataTypes; import ghidra.util.layout.*; -import resources.ResourceManager; /** * BitFieldEditorPanel provides the ability to add or modify bitfields @@ -45,8 +46,10 @@ import resources.ResourceManager; */ public class BitFieldEditorPanel extends JPanel { - private static final Icon DECREMENT_ICON = ResourceManager.loadImage("images/Minus.png"); - private static final Icon INCREMENT_ICON = ResourceManager.loadImage("images/Plus.png"); + //@formatter:off + private static final Icon DECREMENT_ICON = new GIcon("icon.plugin.composite.editor.bit.field.editor.decrement"); + private static final Icon INCREMENT_ICON = new GIcon("icon.plugin.composite.editor.bit.field.editor.increment"); + //@formatter:on private DataTypeManagerService dtmService; private Composite composite; @@ -73,7 +76,6 @@ public class BitFieldEditorPanel extends JPanel { private BitSelectionHandler bitSelectionHandler; - private boolean updating = false; BitFieldEditorPanel(Composite composite, DataTypeManagerService dtmService, @@ -179,7 +181,7 @@ public class BitFieldEditorPanel extends JPanel { statusTextField = new GDLabel(" "); statusTextField.setHorizontalAlignment(SwingConstants.CENTER); - statusTextField.setForeground(Color.red); + statusTextField.setForeground(Colors.ERROR); // use a strut panel so the size of the message area does not change if we make // the message label not visible diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java index 6d17bacfa2..2a42f9f853 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java @@ -22,6 +22,7 @@ import java.util.*; import javax.help.UnsupportedOperationException; import javax.swing.*; +import generic.theme.GColor; import ghidra.program.model.data.*; import ghidra.program.model.data.Composite; import ghidra.util.HTMLUtilities; @@ -42,15 +43,25 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable { private static final int LENEND_BOX_SIZE = 16; - private static final Color TEXT_COLOR = Color.black; - private static final Color LINE_COLOR = Color.black; - private static final Color BYTE_HEADER_COLOR = new Color(0xdfdfdf); - private static final Color UNDEFINED_BIT_COLOR = new Color(0xf8f8f8); - private static final Color ACTIVE_BITFIELD_BITS_COLOR = Color.green; - private static final Color CONFLICT_BITS_COLOR = Color.yellow; - private static final Color BITFIELD_COMPONENT_COLOR = new Color(0xbfbfff); - private static final Color NON_BITFIELD_COMPONENT_COLOR = new Color(0xa0a0ff); - private static final Color INTERIOR_LINE_COLOR = new Color(0xd4d4d4); + private static final Color TEXT_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.text"); + private static final Color LINE_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.line"); + private static final Color BYTE_HEADER_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.byte.header"); + + private static final Color UNDEFINED_BIT_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.bit.undefined"); + private static final Color BITFIELD_COMPONENT_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.bit.component"); + private static final Color ACTIVE_BITFIELD_BITS_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.bit.active"); + private static final Color CONFLICT_BITS_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.bit.conflict"); + private static final Color NON_BITFIELD_COMPONENT_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.non.bit"); + private static final Color INTERIOR_LINE_COLOR = + new GColor("color.bg.plugin.editors.compositeeditor.line.interior"); private int bitWidth = 10; private int byteWidth = getByteWidth(bitWidth); @@ -211,7 +222,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable { return; } if (e.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) { - // TODO: should we handle other modes? + // should we handle other modes? return; } e.consume(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java index f7ac6bf4c6..a75a0af547 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java @@ -17,20 +17,19 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; -import ghidra.util.Msg; +import generic.theme.GIcon; import ghidra.util.exception.UsrException; -import resources.ResourceManager; public class ClearAction extends CompositeEditorTableAction { public final static String ACTION_NAME = "Clear Components"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; - private final static ImageIcon ICON = ResourceManager.loadImage("images/erase16.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.clear"); private final static String[] POPUP_PATH = new String[] { "Clear" }; private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C, 0); @@ -47,10 +46,6 @@ public class ClearAction extends CompositeEditorTableAction { try { model.clearSelectedComponents(); } - catch (OutOfMemoryError memExc) { - String errMsg = "Couldn't clear components. Out of memory."; - Msg.showError(this, null, "Out of Memory", errMsg, memExc); - } catch (UsrException ue) { model.setStatus(ue.getMessage()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java index 3021dafa68..d2ddcbd9dc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java @@ -30,6 +30,7 @@ import docking.widgets.OptionDialog; import docking.widgets.button.GRadioButton; import docking.widgets.fieldpanel.support.FieldSelection; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.compositeeditor.BitFieldPlacementComponent.BitAttributes; import ghidra.program.model.data.*; import ghidra.program.model.data.Composite; @@ -394,7 +395,9 @@ public class CompEditorPanel extends CompositeEditorPanel { String alignmentToolTip = "The align control allows the overall minimum alignment of this
" + "data type to be specified. The actual computed alignment
" + - "may be any multiple of this value. (<F1> for help)"; + "may be any multiple of this value. " + + "(<F1> for help)"; alignPanel.setToolTipText(alignmentToolTip); addMinimumAlignmentComponents(); @@ -570,7 +573,8 @@ public class CompEditorPanel extends CompositeEditorPanel { infoPanel.add(actualAlignmentPanel, gridBagConstraints); actualAlignmentValueTextField = new JTextField(8); - actualAlignmentValueTextField.setText("" + ((CompEditorModel) model).getActualAlignment()); + actualAlignmentValueTextField + .setText(Integer.toString(((CompEditorModel) model).getActualAlignment())); actualAlignmentValueTextField.setToolTipText(actualAlignmentToolTip); actualAlignmentValueTextField.setEditable(false); if (helpManager != null) { @@ -586,7 +590,7 @@ public class CompEditorPanel extends CompositeEditorPanel { gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 3; infoPanel.add(actualAlignmentValueTextField, gridBagConstraints); - actualAlignmentValueTextField.setBackground(new Color(getBackground().getRGB())); + actualAlignmentValueTextField.setBackground(getBackground()); } private void setupPacking() { @@ -669,8 +673,11 @@ public class CompEditorPanel extends CompositeEditorPanel { private void setupPackingEnablementButton() { packingEnablementButton.setName("Packing Enablement"); String packingToolTipText = - "Enable packing when details of all components are known (including sizing and alignment).
" + - "Disable packing when Reverse Engineering composite. (<F1> for help)"; + "Enable packing when details of all components are known (including sizing and" + + " alignment).
" + + "Disable packing when Reverse Engineering composite. " + + "(<F1> for help)"; packingEnablementButton.addActionListener(e -> { ((CompEditorModel) model).setPackingType( packingEnablementButton.isSelected() ? PackingType.DEFAULT : PackingType.DISABLED, @@ -708,8 +715,9 @@ public class CompEditorPanel extends CompositeEditorPanel { explicitPackingButton.addActionListener(e -> chooseByValuePacking()); explicitPackingButton.setToolTipText(packingToolTipText); if (helpManager != null) { - helpManager.registerHelp(explicitPackingButton, new HelpLocation(provider.getHelpTopic(), - provider.getHelpName() + "_" + "Pack")); + helpManager.registerHelp(explicitPackingButton, + new HelpLocation(provider.getHelpTopic(), + provider.getHelpName() + "_" + "Pack")); } explicitPackingTextField.setName("Packing Value"); @@ -831,7 +839,7 @@ public class CompEditorPanel extends CompositeEditorPanel { } else { // not editable - use same background as panel - sizeTextField.setBackground(new Color(getBackground().getRGB())); + sizeTextField.setBackground(getBackground()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index 4bd980b492..450ab47ec1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -43,6 +43,7 @@ import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; import docking.widgets.table.*; import docking.widgets.textfield.GValidatedTextField; +import generic.theme.GColor; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.datatype.DataTypeSelectionEditor; import ghidra.app.util.datatype.NavigationDirection; @@ -70,8 +71,6 @@ public abstract class CompositeEditorPanel extends JPanel implements CompositeEditorModelListener, ComponentCellEditorListener, Draggable, Droppable { // Normal color for selecting components in the table. - // TODO: Why do we choose a different selection color? - //private static final Color SELECTION_COLOR = Color.YELLOW.brighter().brighter(); //protected static final Insets TEXTFIELD_INSETS = new JTextField().getInsets(); protected static final Border BEVELED_BORDER = BorderFactory.createLoweredBevelBorder(); @@ -605,8 +604,6 @@ public abstract class CompositeEditorPanel extends JPanel JScrollPane sp = new JScrollPane(table); table.setPreferredScrollableViewportSize(new Dimension(model.getWidth(), 250)); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - //table.setSelectionBackground(SELECTION_COLOR); - //table.setSelectionForeground(Color.black); tablePanel.add(sp, BorderLayout.CENTER); SearchControlPanel searchPanel = new SearchControlPanel(this); @@ -636,7 +633,7 @@ public abstract class CompositeEditorPanel extends JPanel // This can happen on the Mac and is usually white. This is a simple solution for // that scenario. If this fails on other platforms, then do something more advanced // at that point. - table.setGridColor(Color.GRAY); + table.setGridColor(new GColor("color.bg.table.grid")); } } @@ -668,7 +665,7 @@ public abstract class CompositeEditorPanel extends JPanel JPanel panel = new JPanel(new BorderLayout()); statusLabel = new GDLabel(" "); statusLabel.setHorizontalAlignment(SwingConstants.CENTER); - statusLabel.setForeground(Color.blue); + statusLabel.setForeground(new GColor("color.fg.dialog.status.normal")); statusLabel.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java index ca55101824..9fe4c4e392 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java @@ -22,6 +22,7 @@ import javax.swing.*; import docking.ActionContext; import docking.ComponentProvider; import docking.widgets.OptionDialog; +import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.datatype.EmptyCompositeException; @@ -33,7 +34,6 @@ import ghidra.util.HelpLocation; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import ghidra.util.exception.AssertException; -import resources.ResourceManager; /** * Editor provider for a Composite Data Type. @@ -41,8 +41,7 @@ import resources.ResourceManager; public abstract class CompositeEditorProvider extends ComponentProviderAdapter implements EditorProvider, EditorActionListener { - protected static final ImageIcon EDITOR_ICON = - ResourceManager.loadImage("images/accessories-text-editor.png"); + protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider"); protected Plugin plugin; protected Category category; @@ -56,9 +55,6 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter /** * Construct a new stack editor provider. * @param plugin owner of this provider - * @param program program for data type; may be null if data type - * is part of an archive - * @param stack the stack frame to be edited */ protected CompositeEditorProvider(Plugin plugin) { super(plugin.getTool(), "Composite Editor", plugin.getName()); @@ -283,6 +279,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter /** * Prompts the user if the editor has unsaved changes. Saves the changes if * the user indicates to do so. + * @param allowCancel true if allowed to cancel * @return 0 if the user canceled; 1 if the user saved changes; * 2 if the user did not to save changes; 3 if there was an error when * the changes were applied. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CreateInternalStructureAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CreateInternalStructureAction.java index f845f33353..163ee85ac8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CreateInternalStructureAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CreateInternalStructureAction.java @@ -17,15 +17,15 @@ package ghidra.app.plugin.core.compositeeditor; import java.util.Arrays; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; +import generic.theme.GIcon; import ghidra.util.Swing; import ghidra.util.exception.CancelledException; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Action for use in the structure data type editor. @@ -33,8 +33,7 @@ import resources.ResourceManager; */ public class CreateInternalStructureAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = - ResourceManager.loadImage("images/cstruct.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.create"); public final static String ACTION_NAME = "Create Structure From Selection"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeCellRenderer.java index 59dfe9478b..358c42b509 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeCellRenderer.java @@ -15,13 +15,13 @@ */ package ghidra.app.plugin.core.compositeeditor; -import java.awt.Color; import java.awt.Component; import javax.swing.JLabel; import docking.widgets.table.GTableCellRenderer; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.ToolTipUtils; import ghidra.program.model.data.*; import ghidra.util.HTMLUtilities; @@ -43,7 +43,7 @@ public class DataTypeCellRenderer extends GTableCellRenderer { String dtString = ""; String tooltipText = null; - boolean useRed = false; + boolean showError = false; DataType dt = null; if (value instanceof DataTypeInstance) { @@ -51,7 +51,7 @@ public class DataTypeCellRenderer extends GTableCellRenderer { tooltipText = getDataTypeToolTip(dt); dtString = dt.getDisplayName(); if (dt.isNotYetDefined()) { - useRed = true; + showError = true; } } @@ -61,8 +61,8 @@ public class DataTypeCellRenderer extends GTableCellRenderer { c.setToolTipText(tooltipText); - if (useRed) { - c.setForeground(Color.RED); + if (showError) { + c.setForeground(Colors.ERROR); } return c; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java index cd236c29df..f8c5062b8b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java @@ -17,22 +17,22 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.util.exception.CancelledException; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class DeleteAction extends CompositeEditorTableAction { public final static String ACTION_NAME = "Delete Components"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; - private final static ImageIcon ICON = ResourceManager.loadImage("images/edit-delete.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.delete"); private final static String[] popupPath = new String[] { "Delete" }; private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java index 9fdfe0393b..fc06774ae9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java @@ -18,21 +18,21 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Action to duplicate the selected row */ public class DuplicateAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = ResourceManager.loadImage("images/DuplicateData.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.duplicate"); public final static String ACTION_NAME = "Duplicate Component"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Duplicate the selected component"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java index 4ae608dd00..86a5d5e9ca 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java @@ -18,26 +18,26 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; import docking.widgets.dialogs.NumberInputDialog; +import generic.theme.GIcon; import ghidra.util.HelpLocation; import ghidra.util.exception.CancelledException; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Action that allows the user to make multiple duplicates of the selected item */ public class DuplicateMultipleAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = - ResourceManager.loadImage("images/MultiDuplicateData.png"); + private final static Icon ICON = + new GIcon("icon.plugin.composite.editor.duplicate.multiple"); public final static String ACTION_NAME = "Duplicate Multiple of Component"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Duplicate multiple of the selected component"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java index 72a8e6e557..abafcab546 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java @@ -18,14 +18,14 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.program.model.data.*; import ghidra.util.exception.UsrException; -import resources.ResourceManager; /** * Action for use in the structure data type editor. @@ -33,8 +33,7 @@ import resources.ResourceManager; */ public class InsertUndefinedAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = - ResourceManager.loadImage("images/Plus.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.insert.undefined"); public final static String ACTION_NAME = "Insert Undefined Byte"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Insert an undefined byte before the selection"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java index 8758059816..615e7fca54 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java @@ -18,13 +18,13 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.util.exception.UsrException; -import resources.ResourceManager; /** * Action for use in the composite data type editor. @@ -32,7 +32,7 @@ import resources.ResourceManager; */ public class MoveDownAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = ResourceManager.loadImage("images/down.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.move.down"); public final static String ACTION_NAME = "Move Components Down"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Move the selected components down"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java index 928b6e2e76..bf6a913b53 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java @@ -18,13 +18,13 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.util.exception.UsrException; -import resources.ResourceManager; /** * Action for use in the composite data type editor. @@ -32,7 +32,7 @@ import resources.ResourceManager; */ public class MoveUpAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = ResourceManager.loadImage("images/up.png"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.move.up"); public final static String ACTION_NAME = "Move Components Up"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Move selected components up"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java index 8e526522d2..eadb8d9e84 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java @@ -25,14 +25,12 @@ import javax.swing.event.DocumentListener; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GLabel; -import resources.ResourceManager; +import generic.theme.GIcon; public class SearchControlPanel extends JPanel { - private static final Icon NEXT_ICON = ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/go-down.tango.16.png"), 16, 16); - private static final Icon PREV_ICON = ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/go-up.tango.16.png"), 16, 16); + private static final Icon NEXT_ICON = new GIcon("icon.plugin.composite.editor.search.next"); + private static final Icon PREV_ICON = new GIcon("icon.plugin.composite.editor.search.previous"); private CompositeEditorPanel editorPanel; private JTextField textField; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java index 4fe4b8b260..6c16f9beba 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java @@ -19,9 +19,9 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.services.DataTypeManagerService; import ghidra.program.model.data.*; -import resources.ResourceManager; /** * Shows the editor's data type in the UI using the {@link DataTypeManagerService}. @@ -31,14 +31,13 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction { // This action should go after the row-based actions, which have this group: // 3_COMPONENT_EDITOR_ACTION private static final String TOOLBAR_GROUP = "4_COMPONENT_EDITOR_ACTION"; - private static final Icon ICON = ResourceManager.loadImage("images/go-home.png"); + private static final Icon ICON = new GIcon("icon.plugin.composite.editor.show.type"); public ShowDataTypeInTreeAction(CompositeEditorProvider provider) { super(provider, "Show In Data Type Manager", TOOLBAR_GROUP, null /*popupPath*/, null /*menuPath*/, ICON); - setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/go-home.png"), TOOLBAR_GROUP)); + setToolBarData(new ToolBarData(ICON, TOOLBAR_GROUP)); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java index 43b2e35865..05723a839d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java @@ -15,19 +15,19 @@ */ package ghidra.app.plugin.core.compositeeditor; -import javax.swing.ImageIcon; +import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.framework.plugintool.Plugin; import ghidra.program.model.data.Structure; -import resources.ResourceManager; /** * Editor for a Structure Data Type. */ public class StructureEditorProvider extends CompositeEditorProvider { - protected static final ImageIcon STRUCTURE_EDITOR_ICON = - ResourceManager.loadImage("images/cstruct.png"); + protected static final Icon STRUCTURE_EDITOR_ICON = + new GIcon("icon.plugin.composite.editor.provider.structure"); public StructureEditorProvider(Plugin plugin, Structure structureDataType, boolean showHexNumbers) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java index 3ac09cc3c9..9a17a3086e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java @@ -15,19 +15,19 @@ */ package ghidra.app.plugin.core.compositeeditor; -import javax.swing.ImageIcon; +import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.framework.plugintool.Plugin; import ghidra.program.model.data.Union; -import resources.ResourceManager; /** * Editor for a Union Data Type. */ public class UnionEditorProvider extends CompositeEditorProvider { - protected static final ImageIcon UNION_EDITOR_ICON = - ResourceManager.loadImage("images/cUnion.png"); + protected static final Icon UNION_EDITOR_ICON = + new GIcon("icon.plugin.composite.editor.provider.union"); public UnionEditorProvider(Plugin plugin, Union unionDataType, boolean showInHex) { super(plugin); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java index eeaed26cde..64b4fb04db 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnpackageAction.java @@ -17,17 +17,17 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.KeyBindingData; import docking.widgets.OptionDialog; +import generic.theme.GIcon; import ghidra.util.exception.CancelledException; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Action for use in the composite data type editor. @@ -35,7 +35,7 @@ import resources.ResourceManager; */ public class UnpackageAction extends CompositeEditorTableAction { - private final static ImageIcon ICON = ResourceManager.loadImage("images/Unpackage.gif"); + private final static Icon ICON = new GIcon("icon.plugin.composite.editor.unpackage"); public final static String ACTION_NAME = "Unpackage Component"; private final static String GROUP_NAME = COMPONENT_ACTION_GROUP; private final static String DESCRIPTION = "Replace the selected composite with its components"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java index f5ee090cff..3be30d4367 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java @@ -25,9 +25,10 @@ import javax.swing.text.Document; import docking.*; import docking.action.*; +import generic.theme.GIcon; +import generic.theme.Gui; import ghidra.app.services.*; import ghidra.framework.main.ConsoleTextPane; -import ghidra.framework.options.OptionsChangeListener; import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; @@ -35,26 +36,21 @@ import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.SymbolIterator; import ghidra.program.model.symbol.SymbolTable; -import ghidra.util.*; -import resources.ResourceManager; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; public class ConsoleComponentProvider extends ComponentProviderAdapter - implements ConsoleService, OptionsChangeListener { + implements ConsoleService { private static final String OLD_NAME = "ConsolePlugin"; private static final String NAME = "Console"; - private static final String CONSOLE_GIF = "images/monitor.png"; - private static final String CLEAR_GIF = "images/erase16.png"; - private static final String SCROLL_LOCK_GIF = "images/lock.png"; - - private static final Font DEFAULT_FONT = new Font("monospaced", Font.PLAIN, 12); + private static final String DEFAULT_FONT_ID = "font.plugin.console"; private static final String FONT_OPTION_LABEL = "Font"; private static final String FONT_DESCRIPTION = "This is the font that will be used in the Console. " + "Double-click the font example to change it."; - private Font font; private ConsoleTextPane textPane; private JScrollPane scroller; private JComponent component; @@ -74,7 +70,7 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter setDefaultWindowPosition(WindowPosition.BOTTOM); setHelpLocation(new HelpLocation(owner, owner)); - setIcon(ResourceManager.loadImage(CONSOLE_GIF)); + setIcon(new GIcon("icon.plugin.console.provider")); setWindowMenuGroup("Console"); setSubTitle("Scripting"); setTitle("Console"); @@ -107,27 +103,16 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter private void createOptions() { ToolOptions options = tool.getOptions("Console"); HelpLocation help = new HelpLocation(getOwner(), getOwner()); - options.registerOption(FONT_OPTION_LABEL, DEFAULT_FONT, help, FONT_DESCRIPTION); + options.registerThemeFontBinding(FONT_OPTION_LABEL, DEFAULT_FONT_ID, help, + FONT_DESCRIPTION); options.setOptionsHelpLocation(help); - font = options.getFont(FONT_OPTION_LABEL, DEFAULT_FONT); - font = SystemUtilities.adjustForFontSizeOverride(font); - options.addOptionsChangeListener(this); - } - - @Override - public void optionsChanged(ToolOptions options, String optionName, Object oldValue, - Object newValue) { - if (optionName.equals(FONT_OPTION_LABEL)) { - font = SystemUtilities.adjustForFontSizeOverride((Font) newValue); - textPane.setFont(font); - } } private void build() { textPane = new ConsoleTextPane(tool); textPane.setName("CONSOLE"); - textPane.setFont(font); + Gui.registerFont(textPane, DEFAULT_FONT_ID); textPane.setEditable(false); textPane.addMouseMotionListener(new MouseMotionAdapter() { @Override @@ -281,7 +266,7 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter }; clearAction.setDescription("Clear Console"); // ACTIONS - auto generated - clearAction.setToolBarData(new ToolBarData(ResourceManager.loadImage(CLEAR_GIF), null)); + clearAction.setToolBarData(new ToolBarData(new GIcon("icon.plugin.console.clear"), null)); clearAction.setEnabled(true); @@ -293,7 +278,8 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter }; scrollAction.setDescription("Scroll Lock"); scrollAction - .setToolBarData(new ToolBarData(ResourceManager.loadImage(SCROLL_LOCK_GIF), null)); + .setToolBarData( + new ToolBarData(new GIcon("icon.plugin.console.scroll.lock"), null)); scrollAction.setEnabled(true); scrollAction.setSelected(scrollLock); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java index 61a8977002..3aad90b9ee 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/cparser/ParseDialog.java @@ -44,7 +44,6 @@ import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.filechooser.ExtensionFileFilter; import resources.Icons; -import resources.ResourceManager; /** * Dialog that shows files used for parsing C header files. The profile has a list of @@ -341,7 +340,7 @@ class ParseDialog extends DialogComponentProvider { } }; saveAction.setEnabled(false); - ImageIcon icon = ResourceManager.loadImage("images/disk.png"); + Icon icon = Icons.SAVE_ICON; String saveGroup = "save"; saveAction.setMenuBarData(new MenuData(new String[] { "Save" }, icon, saveGroup)); saveAction.setToolBarData(new ToolBarData(icon, saveGroup)); @@ -355,7 +354,7 @@ class ParseDialog extends DialogComponentProvider { } }; saveAsAction.setEnabled(true); - icon = ResourceManager.loadImage("images/disk_save_as.png"); + icon = Icons.SAVE_AS_ICON; saveAsAction.setMenuBarData(new MenuData(new String[] { "Save As..." }, icon, saveGroup)); saveAsAction.setToolBarData(new ToolBarData(icon, saveGroup)); saveAsAction.setDescription("Save profile to new name"); @@ -369,10 +368,10 @@ class ParseDialog extends DialogComponentProvider { }; clearAction.setEnabled(true); - icon = ResourceManager.loadImage("images/erase16.png"); + icon = Icons.CLEAR_ICON; String clearGroup = "clear"; - clearAction.setMenuBarData( - new MenuData(new String[] { "Clear Profile" }, icon, clearGroup)); + clearAction + .setMenuBarData(new MenuData(new String[] { "Clear Profile" }, icon, clearGroup)); clearAction.setToolBarData(new ToolBarData(icon, clearGroup)); clearAction.setDescription("Clear profile"); addAction(clearAction); @@ -399,7 +398,7 @@ class ParseDialog extends DialogComponentProvider { } }; deleteAction.setEnabled(false); - icon = ResourceManager.loadImage("images/edit-delete.png"); + icon = Icons.DELETE_ICON; String deleteGroup = "Xdelete"; deleteAction.setMenuBarData(new MenuData(new String[] { "Delete" }, icon, deleteGroup)); deleteAction.setToolBarData(new ToolBarData(icon, deleteGroup)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java index 83c88dcb5d..5d3d6c9eda 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/CreateStructureDialog.java @@ -15,10 +15,10 @@ */ package ghidra.app.plugin.core.data; -import java.awt.*; +import java.awt.Component; +import java.awt.Dimension; import java.awt.event.*; import java.util.*; -import java.util.List; import javax.swing.*; import javax.swing.border.TitledBorder; @@ -31,6 +31,7 @@ import javax.swing.text.Document; import docking.DialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.table.*; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.ToolTipUtils; import ghidra.framework.plugintool.PluginTool; @@ -272,18 +273,17 @@ public class CreateStructureDialog extends DialogComponentProvider { return matchingStylePanel; } - // toggles whether the structure being created is new, based upon the - // name field, or a current structure, based upon a structure in the - // table. This method updates the GUI to reflect the current creation - // state. + // toggles whether the structure being created is new, based upon the name field, or a current + // structure, based upon a structure in the table. This method updates the GUI to reflect the + // current creation state. private void setCreateStructureByName(boolean createStructureByName) { if (createStructureByName) { - nameBorder.setTitleColor(Color.BLACK); - structureBorder.setTitleColor(Color.GRAY); + nameBorder.setTitleColor(Colors.FOREGROUND); + structureBorder.setTitleColor(Colors.FOREGROUND_DISABLED); } else { - nameBorder.setTitleColor(Color.GRAY); - structureBorder.setTitleColor(Color.BLACK); + nameBorder.setTitleColor(Colors.FOREGROUND_DISABLED); + structureBorder.setTitleColor(Colors.FOREGROUND); } nameTextField.setEnabled(createStructureByName); @@ -299,7 +299,7 @@ public class CreateStructureDialog extends DialogComponentProvider { // this class in terms of data contained private void searchForMatchingStructures(final Program program, final Structure structure) { - SwingUtilities.invokeLater(() -> { + Swing.runLater(() -> { // Get the structures from the DataTypeManagers of the // DataTypeManagerService DataTypeManagerService service = pluginTool.getService(DataTypeManagerService.class); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeComparePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeComparePanel.java index 670762ce09..368eeb90d7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeComparePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeComparePanel.java @@ -18,10 +18,9 @@ package ghidra.app.plugin.core.datamgr; import java.awt.*; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.ToolTipUtils; import ghidra.app.util.html.HTMLDataTypeRepresentation; import ghidra.program.model.data.DataType; @@ -41,13 +40,6 @@ class DataTypeComparePanel extends JPanel { private String clientName; private String sourceName; - /** - * Creates a panel for viewing two data types side by side. - * @param dataType1 the first data type to display. - * @param dataType2 the second data type to display. - * @param one_to_two true if this panel should display an arrow from data type 1 to data type 2. - * false if the should be from 2 to 1. - */ DataTypeComparePanel(String clientName, String sourceName) { super(new GridLayout(0, 2)); this.clientName = clientName; @@ -72,12 +64,12 @@ class DataTypeComparePanel extends JPanel { add(rightPanel); dtLabel1 = new GDHtmlLabel(); dtLabel1.setOpaque(true); - dtLabel1.setBackground(Color.WHITE); + dtLabel1.setBackground(Colors.BACKGROUND); dtLabel1.setBorder(BorderFactory.createEmptyBorder(2, 8, 0, 0)); dtLabel1.setVerticalAlignment(SwingConstants.TOP); dtLabel2 = new GDHtmlLabel(); dtLabel2.setOpaque(true); - dtLabel2.setBackground(Color.WHITE); + dtLabel2.setBackground(Colors.BACKGROUND); dtLabel2.setBorder(BorderFactory.createEmptyBorder(2, 8, 0, 0)); dtLabel2.setVerticalAlignment(SwingConstants.TOP); @@ -96,19 +88,13 @@ class DataTypeComparePanel extends JPanel { private void syncScrollers(JScrollPane leftScrollPane, JScrollPane rightScrollPane) { final JViewport viewport1 = leftScrollPane.getViewport(); final JViewport viewport2 = rightScrollPane.getViewport(); - viewport1.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - int y = viewport1.getViewPosition().y; - viewport2.setViewPosition(new Point(0, y)); - } + viewport1.addChangeListener(e -> { + int y = viewport1.getViewPosition().y; + viewport2.setViewPosition(new Point(0, y)); }); - viewport2.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - int y = viewport2.getViewPosition().y; - viewport1.setViewPosition(new Point(0, y)); - } + viewport2.addChangeListener(e -> { + int y = viewport2.getViewPosition().y; + viewport1.setViewPosition(new Point(0, y)); }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java index 8d6445e231..ff576efdc3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java @@ -37,6 +37,7 @@ import docking.widgets.PopupWindow; import docking.widgets.textpane.GHtmlTextPane; import docking.widgets.tree.*; import docking.widgets.tree.support.GTreeSelectionEvent.EventOrigin; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.actions.*; import ghidra.app.plugin.core.datamgr.actions.associate.*; import ghidra.app.plugin.core.datamgr.archive.*; @@ -55,12 +56,10 @@ import ghidra.program.model.listing.DataTypeArchive; import ghidra.program.model.listing.Program; import ghidra.util.*; import ghidra.util.task.SwingUpdateManager; -import resources.ResourceManager; import util.HistoryList; public class DataTypesProvider extends ComponentProviderAdapter { - private static final String DATA_TYPES_ICON = "images/dataTypes.png"; private static final String TITLE = "Data Type Manager"; private static final String POINTER_FILTER_STATE = "PointerFilterState"; private static final String ARRAY_FILTER_STATE = "ArrayFilterState"; @@ -103,7 +102,7 @@ public class DataTypesProvider extends ComponentProviderAdapter { this.plugin = plugin; setTitle(TITLE); - setIcon(ResourceManager.loadImage(DATA_TYPES_ICON)); + setIcon(new GIcon("icon.plugin.datatypes.provider")); addToToolbar(); navigationHistory.setAllowDuplicates(true); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CollapseAllArchivesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CollapseAllArchivesAction.java index da37e16902..a84f5a96cb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CollapseAllArchivesAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/CollapseAllArchivesAction.java @@ -19,7 +19,7 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.tree.TreePath; import docking.ActionContext; @@ -40,7 +40,7 @@ import resources.Icons; */ public class CollapseAllArchivesAction extends DockingAction { - private ImageIcon collapseIcon = Icons.COLLAPSE_ALL_ICON; + private Icon collapseIcon = Icons.COLLAPSE_ALL_ICON; private final DataTypeManagerPlugin plugin; public CollapseAllArchivesAction(DataTypeManagerPlugin plugin) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ConflictHandlerModesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ConflictHandlerModesAction.java index 872813e847..33eed2e402 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ConflictHandlerModesAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/ConflictHandlerModesAction.java @@ -20,11 +20,11 @@ import javax.swing.Icon; import docking.menu.ActionState; import docking.menu.MultiStateDockingAction; import docking.widgets.EventTrigger; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.program.model.data.DataTypeConflictHandler; import ghidra.program.model.data.DataTypeConflictHandler.ConflictResolutionPolicy; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ConflictHandlerModesAction extends MultiStateDockingAction { @@ -41,10 +41,12 @@ public class ConflictHandlerModesAction extends new HelpLocation(plugin.getName(), "conflict_mode"); setHelpLocation(conflictModesHelpLocation); - Icon renameAndAddIcon = ResourceManager.loadImage("images/conflictRename.png"); - Icon useExistingIcon = ResourceManager.loadImage("images/conflictKeep.png"); - Icon replaceExistingIcon = ResourceManager.loadImage("images/conflictReplace.png"); - Icon replaceDefaultIcon = ResourceManager.loadImage("images/conflictReplaceOrRename.png"); + //@formatter:off + Icon renameAndAddIcon = new GIcon("icon.plugin.datatypes.conflict.mode.rename.and.add"); + Icon useExistingIcon = new GIcon("icon.plugin.datatypes.conflict.mode.use.existing"); + Icon replaceExistingIcon = new GIcon("icon.plugin.datatypes.conflict.mode.replace.existing"); + Icon replaceDefaultIcon = new GIcon("icon.plugin.datatypes.conflict.mode.replace.or.rename"); + //@formatter:on ActionState renameAndAddState = new ActionState<>( diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java index ee790a84b3..7e2343a725 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DeleteArchiveAction.java @@ -24,6 +24,7 @@ import docking.ActionContext; import docking.action.*; import docking.widgets.OptionDialog; import docking.widgets.tree.GTree; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datamgr.DataTypesActionContext; import ghidra.app.plugin.core.datamgr.archive.FileArchive; @@ -95,7 +96,8 @@ public class DeleteArchiveAction extends DockingAction { "Confirm Delete Operation", "Are you sure you want to delete archive: " + HTMLUtilities.escapeHTML(node.getName()) + "?

" + - "(WARNING: This action will permanently " + + "(WARNING: This action will permanently " + "delete the file from disk.)
", "Yes", OptionDialog.QUESTION_MESSAGE) != OptionDialog.OPTION_ONE) { return; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterArraysAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterArraysAction.java index 1f405edfa9..95253ccff3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterArraysAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterArraysAction.java @@ -23,22 +23,23 @@ import javax.swing.tree.TreePath; import docking.ActionContext; import docking.action.ToggleDockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datamgr.DataTypesActionContext; import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree; import ghidra.util.HTMLUtilities; -import resources.ResourceManager; public class FilterArraysAction extends ToggleDockingAction { - private static final Icon FILTER_ARRAYS_ICON = - ResourceManager.loadImage("images/FilterArrays.png"); - private static final Icon ARRAY_ICON = ResourceManager.loadImage("images/Array.png"); + //@formatter:off + private static final Icon FILTER_ON_ICON = new GIcon("icon.plugin.datatypes.filter.arrays.on"); + private static final Icon FILTER_OFF_ICON = new GIcon("icon.plugin.datatypes.filter.arrays.off"); + //@formatter:on public FilterArraysAction(DataTypeManagerPlugin plugin) { super("Filter Arrays", plugin.getName()); - this.setToolBarData(new ToolBarData(FILTER_ARRAYS_ICON, "filters")); + this.setToolBarData(new ToolBarData(FILTER_ON_ICON, "filters")); setDescription(HTMLUtilities.toHTML( "Toggle whether or not Arrays are\n" + "displayed in the Data Type Manager tree.")); @@ -66,7 +67,7 @@ public class FilterArraysAction extends ToggleDockingAction { @Override public void setSelected(boolean selected) { - getToolBarData().setIcon(selected ? FILTER_ARRAYS_ICON : ARRAY_ICON); + getToolBarData().setIcon(selected ? FILTER_ON_ICON : FILTER_OFF_ICON); super.setSelected(selected); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterPointersAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterPointersAction.java index d1b3cfb29a..e3f587aa77 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterPointersAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/FilterPointersAction.java @@ -23,21 +23,23 @@ import javax.swing.tree.TreePath; import docking.ActionContext; import docking.action.ToggleDockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datamgr.DataTypesActionContext; import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree; import ghidra.util.HTMLUtilities; -import resources.ResourceManager; public class FilterPointersAction extends ToggleDockingAction { - private static final Icon FILTER_POINTERS_ICON = - ResourceManager.loadImage("images/FilterPointers.png"); - private static final Icon POINTER_ICON = ResourceManager.loadImage("images/fingerPointer.png"); + + //@formatter:off + private static final Icon FILTER_ON_ICON = new GIcon("icon.plugin.datatypes.filter.pointers.on"); + private static final Icon FILTER_OFF_ICON = new GIcon("icon.plugin.datatypes.filter.pointers.off"); + //@formatter:on public FilterPointersAction(DataTypeManagerPlugin plugin) { super("Filter Pointers", plugin.getName()); - this.setToolBarData(new ToolBarData(FILTER_POINTERS_ICON, "filters")); + this.setToolBarData(new ToolBarData(FILTER_ON_ICON, "filters")); setDescription(HTMLUtilities.toHTML( "Toggle whether or not Pointers are\n" + "displayed in the Data Type Manager tree.")); @@ -67,7 +69,7 @@ public class FilterPointersAction extends ToggleDockingAction { @Override public void setSelected(boolean selected) { - getToolBarData().setIcon(selected ? FILTER_POINTERS_ICON : POINTER_ICON); + getToolBarData().setIcon(selected ? FILTER_ON_ICON : FILTER_OFF_ICON); super.setSelected(selected); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java index 2b8b847c18..43895edceb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RemoveInvalidArchiveFromProgramAction.java @@ -23,6 +23,7 @@ import docking.action.MenuData; import docking.widgets.OptionDialog; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datamgr.DataTypesActionContext; import ghidra.app.plugin.core.datamgr.archive.*; @@ -79,7 +80,8 @@ public class RemoveInvalidArchiveFromProgramAction extends DockingAction { "Are you sure you want to delete archive: " + HTMLUtilities.escapeHTML(invalidArchiveNode.getName()) + " from the program?

" + - "(WARNING: This action will disassociate " + + "(WARNING: This action will disassociate " + "all datatypes in the program from this archive.)
", "Yes", OptionDialog.QUESTION_MESSAGE) != OptionDialog.OPTION_ONE) { return; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/TypeGraphTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/TypeGraphTask.java index 2f82ea310d..ee9ed3929b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/TypeGraphTask.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/TypeGraphTask.java @@ -17,6 +17,7 @@ package ghidra.app.plugin.core.datamgr.actions; import java.awt.Color; +import generic.theme.GColor; import ghidra.app.util.ToolTipUtils; import ghidra.program.model.data.*; import ghidra.service.graph.*; @@ -33,6 +34,13 @@ import ghidra.util.task.TaskMonitor; */ public class TypeGraphTask extends Task { + private static final Color BG_COLOR_DEFAULT = + new GColor("color.bg.plugin.datamgr.edge.default"); + private static final Color BG_COLOR_COMPOSITE = + new GColor("color.bg.plugin.datamgr.edge.composite"); + private static final Color BG_COLOR_REFERERNCE = + new GColor("color.bg.plugin.datamgr.edge.reference"); + private DataType type; private String graphTitle; private GraphDisplayProvider graphService; @@ -64,9 +72,9 @@ public class TypeGraphTask extends Task { .build(); GraphDisplayOptions options = new GraphDisplayOptionsBuilder(graphType) - .defaultVertexColor(Color.BLUE) - .edge(COMPOSITE, Color.MAGENTA) - .edge(REFERENCE, Color.BLUE) + .defaultVertexColor(BG_COLOR_DEFAULT) + .edge(COMPOSITE, BG_COLOR_COMPOSITE) + .edge(REFERENCE, BG_COLOR_REFERERNCE) .build(); AttributedGraph graph = new AttributedGraph(graphTitle, graphType); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java index 63b169a023..4fe152dbc8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/CommitSingleDataTypeAction.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.datamgr.actions.associate; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.tree.TreePath; import docking.ActionContext; @@ -24,6 +24,7 @@ import docking.action.MenuData; import docking.widgets.OptionDialog; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.*; import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler; import ghidra.app.plugin.core.datamgr.tree.DataTypeNode; @@ -31,13 +32,12 @@ import ghidra.app.plugin.core.datamgr.util.DataTypeUtils; import ghidra.program.model.data.*; import ghidra.util.Msg; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.EmptyIcon; import resources.icons.TranslateIcon; public class CommitSingleDataTypeAction extends DockingAction { - private static ImageIcon COMMIT_ICON = ResourceManager.loadImage("images/smallRightArrow.png"); + private static Icon COMMIT_ICON = new GIcon("icon.plugin.datatypes.commit.single.type"); private final DataTypeManagerPlugin plugin; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/UpdateSingleDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/UpdateSingleDataTypeAction.java index a604a2e470..e0cb3d5a7c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/UpdateSingleDataTypeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/associate/UpdateSingleDataTypeAction.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.datamgr.actions.associate; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.tree.TreePath; import docking.ActionContext; @@ -24,19 +24,19 @@ import docking.action.MenuData; import docking.widgets.OptionDialog; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.*; import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler; import ghidra.app.plugin.core.datamgr.tree.DataTypeNode; import ghidra.app.plugin.core.datamgr.util.DataTypeUtils; import ghidra.program.model.data.*; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.EmptyIcon; import resources.icons.TranslateIcon; public class UpdateSingleDataTypeAction extends DockingAction { - private static ImageIcon UPDATE_ICON = ResourceManager.loadImage("images/smallLeftArrow.png"); + private static Icon UPDATE_ICON = new GIcon("icon.plugin.datatypes.associate.single.type"); private final DataTypeManagerPlugin plugin; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/Archive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/Archive.java index d7f44f016f..77a349dbba 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/Archive.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/Archive.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +15,13 @@ */ package ghidra.app.plugin.core.datamgr.archive; -import ghidra.app.merge.DataTypeManagerOwner; -import ghidra.util.exception.DuplicateFileException; - import java.awt.Component; import java.io.IOException; -import javax.swing.ImageIcon; +import javax.swing.Icon; + +import ghidra.app.merge.DataTypeManagerOwner; +import ghidra.util.exception.DuplicateFileException; /** * This is an interface for data type archives. @@ -63,13 +62,15 @@ public interface Archive extends DataTypeManagerOwner, Comparable { /** * Saves this archive. Some archives cannot be saved. + * @throws DuplicateFileException if there is an exception saving + * @throws IOException if there is an exception saving */ public void save() throws DuplicateFileException, IOException; /** * Saves this archive to a newly named file. - * @param component - * @throws IOException + * @param component the parent component the any dialogs shown + * @throws IOException if there is an exception saving */ public void saveAs(Component component) throws IOException; @@ -79,5 +80,5 @@ public interface Archive extends DataTypeManagerOwner, Comparable { * false indicates the node is closed. * @return the archive's icon. */ - public ImageIcon getIcon(boolean expanded); + public Icon getIcon(boolean expanded); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java index d8eff7bcd7..9a874a75aa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/BuiltInArchive.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +15,20 @@ */ package ghidra.app.plugin.core.datamgr.archive; +import java.awt.Component; +import java.io.IOException; + +import javax.swing.Icon; + +import generic.theme.GIcon; import ghidra.program.model.data.BuiltInDataTypeManager; import ghidra.program.model.data.DataTypeManager; import ghidra.util.exception.DuplicateFileException; -import java.awt.Component; -import java.io.IOException; - -import javax.swing.ImageIcon; - -import resources.ResourceManager; - public class BuiltInArchive implements Archive { - private static ImageIcon CLOSED_ICON = ResourceManager.loadImage("images/closedBookBrown.png"); - private static ImageIcon OPEN_ICON = ResourceManager.loadImage("images/openBookBrown.png"); + private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.built.in.closed"); + private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.built.in.open"); private DataTypeManagerHandler archiveManager; private BuiltInDataTypeManager dataTypeManager; @@ -39,43 +37,53 @@ public class BuiltInArchive implements Archive { this.dataTypeManager = dataTypeManager; } + @Override public DataTypeManager getDataTypeManager() { return dataTypeManager; } + @Override public String getName() { return dataTypeManager.getName(); } + @Override public int compareTo(Archive archive) { return -1; // Built-ins are always at the top } + @Override public boolean isModifiable() { return false; // Can't change the data types that are in Built-Ins. } + @Override public void close() { // Not allowed to close the Built In Data Type Manager. } + @Override public boolean isChanged() { return false; // Can't change. } + @Override public boolean isSavable() { return false; // Can't save. } + @Override public void save() throws DuplicateFileException, IOException { // Can't "Save" so do nothing. } + @Override public void saveAs(Component component) throws IOException { // Can't "Save As" so do nothing. } - public ImageIcon getIcon(boolean expanded) { + @Override + public Icon getIcon(boolean expanded) { return expanded ? OPEN_ICON : CLOSED_ICON; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java index e231a4d2bd..2bd2685b94 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/FileArchive.java @@ -19,13 +19,13 @@ import java.awt.Component; import java.io.File; import java.io.IOException; -import javax.swing.ImageIcon; +import javax.swing.Icon; import generic.jar.ResourceFile; +import generic.theme.GIcon; import ghidra.framework.store.LockException; import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateFileException; -import resources.ResourceManager; /** * Manages a DataTypeFileManager and relative state. For example, whether the manager is writable @@ -33,8 +33,8 @@ import resources.ResourceManager; */ public class FileArchive implements Archive { - private static ImageIcon CLOSED_ICON = ResourceManager.loadImage("images/closedBookGreen.png"); - private static ImageIcon OPEN_ICON = ResourceManager.loadImage("images/openBookGreen.png"); + private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.file.closed"); + private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.file.open"); private ResourceFile archiveFile; private boolean hasWriteLock; private boolean changed; @@ -292,7 +292,7 @@ public class FileArchive implements Archive { } @Override - public ImageIcon getIcon(boolean expanded) { + public Icon getIcon(boolean expanded) { return expanded ? OPEN_ICON : CLOSED_ICON; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java index e62ebb58d9..526fc35932 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/InvalidFileArchive.java @@ -18,17 +18,17 @@ package ghidra.app.plugin.core.datamgr.archive; import java.awt.Component; import java.io.IOException; -import javax.swing.ImageIcon; +import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.program.model.data.*; import ghidra.util.UniversalID; import ghidra.util.exception.DuplicateFileException; -import resources.ResourceManager; public class InvalidFileArchive implements Archive { - private static final ImageIcon INVALID_ARCHIVE_ICON = - ResourceManager.loadImage("images/closedFolderInvalid.png"); + private static final Icon INVALID_ARCHIVE_ICON = + new GIcon("icon.plugin.datatypes.archive.invalid"); private DataTypeManagerHandler archiveManager; private UniversalID universalID; private ArchiveType archiveType; @@ -104,7 +104,7 @@ public class InvalidFileArchive implements Archive { } @Override - public ImageIcon getIcon(boolean expanded) { + public Icon getIcon(boolean expanded) { return INVALID_ARCHIVE_ICON; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java index 386a59c45a..b07baf6cea 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProgramArchive.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +15,22 @@ */ package ghidra.app.plugin.core.datamgr.archive; +import java.awt.Component; +import java.io.IOException; + +import javax.swing.Icon; + +import generic.theme.GIcon; import ghidra.framework.model.DomainFile; import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManagerChangeListener; import ghidra.program.model.listing.Program; import ghidra.util.exception.DuplicateFileException; -import java.awt.Component; -import java.io.IOException; - -import javax.swing.ImageIcon; - -import resources.ResourceManager; - public class ProgramArchive implements DomainFileArchive { - private static ImageIcon CLOSED_ICON = ResourceManager.loadImage("images/closedBookRed.png"); - private static ImageIcon OPEN_ICON = ResourceManager.loadImage("images/openBookRed.png"); + private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.program.closed"); + private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.program.open"); private final Program program; DataTypeManagerChangeListener categoryListener; // hold on to since it is stored in a weak set private DataTypeManager dataTypeManager; @@ -105,7 +103,7 @@ public class ProgramArchive implements DomainFileArchive { } @Override - public ImageIcon getIcon(boolean expanded) { + public Icon getIcon(boolean expanded) { return expanded ? OPEN_ICON : CLOSED_ICON; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java index ddea7e1858..8dd3531961 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/ProjectArchive.java @@ -15,21 +15,20 @@ */ package ghidra.app.plugin.core.datamgr.archive; +import java.awt.Component; +import java.io.IOException; + +import javax.swing.Icon; + +import generic.theme.GIcon; import ghidra.framework.model.DomainFile; import ghidra.program.model.data.*; import ghidra.program.model.listing.DataTypeArchive; -import java.awt.Component; -import java.io.IOException; - -import javax.swing.ImageIcon; - -import resources.ResourceManager; - public class ProjectArchive implements DomainFileArchive { - private static ImageIcon CLOSED_ICON = ResourceManager.loadImage("images/closedBookBlue.png"); - private static ImageIcon OPEN_ICON = ResourceManager.loadImage("images/openBookBlue.png"); + private static Icon CLOSED_ICON = new GIcon("icon.plugin.datatypes.archive.project.closed"); + private static Icon OPEN_ICON = new GIcon("icon.plugin.datatypes.archive.project.open"); private DataTypeArchive dataTypeArchive; private DomainFile originalDomainFile; DataTypeManagerChangeListener categoryListener; // hold on to since it is stored in a weak set @@ -115,7 +114,7 @@ public class ProjectArchive implements DomainFileArchive { } @Override - public ImageIcon getIcon(boolean expanded) { + public Icon getIcon(boolean expanded) { return expanded ? OPEN_ICON : CLOSED_ICON; } @@ -140,7 +139,8 @@ public class ProjectArchive implements DomainFileArchive { } @Override - public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) { + public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, + CategoryPath newPath) { if (!oldPath.equals(newPath)) { fireStateChanged(); } @@ -167,7 +167,8 @@ public class ProjectArchive implements DomainFileArchive { } @Override - public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) { + public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, + DataTypePath newPath) { fireStateChanged(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEditorProvider.java index e82d4a6388..e9672e30ac 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEditorProvider.java @@ -19,7 +19,7 @@ import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -31,6 +31,8 @@ import docking.ActionContext; import docking.ComponentProvider; import docking.action.*; import docking.widgets.OptionDialog; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.compositeeditor.EditorListener; import ghidra.app.plugin.core.compositeeditor.EditorProvider; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; @@ -45,7 +47,6 @@ import ghidra.util.*; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import ghidra.util.exception.DuplicateNameException; -import resources.ResourceManager; import util.CollectionUtils; /** @@ -54,11 +55,10 @@ import util.CollectionUtils; public class EnumEditorProvider extends ComponentProviderAdapter implements ChangeListener, EditorProvider { - static final ImageIcon EDITOR_ICON = ResourceManager.loadImage("images/enum.png"); - private final static ImageIcon APPLY_ICON = ResourceManager.loadImage("images/disk.png"); - private final static ImageIcon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private final static ImageIcon DELETE_ICON = - ResourceManager.loadImage("images/edit-delete.png"); + static final Icon EDITOR_ICON = new GIcon("icon.plugin.enum.editor.provider"); + private final static Icon APPLY_ICON = new GIcon("icon.plugin.enum.editor.apply"); + private final static Icon ADD_ICON = new GIcon("icon.plugin.enum.editor.add"); + private final static Icon DELETE_ICON = new GIcon("icon.plugin.enum.editor.delete"); private final static String HELP_TOPIC = "DataTypeEditors"; private final static int CANCEL = 0; @@ -302,7 +302,7 @@ public class EnumEditorProvider extends ComponentProviderAdapter showEnumAction.setEnabled(true); String thirdGroup = "FThirdGroup"; showEnumAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/go-home.png"), thirdGroup)); + new ToolBarData(new GIcon("icon.plugin.enum.editor.home"), thirdGroup)); tool.addLocalAction(this, applyAction); tool.addLocalAction(this, addAction); @@ -400,8 +400,9 @@ public class EnumEditorProvider extends ComponentProviderAdapter private int showOptionDialog(Enum editedEnoom, Set oldNameFields) { StringBuilder msg = new StringBuilder( - "If you save this Enum with the new value(s)" + - " listed below,
it will invalidate equates created with the old value(s).
"); + "If you save this Enum with the new value(s) listed below,
" + + " it will invalidate equates created with the old value(s).
"); msg.append("
    "); for (String field : oldNameFields) { String newVal; @@ -412,13 +413,16 @@ public class EnumEditorProvider extends ComponentProviderAdapter // Happens if a field is deleted or there is a name AND value change. newVal = "Missing"; } - msg.append(String.format("
  • %s: 0x%s \u2192 %s
  • ", + msg.append(String.format( + "
  • %s: 0x%s \u2192 %s
  • ", HTMLUtilities.escapeHTML(field), Long.toHexString(originalEnum.getValue(field)), newVal)); } msg.append("
"); msg.append( - "Invalidated equates can be automatically removed now or
managed later from the Equates Table window."); + "Invalidated equates can be automatically removed now or
managed later from the" + + " Equates Table window."); msg.append(""); int choice = OptionDialog.showOptionDialog(editorPanel, "Equate Conflicts", msg.toString(), "Save and remove", "Save", OptionDialog.ERROR_MESSAGE); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BackgroundIcon.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BackgroundIcon.java index 623bf08c0f..bc14480e9d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BackgroundIcon.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/BackgroundIcon.java @@ -19,10 +19,15 @@ import java.awt.*; import javax.swing.Icon; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; + class BackgroundIcon implements Icon { - private static Color VERSION_ICON_COLOR_DARK = new Color(0x82, 0x82, 0xff); - private static Color VERSION_ICON_COLOR_LIGHT = new Color(0x9f, 0x9f, 0xff); + private static Color VERSION_ICON_COLOR_LINE = new GColor("color.bg.tree.renderer.icon.line"); + private static Color VERSION_ICON_COLOR_LIGHT = new GColor("color.bg.tree.renderer.icon.fill"); + + private static Color ALPHA = Palette.NO_COLOR; private int width; private int height; @@ -49,14 +54,14 @@ class BackgroundIcon implements Icon { if (isVersioned) { g.setColor(VERSION_ICON_COLOR_LIGHT); g.fillRect(x + 1, y + 1, width - 2, height - 2); - g.setColor(VERSION_ICON_COLOR_DARK); + g.setColor(VERSION_ICON_COLOR_LINE); g.drawLine(x + 1, y, x + width - 2, y); g.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2); g.drawLine(x + 1, y + height - 1, x + width - 2, y + height - 1); g.drawLine(x, y + 1, x, y + height - 2); } else { - g.setColor(c.getBackground()); + g.setColor(ALPHA); g.fillRect(x, y, width, height); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java index 7e40136a78..0957e3e537 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java @@ -27,6 +27,7 @@ import javax.swing.tree.TreePath; import docking.widgets.tree.*; import docking.widgets.tree.internal.DefaultGTreeDataTransformer; import docking.widgets.tree.support.GTreeRenderer; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.*; import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler; import ghidra.app.plugin.core.datamgr.archive.FileArchive; @@ -39,16 +40,13 @@ import ghidra.program.model.listing.Program; import ghidra.util.UniversalID; import ghidra.util.task.TaskMonitor; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.TranslateIcon; public class DataTypeArchiveGTree extends GTree { - private static ImageIcon LOCAL_DELTA_ICON = - ResourceManager.loadImage("images/smallRightArrow.png"); - private static ImageIcon SOURCE_DELTA_ICON = - ResourceManager.loadImage("images/smallLeftArrow.png"); - private static ImageIcon CONFLICT_ICON = ResourceManager.loadImage("images/doubleArrow.png"); - private static ImageIcon MISSING_ICON = ResourceManager.loadImage("images/redQuestionMark.png"); + private static Icon LOCAL_DELTA_ICON = new GIcon("icon.plugin.datatypes.tree.change.local"); + private static Icon SOURCE_DELTA_ICON = new GIcon("icon.plugin.datatypes.tree.change.source"); + private static Icon CONFLICT_ICON = new GIcon("icon.plugin.datatypes.tree.conflict"); + private static Icon MISSING_ICON = new GIcon("icon.plugin.datatypes.tree.missing"); private DataTypeManagerPlugin plugin; private GTreeNode armedNode; @@ -335,7 +333,7 @@ public class DataTypeArchiveGTree extends GTree { // work around an issue on some platforms where the label is painting a color that // does not match the tree label.setBackground( - isSelected ? getBackgroundSelectionColor() : tree.getBackground()); + isSelected ? getBackgroundSelectionColor() : getBackgroundNonSelectionColor()); } MultiIcon multiIcon = new MultiIcon( @@ -362,7 +360,6 @@ public class DataTypeArchiveGTree extends GTree { } setIcon(multiIcon); - return label; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java index fdc506ec51..d795484be3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DomainFileArchiveNode.java @@ -16,27 +16,25 @@ package ghidra.app.plugin.core.datamgr.tree; import javax.swing.Icon; -import javax.swing.ImageIcon; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.archive.DomainFileArchive; import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainObject; import ghidra.program.model.listing.Program; import ghidra.util.HTMLUtilities; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.TranslateIcon; public class DomainFileArchiveNode extends ArchiveNode { - private static ImageIcon CHECKED_OUT_ICON = ResourceManager.loadImage("images/check.png"); - private static ImageIcon CHECKED_OUT_EXCLUSIVE_ICON = - ResourceManager.loadImage("images/checkex.png"); - private static ImageIcon HIJACKED_ICON = ResourceManager.loadImage("images/small_hijack.gif"); - private static ImageIcon READ_ONLY_ICON = - ResourceManager.loadImage("images/user-busy.png", 10, 10); - private static ImageIcon NOT_LATEST_CHECKED_OUT_ICON = - ResourceManager.loadImage("images/checkNotLatest.gif"); + //@formatter:off + private static Icon CHECKED_OUT_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out"); + private static Icon CHECKED_OUT_EXCLUSIVE_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out.exclusive"); + private static Icon HIJACKED_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.hijacked"); + private static Icon READ_ONLY_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.read.only"); + private static Icon NOT_LATEST_CHECKED_OUT_ICON = new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out.not.latest"); + //@formatter:on private boolean isChanged; private boolean isReadOnly; @@ -116,7 +114,7 @@ public class DomainFileArchiveNode extends ArchiveNode { @Override public Icon getIcon(boolean expanded) { - ImageIcon baseIcon = archive.getIcon(expanded); + Icon baseIcon = archive.getIcon(expanded); BackgroundIcon bgIcon = new BackgroundIcon(24, 16, isVersioned); MultiIcon multiIcon = new MultiIcon(bgIcon); multiIcon.addIcon(baseIcon); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java index 4d12f658f8..1eb46bc540 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/FileArchiveNode.java @@ -16,19 +16,18 @@ package ghidra.app.plugin.core.datamgr.tree; import javax.swing.Icon; -import javax.swing.ImageIcon; import generic.jar.ResourceFile; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.archive.FileArchive; import ghidra.util.HTMLUtilities; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.TranslateIcon; public class FileArchiveNode extends ArchiveNode { - private static ImageIcon CHECKED_OUT_EXCLUSIVE_ICON = - ResourceManager.loadImage("images/checkex.png"); + private static Icon CHECKED_OUT_EXCLUSIVE_ICON = + new GIcon("icon.plugin.datatypes.tree.node.archive.file.checked.out.exclusive"); FileArchive fileArchive; // casted reference for easy access @@ -42,7 +41,7 @@ public class FileArchiveNode extends ArchiveNode { BackgroundIcon bgIcon = new BackgroundIcon(24, 16, false); MultiIcon multiIcon = new MultiIcon(bgIcon); boolean hasWriteLock = fileArchive.hasWriteLock(); - ImageIcon baseIcon = fileArchive.getIcon(expanded); + Icon baseIcon = fileArchive.getIcon(expanded); multiIcon.addIcon(baseIcon); if (hasWriteLock) { multiIcon.addIcon(new TranslateIcon(CHECKED_OUT_EXCLUSIVE_ICON, 8, -4)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java index 6a80ab4935..2b7cfb779e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/ConflictDialog.java @@ -16,7 +16,8 @@ package ghidra.app.plugin.core.datamgr.util; import java.awt.BorderLayout; -import java.awt.event.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import javax.swing.*; @@ -24,8 +25,8 @@ import docking.DialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.label.GIconLabel; import docking.widgets.label.GLabel; +import generic.theme.GIcon; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * Dialog to get user input on how to handle data type conflicts. @@ -43,12 +44,12 @@ public class ConflictDialog extends DialogComponentProvider { private JButton applyToAllButton; private int selectedOption = RENAME; - private ImageIcon INFORM_ICON = ResourceManager.loadImage("images/warning.png"); + private Icon INFORM_ICON = new GIcon("icon.warning"); /** * Constructor * @param dtName data type name - * @param categoryName category path + * @param categoryPath category path * @param newDTName new name to resolve conflict */ public ConflictDialog(String dtName, String categoryPath, String newDTName) { @@ -58,27 +59,18 @@ public class ConflictDialog extends DialogComponentProvider { addOKButton(); applyToAllButton = new JButton("Apply to All"); - applyToAllButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - applyToAll = true; - close(); - } + applyToAllButton.addActionListener(e -> { + applyToAll = true; + close(); }); addButton(applyToAllButton); } - /* (non-Javadoc) - * @see ghidra.util.bean.GhidraDialog#okCallback() - */ @Override protected void okCallback() { close(); } - /* (non-Javadoc) - * @see ghidra.util.bean.GhidraDialog#cancelCallback() - */ @Override protected void cancelCallback() { close(); @@ -101,20 +93,17 @@ public class ConflictDialog extends DialogComponentProvider { mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - ItemListener listener = new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - Object source = e.getSource(); - if (source == replaceRB) { - selectedOption = REPLACE; - } - else if (source == useExistingRB) { - selectedOption = USE_EXISTING; - } - else { - selectedOption = RENAME; - } + ItemListener listener = e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + Object source = e.getSource(); + if (source == replaceRB) { + selectedOption = REPLACE; + } + else if (source == useExistingRB) { + selectedOption = USE_EXISTING; + } + else { + selectedOption = RENAME; } } }; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java index 69a6462812..f637ed089e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/util/DataTypeUtils.java @@ -20,8 +20,9 @@ import java.util.*; import java.util.List; import javax.swing.Icon; -import javax.swing.ImageIcon; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.app.services.DataTypeQueryService; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; @@ -37,28 +38,10 @@ public class DataTypeUtils { private static final char END_CHAR = '\uffff'; private static final char BEGIN_CHAR = '\u0000'; - private static Map highlightIconMap = new HashMap<>(); + private static final Color COLOR_ICON_HIGHLIGHT = + new GColor("color.bg.plugin.datamgr.icon.highlight"); - private static String OPEN_FOLDER = "images/openFolder.png"; - private static String CLOSED_FOLDER = "images/closedFolder.png"; - private static String DISABLED_OPEN_FOLDER = "images/disabledOpenFolder.png"; - private static String DISABLED_CLOSED_FOLDER = "images/disabledClosedFolder.png"; - private static String DEFAULT_ICON = "images/defaultDt.gif"; - private static String DISABLED_DEFAULT_ICON = "images/disabledCode.gif"; - private static String LOCKED_OPEN_FOLDER = "images/openFolderCheckedOut.png"; - private static String LOCKED_CLOSED_FOLDER = "images/closedFolderCheckedOut.png"; - private static String OPEN_ARCHIVE_FOLDER = "images/openFolderArchive.png"; - private static String CLOSED_ARCHIVE_FOLDER = "images/closedFolderArchive.png"; - private static String ROOT_ICON = "images/BookShelf.png"; - private static String OPEN_ROOT_ICON = "images/BookShelfOpen.png"; - private static String FAVORITE_ICON = "images/emblem-favorite.png"; - private static String BUILT_IN_ICON = "images/package_development.png"; - private static String STRUCTURE_ICON = "images/cstruct.png"; - private static String UNION_ICON = "images/cUnion.png"; - private static String TYPEDEF_ICON = "images/typedef.png"; - private static String FUNCTION_ICON = "images/functionDef.png"; - private static String ENUM_ICON = "images/enum.png"; - private static String POINTER_ICON = "images/fingerPointer.png"; + private static Map highlightIconMap = new HashMap<>(); private static Icon defaultIcon; private static Icon disabledIcon; @@ -89,29 +72,29 @@ public class DataTypeUtils { return; } imagesLoaded = true; - defaultIcon = ResourceManager.loadImage(DEFAULT_ICON); - disabledIcon = ResourceManager.loadImage(DISABLED_DEFAULT_ICON); + defaultIcon = new GIcon("icon.plugin.datatypes.default"); + disabledIcon = new GIcon("icon.plugin.datatypes.default.disabled"); - favoriteIcon = ResourceManager.loadImage(FAVORITE_ICON); - disabledFavoriteIcon = ResourceManager.getDisabledIcon((ImageIcon) favoriteIcon); + favoriteIcon = new GIcon("icon.plugin.datatypes.util.favorite"); + disabledFavoriteIcon = new GIcon("icon.plugin.datatypes.util.favorite.disabled"); - builtInIcon = ResourceManager.loadImage(BUILT_IN_ICON); - disabledBuiltInIcon = ResourceManager.getDisabledIcon((ImageIcon) builtInIcon); + builtInIcon = new GIcon("icon.plugin.datatypes.built.in"); + disabledBuiltInIcon = new GIcon("icon.plugin.datatypes.built.in.disabled"); - rootIcon = ResourceManager.loadImage(ROOT_ICON); - openRootIcon = ResourceManager.loadImage(OPEN_ROOT_ICON); + rootIcon = new GIcon("icon.plugin.datatypes.util.root"); + openRootIcon = new GIcon("icon.plugin.datatypes.util.open.root"); - openFolderIcon = ResourceManager.loadImage(OPEN_FOLDER); - disabledOpenFolderIcon = ResourceManager.loadImage(DISABLED_OPEN_FOLDER); + openFolderIcon = new GIcon("icon.plugin.datatypes.util.open.folder"); + disabledOpenFolderIcon = new GIcon("icon.plugin.datatypes.util.open.folder.disabled"); - closedFolderIcon = ResourceManager.loadImage(CLOSED_FOLDER); - disabledClosedFolderIcon = ResourceManager.loadImage(DISABLED_CLOSED_FOLDER); + closedFolderIcon = new GIcon("icon.plugin.datatypes.util.closed.folder"); + disabledClosedFolderIcon = new GIcon("icon.plugin.datatypes.util.closed.folder.disabled"); - lockedOpenFolderIcon = ResourceManager.loadImage(LOCKED_OPEN_FOLDER); - lockedClosedFolderIcon = ResourceManager.loadImage(LOCKED_CLOSED_FOLDER); + lockedOpenFolderIcon = new GIcon("icon.plugin.datatypes.util.open.folder.locked"); + lockedClosedFolderIcon = new GIcon("icon.plugin.datatypes.util.closed.folder.locked"); - openArchiveFolderIcon = ResourceManager.loadImage(OPEN_ARCHIVE_FOLDER); - closedArchiveFolderIcon = ResourceManager.loadImage(CLOSED_ARCHIVE_FOLDER); + openArchiveFolderIcon = new GIcon("icon.plugin.datatypes.util.open.archive"); + closedArchiveFolderIcon = new GIcon("icon.plugin.datatypes.util.closed.archive"); createDataTypeIcons(); @@ -120,29 +103,29 @@ public class DataTypeUtils { private static void createDataTypeIcons() { List list = new ArrayList<>(); - Icon enumIcon = ResourceManager.loadImage(ENUM_ICON); + Icon enumIcon = new GIcon("icon.plugin.datatypes.enum"); list.add(new DataTypeIconWrapper(Enum.class, enumIcon, - ResourceManager.getDisabledIcon((ImageIcon) enumIcon))); + ResourceManager.getDisabledIcon(enumIcon))); - Icon functionIcon = ResourceManager.loadImage(FUNCTION_ICON); + Icon functionIcon = new GIcon("icon.plugin.datatypes.function"); list.add(new DataTypeIconWrapper(FunctionDefinition.class, functionIcon, - ResourceManager.getDisabledIcon((ImageIcon) functionIcon))); + ResourceManager.getDisabledIcon(functionIcon))); - Icon pointerIcon = ResourceManager.loadImage(POINTER_ICON); + Icon pointerIcon = new GIcon("icon.plugin.datatypes.pointer"); list.add(new DataTypeIconWrapper(Pointer.class, pointerIcon, - ResourceManager.getDisabledIcon((ImageIcon) pointerIcon))); + ResourceManager.getDisabledIcon(pointerIcon))); - Icon typedefIcon = ResourceManager.loadImage(TYPEDEF_ICON); + Icon typedefIcon = new GIcon("icon.plugin.datatypes.typedef"); list.add(new DataTypeIconWrapper(TypeDef.class, typedefIcon, - ResourceManager.getDisabledIcon((ImageIcon) typedefIcon))); + ResourceManager.getDisabledIcon(typedefIcon))); - Icon unionIcon = ResourceManager.loadImage(UNION_ICON); + Icon unionIcon = new GIcon("icon.plugin.datatypes.union"); list.add(new DataTypeIconWrapper(Union.class, unionIcon, - ResourceManager.getDisabledIcon((ImageIcon) unionIcon))); + ResourceManager.getDisabledIcon(unionIcon))); - Icon structureIcon = ResourceManager.loadImage(STRUCTURE_ICON); + Icon structureIcon = new GIcon("icon.plugin.datatypes.structure"); list.add(new DataTypeIconWrapper(Structure.class, structureIcon, - ResourceManager.getDisabledIcon((ImageIcon) structureIcon))); + ResourceManager.getDisabledIcon(structureIcon))); dataTypeIconWrappers = list.toArray(new DataTypeIconWrapper[list.size()]); } @@ -281,7 +264,7 @@ public class DataTypeUtils { MultiIcon highlightIcon = highlightIconMap.get(baseIcon); if (highlightIcon == null) { - highlightIcon = new MultiIcon(new HighlightIcon(new Color(204, 204, 255))); + highlightIcon = new MultiIcon(new HighlightIcon(COLOR_ICON_HIGHLIGHT)); highlightIcon.addIcon(baseIcon); highlightIconMap.put(baseIcon, highlightIcon); } @@ -461,7 +444,6 @@ public class DataTypeUtils { } Msg.showInfo(DataTypeUtils.class, parent, title, msg); } - } //================================================================================================== @@ -533,45 +515,3 @@ class HighlightIcon implements Icon { g.drawRect(x, y, WIDTH + 1, HEIGHT - 1); } } - -class VersionIcon implements Icon { - - private static Color VERSION_ICON_COLOR_DARK = new Color(0x82, 0x82, 0xff); - private static Color VERSION_ICON_COLOR_LIGHT = new Color(0x9f, 0x9f, 0xff); - - private static final int WIDTH = 18; - private static final int HEIGHT = 17; - - int width; - int height; - - VersionIcon() { - this(WIDTH, HEIGHT); - } - - VersionIcon(int width, int height) { - this.width = width; - this.height = height; - } - - @Override - public int getIconHeight() { - return height; - } - - @Override - public int getIconWidth() { - return width; - } - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - g.setColor(VERSION_ICON_COLOR_LIGHT); - g.fillRect(x + 1, y + 1, width - 2, height - 2); - g.setColor(VERSION_ICON_COLOR_DARK); - g.drawLine(x + 1, y, x + width - 2, y); - g.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2); - g.drawLine(x + 1, y + height - 1, x + width - 2, y + height - 1); - g.drawLine(x, y + 1, x, y + height - 2); - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java index 4bee7cfac9..df59a8d79e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java @@ -48,7 +48,7 @@ import ghidra.util.data.DataTypeParser.AllowedDataTypes; import ghidra.util.table.GhidraTable; import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; +import resources.Icons; import util.CollectionUtils; //@formatter:off @@ -301,7 +301,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin { } }; addAction.setPopupMenuData(new MenuData(new String[] { "Add" })); - addAction.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/Plus.png"))); + addAction.setToolBarData(new ToolBarData(Icons.ADD_ICON)); addAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_PLUS, 0)); addAction.setDescription("Add Datatypes"); @@ -316,8 +316,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin { } }; deleteAction.setPopupMenuData(new MenuData(new String[] { "Delete" })); - deleteAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/edit-delete.png"))); + deleteAction.setToolBarData(new ToolBarData(Icons.DELETE_ICON)); deleteAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_DELETE, 0)); deleteAction.setDescription("Delete Selected Datatypes"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java index 2569ea574d..c909a3934a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java @@ -23,6 +23,7 @@ import javax.swing.*; import javax.swing.table.JTableHeader; import docking.ActionContext; +import generic.theme.GIcon; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.program.model.address.Address; @@ -30,14 +31,13 @@ import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; import ghidra.util.table.*; -import resources.ResourceManager; /** * Provider for the equates table. */ class DataWindowProvider extends ComponentProviderAdapter { - public static final ImageIcon ICON = ResourceManager.loadImage("images/dataW.gif"); + public static final Icon ICON = new GIcon("icon.plugin.datawindow.provider"); private DataWindowPlugin plugin; @@ -93,7 +93,9 @@ class DataWindowProvider extends ComponentProviderAdapter { } void programClosed() { - dataModel.reload(null); + if (isVisible()) { + dataModel.reload(null); + } } void dispose() { @@ -156,10 +158,14 @@ class DataWindowProvider extends ComponentProviderAdapter { } private void setDataTableRenderer() { - dataTable.getColumnModel().getColumn(DataTableModel.LOCATION_COL).setPreferredWidth( - DataTableModel.ADDRESS_COL_WIDTH); - dataTable.getColumnModel().getColumn(DataTableModel.SIZE_COL).setPreferredWidth( - DataTableModel.SIZE_COL_WIDTH); + dataTable.getColumnModel() + .getColumn(DataTableModel.LOCATION_COL) + .setPreferredWidth( + DataTableModel.ADDRESS_COL_WIDTH); + dataTable.getColumnModel() + .getColumn(DataTableModel.SIZE_COL) + .setPreferredWidth( + DataTableModel.SIZE_COL_WIDTH); } void reload() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java index bbe236ccdb..64c2d52027 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/FilterAction.java @@ -34,6 +34,7 @@ import docking.widgets.combobox.GhidraComboBox; import docking.widgets.filter.FilterListener; import docking.widgets.filter.FilterTextField; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors; import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import ghidra.util.task.SwingUpdateManager; @@ -133,8 +134,8 @@ class FilterAction extends ToggleDockingAction { } synchronized void selectTypes(ArrayList list) { - for (int i = 0; i < list.size(); i++) { - typeEnabledMap.put(list.get(i), Boolean.TRUE); + for (String element : list) { + typeEnabledMap.put(element, Boolean.TRUE); } if (dialog != null) { dialog.selectTypes(list); @@ -222,15 +223,13 @@ class FilterAction extends ToggleDockingAction { } void selectTypes(ArrayList list) { - for (int i = 0; i < list.size(); i++) { - String type = list.get(i); + for (String type : list) { selectCheckBox(type); } } private void selectCheckBox(String typeName) { - for (int i = 0; i < checkboxes.size(); i++) { - JCheckBox cb = checkboxes.get(i); + for (JCheckBox cb : checkboxes) { if (cb.getText().equals(typeName)) { cb.setSelected(true); return; @@ -302,7 +301,7 @@ class FilterAction extends ToggleDockingAction { typeButtonPanel.add(selectNoneButton); checkboxPanel = new JPanel(); - checkboxPanel.setBackground(Color.WHITE); + checkboxPanel.setBackground(Colors.BACKGROUND); checkboxPanel.setLayout(new BoxLayout(checkboxPanel, BoxLayout.Y_AXIS)); buildCheckBoxList(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java index 81eef78479..b8eaf1cd15 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java @@ -24,6 +24,7 @@ import javax.swing.event.ChangeListener; import docking.WindowPosition; import docking.widgets.list.GListCellRenderer; +import generic.theme.Gui; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; @@ -449,8 +450,8 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec Color background = selectedAddressColor; if (isSelected) { - foreground = foreground.brighter(); - background = background.darker(); + foreground = Gui.brighter(foreground); + background = Gui.darker(background); } setForeground(foreground); @@ -490,7 +491,7 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec OptionsGui.BACKGROUND.getDefaultColor()); // font - font = opt.getFont(ADDRESS_FONT_OPTION, FieldFactory.DEFAULT_FIELD_FONT); + font = Gui.getFont(FieldFactory.BASE_LISTING_FONT_ID); contentList.setForeground(addressForegroundColor); contentList.setBackground(backgroundColor); @@ -509,22 +510,6 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec opt.removeOptionsChangeListener(optionsChangeListener); } - /** - * Adds the given listener to be notified when the user selects list - * items in the view. - * - * @param listener The listener to add. - */ -// void addListSelectionListener( ListSelectionListener listener ) -// { -// contentList.addListSelectionListener( listener ); -// } - - /** - * Sets the contents to the provided value. - * - * @param displayContents The value that the view should display. - */ void setContents(DisassembledAddressInfo[] addressInfos) { contentList.setListData(addressInfos); } @@ -595,7 +580,7 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec contentList.setBackground(backgroundColor); } else if (optionName.equals(ADDRESS_FONT_OPTION)) { - font = (Font) newValue; + font = Gui.getFont(FieldFactory.BASE_LISTING_FONT_ID); } } @@ -606,9 +591,8 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec } /** - * An object that provides information about the address that it wraps. - * The info knows how to locate a {@link CodeInfo} object for the address - * and can generate a string preview of the address. + * An object that provides information about the address that it wraps. The info knows how to + * locate an info object for the address and can generate a string preview of the address. */ private class DisassembledAddressInfo { /** @@ -683,8 +667,8 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec /** * Get the code unit from the program location. * - * @param The address from which we want the CodeUnit. - * @return CodeUnit null if there is no location. + * @param address the address from which we want the CodeUnit. + * @return null if there is no location. */ private CodeUnit getCodeUnitForAddress(Address address) { CodeUnit codeUnit = null; @@ -693,8 +677,8 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec Listing listing = currentProgram.getListing(); codeUnit = listing.getCodeUnitAt(address); - // if the CodeUnit is Data and is not defined, then we - // need to try to virutally disassemble it + // if the CodeUnit is Data and is not defined, then we need to try to virtually + // disassemble it if (codeUnit instanceof Data) { if (!((Data) codeUnit).isDefined()) { CodeUnit virtualCodeUnit = virtuallyDisassembleAddress(address); @@ -727,18 +711,15 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec codeUnit = disassembler.disassemble(address); } catch (UsrException ue) { - // these exceptions happen if there is insufficient data - // from the program: InsufficientBytesException, - // UnknownInstructionException, UnknownContextException + // these exceptions happen if there is insufficient data from the program: + // InsufficientBytesException, UnknownInstructionException, + // UnknownContextException } } return codeUnit; } - /** - * Gets the preview String for the provided code unit. - */ public String getAddressPreview(CodeUnitFormat format) { return getAddress().toString() + " " + format.getRepresentationString(addressCodeUnit); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java index 39c204ae3e..28597cca52 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/editor/TextEditorComponentProvider.java @@ -19,8 +19,6 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.event.KeyEvent; import java.io.*; -import java.util.Iterator; -import java.util.List; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -32,36 +30,21 @@ import docking.ActionContext; import docking.ComponentProvider; import docking.action.*; import docking.actions.KeyBindingUtils; -import docking.options.editor.FontPropertyEditor; +import docking.options.editor.FontEditor; import docking.widgets.OptionDialog; import docking.widgets.filechooser.GhidraFileChooser; -import ghidra.framework.options.SaveState; +import generic.theme.*; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.datastruct.FixedSizeStack; -import resources.ResourceManager; +import resources.Icons; public class TextEditorComponentProvider extends ComponentProviderAdapter { private static final String TITLE = "Text Editor"; - + private static final String FONT_ID = "font.plugin.service.text.editor"; private static final int MAX_UNDO_REDO_SIZE = 50; - static Font defaultFont = new Font("monospaced", Font.PLAIN, 12); - - static void restoreState(SaveState saveState) { - String name = saveState.getString("DEFAULT_FONT_NAME", "Monospaced"); - int style = saveState.getInt("DEFAULT_FONT_STYLE", Font.PLAIN); - int size = saveState.getInt("DEFAULT_FONT_SIZE", 12); - defaultFont = new Font(name, style, size); - } - - static void saveState(SaveState saveState) { - saveState.putString("DEFAULT_FONT_NAME", defaultFont.getName()); - saveState.putInt("DEFAULT_FONT_STYLE", defaultFont.getStyle()); - saveState.putInt("DEFAULT_FONT_SIZE", defaultFont.getSize()); - } - private TextEditorManagerPlugin plugin; private GhidraFileChooser chooser; private File textFile; @@ -200,7 +183,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { }; undoAction.setDescription("Undo"); undoAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/undo.png"), "UndoRedo")); + new ToolBarData(new GIcon("icon.undo"), "UndoRedo")); undoAction.setEnabled(false); plugin.getTool().addLocalAction(this, undoAction); @@ -218,7 +201,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { }; redoAction.setDescription("Redo"); redoAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/redo.png"), "UndoRedo")); + new ToolBarData(new GIcon("icon.redo"), "UndoRedo")); redoAction.setEnabled(false); plugin.getTool().addLocalAction(this, redoAction); @@ -236,7 +219,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { }; saveAction.setDescription("Save"); saveAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/disk.png"), "Save")); + new ToolBarData(Icons.SAVE_ICON, "Save")); saveAction.setEnabled(false); plugin.getTool().addLocalAction(this, saveAction); @@ -254,7 +237,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { }; saveAsAction.setDescription("Save As..."); saveAsAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/disk_save_as.png"), "Save")); + new ToolBarData(Icons.SAVE_AS_ICON, "Save")); saveAsAction.setEnabled(true); plugin.getTool().addLocalAction(this, saveAsAction); @@ -265,7 +248,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { } }; fontAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/text_lowercase.png"), "ZZFont")); + new ToolBarData(new GIcon("icon.font"), "ZZFont")); fontAction.setDescription("Select Font"); fontAction.setEnabled(true); plugin.getTool().addLocalAction(this, fontAction); @@ -287,17 +270,10 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { } protected void doSelectFont() { - FontPropertyEditor editor = new FontPropertyEditor(); - editor.setValue(defaultFont); + FontEditor editor = new FontEditor(); + editor.setValue(Gui.getFont(FONT_ID)); editor.showDialog(); - defaultFont = (Font) editor.getValue(); - - List values = plugin.getEditors(); - Iterator iterator = values.iterator(); - while (iterator.hasNext()) { - TextEditorComponentProvider editorComponent = iterator.next(); - editorComponent.textarea.setFont(defaultFont); - } + ThemeManager.getInstance().setFont(FONT_ID, (Font) editor.getValue()); } private void save() { @@ -390,8 +366,7 @@ public class TextEditorComponentProvider extends ComponentProviderAdapter { private KeyMasterTextArea(String text) { super(text); - - setFont(defaultFont); + Gui.registerFont(this, FONT_ID); setName("EDITOR"); setWrapStyleWord(false); Document document = getDocument(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableModel.java index 7da1cab34f..95fc54972a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableModel.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,8 +21,11 @@ import java.util.ArrayList; import java.util.List; import javax.swing.JLabel; +import javax.swing.JTable; import docking.widgets.table.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.app.util.ToolTipUtils; import ghidra.docking.settings.FormatSettingsDefinition; import ghidra.docking.settings.Settings; @@ -40,6 +43,8 @@ import util.CollectionUtils; class EquateTableModel extends GDynamicColumnTableModel { + private static final Color FG_ENUM_BASED = new GColor("color.fg.plugin.equate.enum"); + private EquateTablePlugin plugin; private List equateList = new ArrayList<>(); @@ -149,10 +154,14 @@ class EquateTableModel extends GDynamicColumnTableModel { return label; } + JTable table = data.getTable(); if (!eq.isValidUUID()) { // Error equate - label.setForeground((isSelected) ? Color.WHITE : Color.RED); - } else if (!eq.isEnumBased()) { // User label - label.setForeground((isSelected) ? Color.WHITE : Color.BLUE.brighter()); + label.setForeground( + (isSelected) ? table.getSelectionForeground() : Tables.FG_ERROR_UNSELECTED); + } + else if (!eq.isEnumBased()) { // User label + label.setForeground( + (isSelected) ? table.getSelectionForeground() : FG_ENUM_BASED); } String tooltip = getEquateToolTip(eq); @@ -192,7 +201,7 @@ class EquateTableModel extends GDynamicColumnTableModel { @Override public String getValue(Equate rowObject, Settings settings, Object data, - ServiceProvider serviceProvider) throws IllegalArgumentException { + ServiceProvider sp) throws IllegalArgumentException { return rowObject.getDisplayName(); } @@ -243,7 +252,7 @@ class EquateTableModel extends GDynamicColumnTableModel { @Override public Long getValue(Equate rowObject, Settings settings, Object data, - ServiceProvider serviceProvider) throws IllegalArgumentException { + ServiceProvider sp) throws IllegalArgumentException { FormatSettingsDefinition formatDef = FormatSettingsDefinition.DEF; @@ -263,7 +272,7 @@ class EquateTableModel extends GDynamicColumnTableModel { } private class EquateReferenceCountColumn - extends AbstractDynamicTableColumn { + extends AbstractDynamicTableColumn { public static final String NAME = "# Refs"; @@ -274,14 +283,14 @@ class EquateTableModel extends GDynamicColumnTableModel { @Override public Integer getValue(Equate rowObject, Settings settings, Object data, - ServiceProvider serviceProvider) throws IllegalArgumentException { + ServiceProvider sp) throws IllegalArgumentException { return rowObject.getReferenceCount(); } } private class IsEnumBasedEquateColumn - extends AbstractDynamicTableColumn { + extends AbstractDynamicTableColumn { public static final String NAME = "Is Enum-Based"; @@ -292,7 +301,7 @@ class EquateTableModel extends GDynamicColumnTableModel { @Override public Boolean getValue(Equate rowObject, Settings settings, Object data, - ServiceProvider serviceProvider) throws IllegalArgumentException { + ServiceProvider sp) throws IllegalArgumentException { return rowObject.isEnumBased(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java index 793a3bd759..56f30a71fe 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java @@ -40,12 +40,10 @@ import ghidra.program.model.symbol.Equate; import ghidra.util.HelpLocation; import ghidra.util.UniversalID; import ghidra.util.table.*; -import resources.ResourceManager; +import resources.Icons; public class EquateTableProvider extends ComponentProviderAdapter { - private final static String DELETE_IMAGE = "images/edit-delete.png"; - private EquateTablePlugin plugin; private GhidraTable equatesTable; private EquateTableModel equatesModel; @@ -160,8 +158,8 @@ public class EquateTableProvider extends ComponentProviderAdapter { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN || - e.getKeyCode() == KeyEvent.VK_PAGE_UP || - e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) { + e.getKeyCode() == KeyEvent.VK_PAGE_UP || + e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) { handleEquateTableSelection(); } } @@ -191,7 +189,7 @@ public class EquateTableProvider extends ComponentProviderAdapter { Equate equate = (Equate) table.getValueAt(row, column); UniversalID id = - new UniversalID(Long.parseLong(equate.getName().split(":")[1])); + new UniversalID(Long.parseLong(equate.getName().split(":")[1])); Enum enoom = (Enum) dtm.findDataTypeForID(id); if (enoom != null) { dtms.edit(enoom); @@ -254,7 +252,7 @@ public class EquateTableProvider extends ComponentProviderAdapter { JPanel workPanel = new JPanel(new BorderLayout()); JSplitPane splitPane = - new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, equatesPanel, referencesPanel); + new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, equatesPanel, referencesPanel); splitPane.setResizeWeight(0.5); workPanel.add(splitPane, BorderLayout.CENTER); @@ -269,7 +267,7 @@ public class EquateTableProvider extends ComponentProviderAdapter { private void createAction() { - ImageIcon deleteImage = ResourceManager.loadImage(DELETE_IMAGE); + Icon deleteImage = Icons.DELETE_ICON; deleteAction = new DockingAction("Delete Equate", plugin.getName()) { @Override public void actionPerformed(ActionContext context) { @@ -291,7 +289,7 @@ public class EquateTableProvider extends ComponentProviderAdapter { deleteAction.setHelpLocation(new HelpLocation("EquatePlugin", "Delete Equate")); SelectionNavigationAction selectionNavigationAction = - new SelectionNavigationAction(plugin, referencesTable); + new SelectionNavigationAction(plugin, referencesTable); selectionNavigationAction.setHelpLocation( new HelpLocation(HelpTopics.SEARCH, "Selection_Navigation")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/fallthrough/FallThroughDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/fallthrough/FallThroughDialog.java index 74d62df7c1..3d58ff0476 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/fallthrough/FallThroughDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/fallthrough/FallThroughDialog.java @@ -16,9 +16,6 @@ package ghidra.app.plugin.core.fallthrough; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.net.URL; import javax.swing.*; import javax.swing.border.TitledBorder; @@ -28,17 +25,14 @@ import javax.swing.event.ChangeListener; import docking.DialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.label.GDLabel; +import generic.theme.Gui; import ghidra.app.util.AddressInput; import ghidra.program.model.address.Address; import ghidra.util.HelpLocation; -import resources.ResourceManager; +import resources.Icons; /** - * Dialog to prompt for overriding a fallthrough address on an - * instruction. - * - * - * + * Dialog to prompt for overriding a fallthrough address on an instruction. */ class FallThroughDialog extends DialogComponentProvider implements ChangeListener { @@ -65,25 +59,16 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene model.setChangeListener(this); } - /** - * @see ghidra.util.bean.GhidraDialog#applyCallback() - */ @Override protected void applyCallback() { model.execute(); } - /** - * @see ghidra.util.bean.GhidraDialog#cancelCallback() - */ @Override protected void cancelCallback() { close(); } - /** - * @see ghidra.util.bean.GhidraDialog#okCallback() - */ @Override protected void okCallback() { if (model.execute()) { @@ -91,9 +76,6 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene } } - /** - * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) - */ public void updateState() { Address addr = model.getAddress(); if (addr == null) { @@ -140,18 +122,15 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene return; } - Runnable r = new Runnable() { - @Override - public void run() { - Address addr = addrField.getAddress(); - if (addr != null || addrField.getValue().length() == 0) { - model.setCurrentFallthrough(addr); - } - else { - setStatusText("Invalid Address"); - setOkEnabled(false); - setApplyEnabled(false); - } + Runnable r = () -> { + Address addr = addrField.getAddress(); + if (addr != null || addrField.getValue().length() == 0) { + model.setCurrentFallthrough(addr); + } + else { + setStatusText("Invalid Address"); + setOkEnabled(false); + setApplyEnabled(false); } }; SwingUtilities.invokeLater(r); @@ -162,18 +141,8 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene panel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); addrField = new AddressInput(); addrField.setAddressFactory(model.getProgram().getAddressFactory()); - addrField.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - addressChanged(); - } - }); - addrField.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - model.setCurrentFallthrough(addrField.getAddress()); - } - }); + addrField.addChangeListener(e -> addressChanged()); + addrField.addActionListener(e -> model.setCurrentFallthrough(addrField.getAddress())); panel.add(createHomePanel(), BorderLayout.NORTH); panel.add(createAddressPanel(), BorderLayout.CENTER); return panel; @@ -194,20 +163,14 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene addressLabel = new GDLabel("01001000"); - Font font = addressLabel.getFont(); - Font monoFont = new Font("monospaced", font.getStyle(), font.getSize()); + Font monoFont = Gui.getFont("font.monospaced"); addressLabel.setFont(monoFont); instLabel = new GDLabel("jmp DAT_01001000"); instLabel.setFont(monoFont); - homeButton = createButton("images/go-home.png", "Home"); - homeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - plugin.goTo(model.getAddress()); - } - }); + homeButton = createButton("Home"); + homeButton.addActionListener(e -> plugin.goTo(model.getAddress())); JPanel innerPanel = new JPanel(); BoxLayout bl = new BoxLayout(innerPanel, BoxLayout.X_AXIS); @@ -232,21 +195,11 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene ButtonGroup group = new ButtonGroup(); defaultRB = new GRadioButton("Default", true); - defaultRB.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ev) { - model.defaultSelected(); - } - }); + defaultRB.addActionListener(ev -> model.defaultSelected()); defaultRB.setToolTipText("Use default fallthrough address"); userRB = new GRadioButton("User", false); - userRB.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ev) { - model.userSelected(); - } - }); + userRB.addActionListener(ev -> model.userSelected()); userRB.setToolTipText("Override default fallthrough address"); group.add(defaultRB); @@ -260,18 +213,13 @@ class FallThroughDialog extends DialogComponentProvider implements ChangeListene return outerPanel; } - private JButton createButton(String filename, String altText) { + private JButton createButton(String altText) { JButton button = new JButton(); - URL imageURL = ResourceManager.getResource(filename); - if (imageURL != null) { - ImageIcon icon = new ImageIcon(imageURL); - button = new JButton(icon); - Insets noInsets = new Insets(0, 0, 0, 0); - button.setMargin(noInsets); - } - else { - button = new JButton(altText); - } + Icon icon = Icons.HOME_ICON; + button = new JButton(icon); + Insets noInsets = new Insets(0, 0, 0, 0); + button.setMargin(noInsets); + button.setToolTipText("Go back to home address"); return button; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java index 4a87ad48e8..e99c3ddf73 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java @@ -642,14 +642,14 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh private void getOptions() { ToolOptions opt = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); - opt.registerOption(OptionsGui.FLOW_ARROW_NON_ACTIVE.getColorOptionName(), - OptionsGui.FLOW_ARROW_NON_ACTIVE.getDefaultColor(), null, + opt.registerThemeColorBinding(OptionsGui.FLOW_ARROW_NON_ACTIVE.getColorOptionName(), + OptionsGui.FLOW_ARROW_NON_ACTIVE.getThemeColorId(), null, "The color for an arrow with no endpoint at the current address"); - opt.registerOption(OptionsGui.FLOW_ARROW_ACTIVE.getColorOptionName(), - OptionsGui.FLOW_ARROW_ACTIVE.getDefaultColor(), null, + opt.registerThemeColorBinding(OptionsGui.FLOW_ARROW_ACTIVE.getColorOptionName(), + OptionsGui.FLOW_ARROW_ACTIVE.getThemeColorId(), null, "The color for an arrow with an endpoint at the current address"); - opt.registerOption(OptionsGui.FLOW_ARROW_SELECTED.getColorOptionName(), - OptionsGui.FLOW_ARROW_SELECTED.getDefaultColor(), null, + opt.registerThemeColorBinding(OptionsGui.FLOW_ARROW_SELECTED.getColorOptionName(), + OptionsGui.FLOW_ARROW_SELECTED.getThemeColorId(), null, "The color for an arrow that has been selected by the user"); Color c = opt.getColor(OptionsGui.BACKGROUND.getColorOptionName(), diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java index a55b564afd..05d80a593b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackDepthFieldFactory.java @@ -15,11 +15,12 @@ */ package ghidra.app.plugin.core.function; -import java.awt.Color; import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.cmd.function.CallDepthChangeInfo; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.field.*; @@ -39,12 +40,8 @@ public class StackDepthFieldFactory extends FieldFactory { private CallDepthChangeInfo depth = null; private long lastModNumber = -1; - /** - * - */ public StackDepthFieldFactory() { super(FIELD_NAME); - // TODO Auto-generated constructor stub } private StackDepthFieldFactory(FieldFormatModel model, HighlightProvider hsProvider, @@ -57,14 +54,11 @@ public class StackDepthFieldFactory extends FieldFactory { @Override public FieldFactory newInstance(FieldFormatModel newModel, HighlightProvider highlightProvider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new StackDepthFieldFactory(newModel, highlightProvider, displayOptions, + ToolOptions toolDisplayOptions, ToolOptions fieldOptions) { + return new StackDepthFieldFactory(newModel, highlightProvider, toolDisplayOptions, fieldOptions); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getField(ProxyObj, int) - */ @Override public ListingField getField(ProxyObj proxy, int varWidth) { Object obj = proxy.getObject(); @@ -94,14 +88,14 @@ public class StackDepthFieldFactory extends FieldFactory { // This can be used to display the value of any register symbolically flowing over the program. // depthString = depth.getRegValueRepresentation(cu.getMinAddress(), cu.getProgram().getRegister("ESP")); - AttributedString as = new AttributedString(depthString, Color.BLUE, getMetrics()); + AttributedString as = new AttributedString(depthString, Palette.BLUE, getMetrics()); Integer overrideDepth = CallDepthChangeInfo.getStackDepthChange(cu.getProgram(), cu.getMinAddress()); if (overrideDepth != null) { String grows = (func.getStackFrame().growsNegative() ? " - " : " + "); depthString = depthString + grows + Integer.toString(overrideDepth, 16); - as = new AttributedString(depthString, Color.RED, getMetrics()); + as = new AttributedString(depthString, Colors.ERROR, getMetrics()); } FieldElement text = new TextFieldElement(as, 0, 0); @@ -109,15 +103,11 @@ public class StackDepthFieldFactory extends FieldFactory { width, hlProvider); } - /** - * @param depthChange - * @return - */ private String getDepthString(int depthChange, boolean isInDelaySlot) { if (isInDelaySlot) { - return ""; // if in delayslot, stack changes will be on main instruction + return ""; // if in delay slot, stack changes will be on main instruction } - + String stringDepth = "- ? -"; if (depthChange != Function.UNKNOWN_STACK_DEPTH_CHANGE && @@ -134,7 +124,7 @@ public class StackDepthFieldFactory extends FieldFactory { stringDepth = filler.substring(len) + stringDepth; } } - + return stringDepth; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java index 79e622a132..1f70f889e4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java @@ -35,6 +35,10 @@ import docking.widgets.checkbox.GCheckBox; import docking.widgets.combobox.GComboBox; import docking.widgets.label.GLabel; import docking.widgets.table.*; +import generic.theme.GColor; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.*; import generic.util.WindowUtilities; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.ToolTipUtils; @@ -47,13 +51,12 @@ import ghidra.program.model.symbol.ExternalLocation; import ghidra.util.*; import ghidra.util.layout.PairLayout; import ghidra.util.layout.VerticalLayout; -import resources.ResourceManager; +import resources.Icons; public class FunctionEditorDialog extends DialogComponentProvider implements ModelChangeListener { - private static Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static Icon REMOVE_ICON = ResourceManager.loadImage("images/edit-delete.png"); - private static Icon UP_ICON = ResourceManager.loadImage("images/up.png"); - private static Icon DOWN_ICON = ResourceManager.loadImage("images/down.png"); + private static final Color FG_COLOR_THUNK = + new GColor("color.fg.plugin.function.editor.dialog.thunk"); + private FunctionEditorModel model; private DocumentListener nameFieldDocumentListener; private GTable parameterTable; @@ -209,10 +212,10 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod thunkedText.setEditable(false); DockingUtils.setTransparent(thunkedText); CompoundBorder border = - BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.GRAY), + BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Java.BORDER), BorderFactory.createEmptyBorder(0, 5, 0, 5)); thunkedText.setBorder(border); - thunkedText.setForeground(Color.BLUE); + thunkedText.setForeground(FG_COLOR_THUNK); thunkedPanel.add(thunkedText); return thunkedPanel; } @@ -224,9 +227,9 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod scroll = new JScrollPane(verticalScrollPanel); scroll.setBorder(null); scroll.setOpaque(true); - scroll.setBackground(Color.WHITE); - scroll.getViewport().setBackground(new Color(0, 0, 0, 0)); // transparent - scroll.getViewport().setBackground(Color.WHITE); + scroll.setBackground(Colors.BACKGROUND); + scroll.getViewport().setBackground(Palette.NO_COLOR); // transparent + scroll.getViewport().setBackground(Colors.BACKGROUND); previewPanel.add(scroll, BorderLayout.CENTER); previewPanel.setBorder(BorderFactory.createLoweredBevelBorder()); scroll.getViewport().addMouseListener(new MouseAdapter() { @@ -440,10 +443,10 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod private Component buildButtonPanel() { JPanel panel = new JPanel(new VerticalLayout(5)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - addButton = new JButton(ADD_ICON); - removeButton = new JButton(REMOVE_ICON); - upButton = new JButton(UP_ICON); - downButton = new JButton(DOWN_ICON); + addButton = new JButton(Icons.ADD_ICON); + removeButton = new JButton(Icons.DELETE_ICON); + upButton = new JButton(new GIcon("icon.up")); + downButton = new JButton(new GIcon("icon.down")); addButton.setToolTipText("Add parameter"); removeButton.setToolTipText("Delete selected parameters"); upButton.setToolTipText("Move selected parameter up"); @@ -657,12 +660,13 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod DataType dataType = (DataType) value; Color color = isSelected ? table.getSelectionForeground() : table.getForeground(); if (!tableModel.isCellEditable(row, column)) { - color = isSelected ? Color.yellow : Color.gray; + color = + isSelected ? Tables.FG_UNEDITABLE_SELECTED : Tables.FG_UNEDITABLE_UNSELECTED; } if (dataType != null) { setText(dataType.getName()); if (dataType.isNotYetDefined()) { - color = Color.red; + color = isSelected ? Tables.FG_ERROR_SELECTED : Tables.FG_ERROR_UNSELECTED; } String toolTipText = ToolTipUtils.getToolTipText(dataType); String headerText = "" + @@ -751,17 +755,20 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod boolean isInvalidStorage = !storage.isValid() || rowData.getFormalDataType().getLength() != storage.size(); if (isInvalidStorage) { - setForeground(Color.RED); + setForeground( + isSelected ? Tables.FG_ERROR_SELECTED : Tables.FG_ERROR_UNSELECTED); setToolTipText("Invalid Parameter Storage"); } else { - setForeground(isSelected ? Color.WHITE : Color.BLACK); + setForeground( + isSelected ? table.getSelectionForeground() : Colors.FOREGROUND); setToolTipText(""); } setText(storage.toString()); } else { - setForeground(isSelected ? Color.WHITE : Color.BLACK); + setForeground( + isSelected ? table.getSelectionForeground() : Colors.FOREGROUND); setText(""); setToolTipText(null); } @@ -770,6 +777,7 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod } private class VariableStringCellRenderer extends GTableCellRenderer { + @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { @@ -785,7 +793,8 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod ParameterTableModel tableModel = (ParameterTableModel) table.getModel(); if (!tableModel.isCellEditable(row, column)) { - setForeground(isSelected ? Color.yellow : Color.gray); + setForeground( + isSelected ? Tables.FG_UNEDITABLE_SELECTED : Tables.FG_UNEDITABLE_UNSELECTED); } else { if (isSelected) { @@ -853,7 +862,7 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod Composite originalComposite = g2d.getComposite(); g2d.setComposite(alphaComposite); - g.setColor(Color.white); + g.setColor(Colors.BACKGROUND); g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); g2d.setComposite(originalComposite); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java index d42c139764..2d256a9eda 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionSignatureTextField.java @@ -15,9 +15,6 @@ */ package ghidra.app.plugin.core.function.editor; -import static java.awt.Color.blue; -import static java.awt.Color.red; - import java.awt.*; import java.awt.event.*; import java.util.ArrayList; @@ -28,16 +25,21 @@ import javax.swing.event.*; import javax.swing.text.*; import docking.actions.KeyBindingUtils; +import generic.theme.GColor; import ghidra.util.Swing; class FunctionSignatureTextField extends JTextPane { private static final String ENTER_ACTION_NAME = "ENTER"; private static final String ESCAPE_ACTION_NAME = "ESCAPE"; private static final String TAB_ACTION_NAME = "TAB"; - public static Color DEFAULT_COLOR = Color.black; - public static Color PARAMETER_NAME_COLOR = new Color(155, 50, 155); - public static Color FUNCTION_NAME_COLOR = blue; - public static Color ERROR_NAME_COLOR = red; + public static Color DEFAULT_COLOR = + new GColor("color.fg.plugin.function.editor.dialog.textfield.default"); + public static Color PARAMETER_NAME_COLOR = + new GColor("color.fg.plugin.function.editor.dialog.textfield.parameter"); + public static Color FUNCTION_NAME_COLOR = + new GColor("color.fg.plugin.function.editor.dialog.textfield.function.name"); + public static Color ERROR_NAME_COLOR = + new GColor("color.fg.plugin.function.editor.dialog.textfield.error"); private StyledDocument doc; private SimpleAttributeSet paramNameAttributes; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageTableCellEditor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageTableCellEditor.java index 7f3d19138c..cd89ebe0fe 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageTableCellEditor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/StorageTableCellEditor.java @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.function.editor; -import java.awt.Color; import java.awt.Component; import java.awt.event.MouseEvent; import java.util.EventObject; @@ -24,6 +23,7 @@ import javax.swing.*; import javax.swing.table.TableCellEditor; import docking.DockingWindowManager; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.program.model.listing.VariableStorage; class StorageTableCellEditor extends AbstractCellEditor implements TableCellEditor { @@ -53,30 +53,27 @@ class StorageTableCellEditor extends AbstractCellEditor implements TableCellEdit boolean isSelected, int row, int column) { String stringValue = value == null ? "" : value.toString(); JTextField field = new JTextField(stringValue); - field.setBackground(Color.yellow); + field.setBackground( + isSelected ? Tables.FG_UNEDITABLE_SELECTED : Tables.FG_UNEDITABLE_UNSELECTED); field.setEditable(false); ParameterTableModel tableModel = (ParameterTableModel) table.getModel(); FunctionVariableData rowData = tableModel.getRowObject(row); final StorageAddressEditorDialog dialog = new StorageAddressEditorDialog(model.getProgram(), model.getDataTypeManagerService(), (VariableStorage) value, rowData); - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - DockingWindowManager.showDialog(table, dialog); - if (!dialog.wasCancelled()) { - storage = dialog.getStorage(); - } - TableCellEditor cellEditor = table.getCellEditor(); - if (cellEditor == null) { - return; - } - if (storage == null) { - cellEditor.cancelCellEditing(); - } - else { - cellEditor.stopCellEditing(); - } + SwingUtilities.invokeLater(() -> { + DockingWindowManager.showDialog(table, dialog); + if (!dialog.wasCancelled()) { + storage = dialog.getStorage(); + } + TableCellEditor cellEditor = table.getCellEditor(); + if (cellEditor == null) { + return; + } + if (storage == null) { + cellEditor.cancelCellEditing(); + } + else { + cellEditor.stopCellEditing(); } }); return field; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeLocationCellEditor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeLocationCellEditor.java index 293f5f88f4..a93be40e57 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeLocationCellEditor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeLocationCellEditor.java @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.function.editor; -import java.awt.Color; import java.awt.Component; import java.awt.event.*; import java.math.BigInteger; @@ -28,6 +27,7 @@ import javax.swing.table.TableCellEditor; import docking.widgets.combobox.GhidraComboBox; import docking.widgets.textfield.IntegerTextField; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.AddressInput; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressOutOfBoundsException; @@ -44,12 +44,7 @@ class VarnodeLocationCellEditor extends AbstractCellEditor implements TableCellE private AddressInput addressInput; private IntegerTextField offsetInput; - private Comparator registerWrapperComparator = new Comparator() { - @Override - public int compare(Register r1, Register r2) { - return r1.toString().compareToIgnoreCase(r2.toString()); - } - }; + private Comparator registerWrapperComparator = (r1, r2) -> r1.toString().compareToIgnoreCase(r2.toString()); private VarnodeInfo currentVarnode; private int maxRegisterSize; @@ -146,12 +141,7 @@ class VarnodeLocationCellEditor extends AbstractCellEditor implements TableCellE if (address != null) { addressInput.setAddress(address); } - addressInput.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - stopCellEditing(); - } - }); + addressInput.addActionListener(e -> stopCellEditing()); return addressInput; } @@ -162,14 +152,9 @@ class VarnodeLocationCellEditor extends AbstractCellEditor implements TableCellE if (address != null) { offsetInput.setValue(address.getOffset()); } - offsetInput.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - stopCellEditing(); - } - }); + offsetInput.addActionListener(e -> stopCellEditing()); JComponent component = offsetInput.getComponent(); - component.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); + component.setBorder(BorderFactory.createLineBorder(Palette.GRAY, 1)); return component; } @@ -215,12 +200,7 @@ class VarnodeLocationCellEditor extends AbstractCellEditor implements TableCellE } }); - combo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - stopCellEditing(); - } - }); + combo.addActionListener(e -> stopCellEditing()); return combo; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeSizeCellEditor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeSizeCellEditor.java index 0d6dabeaba..cf52210291 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeSizeCellEditor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/VarnodeSizeCellEditor.java @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.function.editor; -import java.awt.Color; import java.awt.Component; import java.awt.event.*; import java.math.BigInteger; @@ -25,6 +24,7 @@ import javax.swing.*; import javax.swing.table.TableCellEditor; import docking.widgets.textfield.IntegerTextField; +import generic.theme.GThemeDefaults.Colors.Palette; class VarnodeSizeCellEditor extends AbstractCellEditor implements TableCellEditor { @@ -70,14 +70,9 @@ class VarnodeSizeCellEditor extends AbstractCellEditor implements TableCellEdito }; input.getComponent().addFocusListener(focusListener); } - input.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - stopCellEditing(); - } - }); + input.addActionListener(e -> stopCellEditing()); JComponent component = input.getComponent(); - component.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1)); + component.setBorder(BorderFactory.createLineBorder(Palette.GRAY, 1)); return component; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagButtonPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagButtonPanel.java index a0e17897cc..fae3c7d2c7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagButtonPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagButtonPanel.java @@ -20,8 +20,8 @@ import java.awt.event.ActionListener; import javax.swing.*; +import generic.theme.GIcon; import resources.Icons; -import resources.ResourceManager; /** * Provides buttons to be used with the {@link FunctionTagProvider}. @@ -35,9 +35,6 @@ import resources.ResourceManager; */ public class FunctionTagButtonPanel extends JPanel { - private Icon ADD_IMG = ResourceManager.loadImage("images/2rightarrow.png"); - private Icon REMOVE_IMG = ResourceManager.loadImage("images/2leftarrow.png"); - private SourceTagsPanel sourcePanel; private TargetTagsPanel targetPanel; private JButton addBtn; @@ -101,25 +98,24 @@ public class FunctionTagButtonPanel extends JPanel { deleteBtn.setEnabled(hasSelection && !isImmutable); } - /****************************************************************************** - * PRIVATE METHODS - ******************************************************************************/ - private void createButtonPanel() { setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; - addBtn = createButton("addBtn", ADD_IMG, "Add selected tags to the function", + addBtn = createButton("addBtn", new GIcon("icon.plugin.functiontags.add"), + "Add selected tags to the function", e -> { sourcePanel.addSelectedTags(); }); add(addBtn, gbc); gbc.gridy = 1; - removeBtn = createButton("removeBtn", REMOVE_IMG, "Remove selected tags from the function", - e -> targetPanel.removeSelectedTags()); + removeBtn = + createButton("removeBtn", new GIcon("icon.plugin.functiontags.remove"), + "Remove selected tags from the function", + e -> targetPanel.removeSelectedTags()); add(removeBtn, gbc); gbc.gridy = 2; @@ -147,7 +143,6 @@ public class FunctionTagButtonPanel extends JPanel { JButton button = new JButton(name); button.setName(name); button.setToolTipText(tooltip); - icon = ResourceManager.getScaledIcon(icon, 16, 16); button.setIcon(icon); button.setText(""); button.addActionListener(action); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java index 943268563b..7c5ed34091 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java @@ -15,9 +15,9 @@ */ package ghidra.app.plugin.core.function.tags; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Dimension; import java.util.*; -import java.util.List; import javax.swing.*; import javax.swing.border.BevelBorder; @@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.label.GLabel; import docking.widgets.textfield.HintTextField; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.app.cmd.function.CreateFunctionTagCmd; import ghidra.app.context.ProgramActionContext; import ghidra.framework.cmd.Command; @@ -58,8 +59,6 @@ import resources.ResourceManager; public class FunctionTagProvider extends ComponentProviderAdapter implements DomainObjectListener { - private Color BORDER_COLOR = Color.GRAY; - private SourceTagsPanel sourcePanel; private TargetTagsPanel targetPanel; private FunctionTagButtonPanel buttonPanel; @@ -240,9 +239,9 @@ public class FunctionTagProvider extends ComponentProviderAdapter targetPanel = new TargetTagsPanel(this, tool, "Assigned To Function"); allFunctionsPanel = new AllFunctionsPanel(program, this, "Functions with Selected Tag"); buttonPanel = new FunctionTagButtonPanel(sourcePanel, targetPanel); - sourcePanel.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); - targetPanel.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); - allFunctionsPanel.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); + sourcePanel.setBorder(BorderFactory.createLineBorder(Java.BORDER)); + targetPanel.setBorder(BorderFactory.createLineBorder(Java.BORDER)); + allFunctionsPanel.setBorder(BorderFactory.createLineBorder(Java.BORDER)); // If we don't set this, then the splitter won't be able to shrink the // target panels below the size required by its header, which can be large diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/FunctionComparisonPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/FunctionComparisonPanel.java index 8ca6920578..5dd2e8cc3e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/FunctionComparisonPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/FunctionComparisonPanel.java @@ -31,6 +31,7 @@ import docking.ComponentProvider; import docking.action.*; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.tabbedpane.DockingTabRenderer; +import generic.theme.GIcon; import ghidra.app.util.viewer.listingpanel.ListingCodeComparisonPanel; import ghidra.app.util.viewer.util.CodeComparisonPanel; import ghidra.framework.options.SaveState; @@ -44,7 +45,6 @@ import ghidra.util.Msg; import ghidra.util.classfinder.ClassSearcher; import help.Help; import help.HelpService; -import resources.ResourceManager; /** * A panel for displaying {@link Function functions}, {@link Data data}, or @@ -66,9 +66,10 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener { private static final HelpService help = Help.getHelpService(); private static final String HELP_TOPIC = "FunctionComparison"; - private static final Icon SYNC_SCROLLING_ICON = ResourceManager.loadImage("images/lock.gif"); + private static final Icon SYNC_SCROLLING_ICON = + new GIcon("icon.plugin.functioncompare.scroll.lock"); private static final Icon UNSYNC_SCROLLING_ICON = - ResourceManager.loadImage("images/unlock.gif"); + new GIcon("icon.plugin.functioncompare.scroll.unlock"); private static final String SCROLLING_GROUP = "A9_SCROLLING"; private static final String DUAL_SCROLLING_ACTION_GROUP = "DualScrolling"; private static final String DUAL_SCROLLING_HELP_TOPIC = "FunctionComparison"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java index 3bab2121d1..79063dce92 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/CompareFunctionsAction.java @@ -19,18 +19,14 @@ import java.awt.event.InputEvent; import java.util.Set; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.services.FunctionComparisonService; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.listing.Function; import ghidra.util.HelpLocation; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.ScaledImageIcon; -import resources.icons.TranslateIcon; /** * Creates a new comparison between a set of functions, launching a new @@ -45,13 +41,7 @@ public abstract class CompareFunctionsAction extends DockingAction { protected FunctionComparisonService comparisonService; - private static final ImageIcon COMPARISON_ICON = - ResourceManager.loadImage("images/page_white_c.png"); - private static final Icon NEW_ICON = ResourceManager.loadImage("images/bullet_star.png"); - private static final Icon SCALED_NEW_ICON = new ScaledImageIcon(NEW_ICON, 16, 16); - private static final Icon TRANSLATED_NEW_ICON = new TranslateIcon(SCALED_NEW_ICON, 4, -4); - private static final Icon CREATE_NEW_COMPARISON_ICON = - new MultiIcon(COMPARISON_ICON, TRANSLATED_NEW_ICON); + private static final Icon COMPARISON_ICON = new GIcon("icon.plugin.functioncompare.new"); private static final String CREATE_COMPARISON_GROUP = "A9_CreateComparison"; static final String POPUP_MENU_NAME = "Compare Selected Functions"; @@ -85,7 +75,7 @@ public abstract class CompareFunctionsAction extends DockingAction { * @return the icon */ protected Icon getToolBarIcon() { - return CREATE_NEW_COMPARISON_ICON; + return COMPARISON_ICON; } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NavigateToFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NavigateToFunctionAction.java index ad6b0b4491..6b2b3168d0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NavigateToFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NavigateToFunctionAction.java @@ -18,7 +18,7 @@ package ghidra.app.plugin.core.functioncompare.actions; import java.awt.event.*; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.ToggleDockingAction; import docking.action.ToolBarData; @@ -48,7 +48,7 @@ public class NavigateToFunctionAction extends ToggleDockingAction { private GoToService goToService; - private static final ImageIcon NAV_FUNCTION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; + private static final Icon NAV_FUNCTION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; /** * Constructor @@ -64,10 +64,9 @@ public class NavigateToFunctionAction extends ToggleDockingAction { setSelected(false); ToolBarData newToolBarData = new ToolBarData(NAV_FUNCTION_ICON); setToolBarData(newToolBarData); - setDescription( - HTMLUtilities.toHTML("Toggle On means to navigate to whatever " + - "function is selected in the comparison panel, when focus changes or" + - "a new function is selected.")); + setDescription(HTMLUtilities.toHTML("Toggle On means to navigate to whatever " + + "function is selected in the comparison panel, when focus changes or" + + "a new function is selected.")); setHelpLocation( new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC, "Navigate_To_Function")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NextFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NextFunctionAction.java index 2c7afcbe4d..915724a1ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NextFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/NextFunctionAction.java @@ -24,13 +24,11 @@ import javax.swing.JComboBox; import docking.ActionContext; import docking.ComponentProvider; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonPanel; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonProvider; import ghidra.program.model.listing.Function; import ghidra.util.HelpLocation; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.TranslateIcon; /** * Displays the next available function in the function comparison panel. If @@ -39,11 +37,8 @@ import resources.icons.TranslateIcon; public class NextFunctionAction extends DockingAction { private static final String FUNCTION_NAVIGATE_GROUP = "A9_FunctionNavigate"; - private static final Icon NEXT_ICON = - new TranslateIcon(ResourceManager.loadImage("images/arrow_down.png"), 3, 1); - private static final Icon FUNCTION_ICON = - new TranslateIcon(ResourceManager.loadImage("images/FunctionScope.gif"), -5, -2); - private static final Icon NEXT_FUNCTION_ICON = new MultiIcon(NEXT_ICON, FUNCTION_ICON); + private static final Icon NEXT_FUNCTION_ICON = + new GIcon("icon.plugin.functioncompare.function.next"); /** * Constructor diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java index b4f3e5cffa..77f42d7063 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/OpenFunctionTableAction.java @@ -20,11 +20,11 @@ import java.util.*; import java.util.stream.Collectors; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.ActionContext; import docking.action.*; import docking.widgets.dialogs.TableSelectionDialog; +import generic.theme.GIcon; import ghidra.app.plugin.core.functioncompare.FunctionComparisonProvider; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonPanel; import ghidra.app.plugin.core.functionwindow.FunctionRowObject; @@ -35,10 +35,6 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.ScaledImageIcon; -import resources.icons.TranslateIcon; import util.CollectionUtils; /** @@ -49,14 +45,9 @@ import util.CollectionUtils; */ public class OpenFunctionTableAction extends DockingAction { - private static final Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static final Icon SCALED_ADD_ICON = new ScaledImageIcon(ADD_ICON, 10, 10); - private static final ImageIcon COMPARISON_ICON = - ResourceManager.loadImage("images/page_white_c.png"); - private static final Icon TRANSLATED_ADD_ICON = new TranslateIcon(SCALED_ADD_ICON, 8, 1); private static final String ADD_COMPARISON_GROUP = "A9_AddToComparison"; private static final Icon ADD_TO_COMPARISON_ICON = - new MultiIcon(COMPARISON_ICON, TRANSLATED_ADD_ICON); + new GIcon("icon.plugin.functioncompare.open.function.table"); protected PluginTool tool; protected ProgramManager programManagerService; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/PreviousFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/PreviousFunctionAction.java index 01be55d06e..ece250013a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/PreviousFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/PreviousFunctionAction.java @@ -24,13 +24,11 @@ import javax.swing.JComboBox; import docking.ActionContext; import docking.ComponentProvider; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonPanel; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonProvider; import ghidra.program.model.listing.Function; import ghidra.util.HelpLocation; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.TranslateIcon; /** * Displays the previous function in the function comparison panel. If @@ -39,11 +37,8 @@ import resources.icons.TranslateIcon; public class PreviousFunctionAction extends DockingAction { private static final String FUNCTION_NAVIGATE_GROUP = "A9_FunctionNavigate"; - private static final Icon PREVIOUS_ICON = - new TranslateIcon(ResourceManager.loadImage("images/arrow_up.png"), 3, 1); - private static final Icon FUNCTION_ICON = - new TranslateIcon(ResourceManager.loadImage("images/FunctionScope.gif"), -5, -2); - private static final Icon PREVIOUS_FUNCTION_ICON = new MultiIcon(PREVIOUS_ICON, FUNCTION_ICON); + private static final Icon PREVIOUS_FUNCTION_ICON = + new GIcon("icon.plugin.functioncompare.function.previous"); /** * Constructor diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/RemoveFunctionsAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/RemoveFunctionsAction.java index f1cead3ba8..cf390a5fef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/RemoveFunctionsAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functioncompare/actions/RemoveFunctionsAction.java @@ -25,13 +25,11 @@ import javax.swing.JComboBox; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonPanel; import ghidra.app.plugin.core.functioncompare.MultiFunctionComparisonProvider; import ghidra.program.model.listing.Function; import ghidra.util.HelpLocation; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.TranslateIcon; /** * Removes the currently-selected function from the comparison panel. If no @@ -39,12 +37,9 @@ import resources.icons.TranslateIcon; */ public class RemoveFunctionsAction extends DockingAction { - private static final Icon FUNCTION_ICON = - new TranslateIcon(ResourceManager.loadImage("images/FunctionScope.gif"), -5, -2); - private static final Icon REMOVE_ICON = - new TranslateIcon(ResourceManager.loadImage("images/edit-delete.png"), 3, 3); private static final String REMOVE_FUNCTION_GROUP = "A9_RemoveFunctions"; - private static final Icon REMOVE_FUNCTION_ICON = new MultiIcon(REMOVE_ICON, FUNCTION_ICON); + private static final Icon REMOVE_FUNCTION_ICON = + new GIcon("icon.plugin.functioncompare.function.remove"); /** * Constructor diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java index 274d48bc47..67395fa17f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java @@ -25,6 +25,7 @@ import javax.swing.*; import javax.swing.table.*; import docking.ActionContext; +import generic.theme.GIcon; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.program.model.address.Address; @@ -32,14 +33,13 @@ import ghidra.program.model.listing.*; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; import ghidra.util.table.*; -import resources.ResourceManager; /** * Provider that displays all functions in the selected program */ public class FunctionWindowProvider extends ComponentProviderAdapter { - public static final ImageIcon icon = ResourceManager.loadImage("images/functions.gif"); + public static final Icon ICON = new GIcon("icon.plugin.functionwindow.provider"); private FunctionWindowPlugin plugin; private GhidraTable functionTable; @@ -58,7 +58,7 @@ public class FunctionWindowProvider extends ComponentProviderAdapter { super(plugin.getTool(), "Functions Window", plugin.getName()); setTitle("Functions"); this.plugin = plugin; - setIcon(icon); + setIcon(ICON); setHelpLocation(new HelpLocation(plugin.getName(), plugin.getName())); tool = plugin.getTool(); mainPanel = createWorkPanel(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java index c69538acc8..a7b641bd93 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/hover/AbstractReferenceHover.java @@ -24,6 +24,8 @@ import javax.swing.JToolTip; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.gotoquery.GoToHelper; import ghidra.app.services.CodeFormatService; import ghidra.app.util.*; @@ -44,7 +46,8 @@ import ghidra.util.bean.opteditor.OptionsVetoException; public abstract class AbstractReferenceHover extends AbstractConfigurableHover { private static final int WINDOW_OFFSET = 50; - private static final Color BACKGROUND_COLOR = new Color(255, 255, 230); + private static final Color BACKGROUND_COLOR = Colors.BACKGROUND_TOOLTIP; + private static final Color FG_COLOR_NOT_IN_MEMORY = new GColor("color.fg.hint"); private CodeFormatService codeFormatService; private ListingPanel panel; @@ -283,7 +286,7 @@ public abstract class AbstractReferenceHover extends AbstractConfigurableHover { String message = "Address not in memory"; message = HTMLUtilities.italic(message); - message = HTMLUtilities.colorString(Color.GRAY, message); + message = HTMLUtilities.colorString(FG_COLOR_NOT_IN_MEMORY, message); buffy.append(message); toolTip.setTipText(buffy.toString()); return toolTip; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java index aa6f1c81f9..123bd91d8e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java @@ -15,13 +15,13 @@ */ package ghidra.app.plugin.core.instructionsearch; -import java.awt.Color; import java.util.HashSet; import java.util.Set; import docking.action.DockingAction; import docking.action.MenuData; import docking.tool.ToolConstants; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.CorePluginPackage; import ghidra.app.context.NavigatableActionContext; import ghidra.app.context.NavigatableContextAction; @@ -135,12 +135,12 @@ public class InstructionSearchPlugin extends ProgramPlugin { if (selection.getNumAddresses() == 0) { dialog.displayMessage( "Select instructions from the listing (and hit reload) to populate the table.", - Color.BLUE); + Messages.NORMAL); return false; } if (!isSelectionSizeValid(selection)) { dialog.displayMessage("Invalid selection. Cannot select more than " + - MAX_SELECTION_SIZE + " instructions and/or data items.", Color.RED); + MAX_SELECTION_SIZE + " instructions and/or data items.", Messages.ERROR); return false; } @@ -150,7 +150,7 @@ public class InstructionSearchPlugin extends ProgramPlugin { } } catch (InvalidInputException e) { - dialog.displayMessage(e.getMessage(), Color.RED); + dialog.displayMessage(e.getMessage(), Messages.ERROR); return false; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionTableDataObject.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionTableDataObject.java index 126cb6aa62..f81ed99f13 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionTableDataObject.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionTableDataObject.java @@ -22,6 +22,8 @@ import java.util.Set; import javax.swing.BorderFactory; import javax.swing.border.Border; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.instructionsearch.ui.AbstractInstructionTable.OperandState; import ghidra.app.plugin.core.instructionsearch.ui.InstructionTable; @@ -42,37 +44,41 @@ public class InstructionTableDataObject { * This is static since all data objects will have the same list of * observers */ - private Set observers = new HashSet(); + private Set observers = new HashSet<>(); // The text displayed in the cell. private String data; // Some cell attributes. private Color backgroundColor; - private Color foregroundColor; + private Color foregroundColor = Colors.FOREGROUND; private int fontStyle; - // The border style of the cell. This is used to facilitate the 3D look of the - // cells (bevel-styling). + // The border style of the cell. This is used to facilitate the 3D look of the cells + // (bevel-styling). private Border border; - // The state of the object; this describes whether the cell is in a masked or - // unmasked state, or neither (NA). + // The state of the object; this describes whether the cell is in a masked or unmasked state, + // or neither (NA). private OperandState state; - // True if this data object represents an instruction (and not an undefined data item or - // string). + // True if this data object represents an instruction (and not an undefined data). private boolean isInstruction; // Stores information about the operand for this cell (if it's an operand); if the // cell represents a mnemonic then this does not apply. private OperandMetadata operandCase; - private static final Color BACKGROUND_COLOR = new Color(237, 243, 254); - private static final Color BACKGROUND_COLOR_DARKER = new Color(188, 212, 254); - private static final Color BACKGROUND_COLOR_NON_INSTRUCTION = new Color(255, 242, 214); - private static final Color BACKGROUND_COLOR_DARKER_NON_INSTRUCTION = new Color(203, 186, 150); - private static final Color PANEL_COLOR = new Color(214, 217, 223); + private static final Color BG_COLOR_MASKED_INSTRUCTION = + new GColor("color.bg.plugin.instructionsearch.table.masked.instruction"); + private static final Color BG_COLOR_NOT_MASKED_INSTRUCTION = + new GColor("color.bg.plugin.instructionsearch.table.not.masked.instruction"); + private static final Color BG_COLOR_MASKED_NON_INSTRUCTION = + new GColor("color.bg.plugin.instructionsearch.table.masked.non.instruction"); + private static final Color BG_COLOR_NOT_MASKED_NON_INSTRUCTION = + new GColor("color.bg.plugin.instructionsearch.table.not.masked.non.instruction"); + private static final Color BG_COLOR_DEFAULT = + new GColor("color.bg.plugin.instructionsearch.table.default"); /** * Constructor. @@ -124,22 +130,20 @@ public class InstructionTableDataObject { switch (state) { case MASKED: backgroundColor = - isInstruction ? BACKGROUND_COLOR : BACKGROUND_COLOR_NON_INSTRUCTION; - foregroundColor = Color.BLACK; + isInstruction ? BG_COLOR_MASKED_INSTRUCTION : BG_COLOR_MASKED_NON_INSTRUCTION; border = BorderFactory.createLoweredSoftBevelBorder(); break; case NOT_MASKED: - backgroundColor = isInstruction ? BACKGROUND_COLOR_DARKER - : BACKGROUND_COLOR_DARKER_NON_INSTRUCTION; - foregroundColor = Color.BLACK; + backgroundColor = isInstruction ? BG_COLOR_NOT_MASKED_INSTRUCTION + : BG_COLOR_NOT_MASKED_NON_INSTRUCTION; border = BorderFactory.createRaisedSoftBevelBorder(); break; case NA: - backgroundColor = PANEL_COLOR; + backgroundColor = BG_COLOR_DEFAULT; break; case PREVIEW: backgroundColor = - isInstruction ? BACKGROUND_COLOR : BACKGROUND_COLOR_NON_INSTRUCTION; + isInstruction ? BG_COLOR_MASKED_INSTRUCTION : BG_COLOR_MASKED_NON_INSTRUCTION; break; } @@ -148,9 +152,6 @@ public class InstructionTableDataObject { } } - /** - * Subscribes the given observer to be notified of changes to this object. - */ public void register(InstructionTableObserver observer) { observers.add(observer); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/AbstractInstructionTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/AbstractInstructionTable.java index 270620a717..e70bc184b9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/AbstractInstructionTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/AbstractInstructionTable.java @@ -15,8 +15,6 @@ */ package ghidra.app.plugin.core.instructionsearch.ui; -import java.awt.Font; - import javax.swing.JToolBar; import javax.swing.table.TableCellRenderer; @@ -58,8 +56,7 @@ public abstract class AbstractInstructionTable extends GhidraTable { protected JToolBar toolbar; - protected InstructionTableCellRenderer renderer = - new InstructionTableCellRenderer(new Font("Courier", Font.PLAIN, 14)); + protected InstructionTableCellRenderer renderer = new InstructionTableCellRenderer(); protected InstructionSearchData searchData; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/ControlPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/ControlPanel.java index b8f207572e..ac8c4fb3f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/ControlPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/ControlPanel.java @@ -15,11 +15,13 @@ */ package ghidra.app.plugin.core.instructionsearch.ui; -import java.awt.*; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; import javax.swing.BorderFactory; import javax.swing.JPanel; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; /** @@ -31,11 +33,6 @@ public class ControlPanel extends JPanel { private SelectionScopeWidget rangeWidget; private SearchDirectionWidget directionWidget; - /** - * - * @param plugin - * @param dialog - */ public ControlPanel(InstructionSearchPlugin plugin, InstructionSearchDialog dialog) { setLayout(new GridBagLayout()); @@ -60,21 +57,13 @@ public class ControlPanel extends JPanel { gbc.weightx = 1.0; this.add(directionWidget, gbc); - this.setBorder(BorderFactory.createLineBorder(Color.GRAY)); + this.setBorder(BorderFactory.createLineBorder(Java.BORDER)); } - /** - * - * @return - */ public SelectionScopeWidget getRangeWidget() { return this.rangeWidget; } - /** - * - * @return - */ public SearchDirectionWidget getDirectionWidget() { return this.directionWidget; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/HintTextAreaIS.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/HintTextAreaIS.java index ef67a1393a..ba0e87cf72 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/HintTextAreaIS.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/HintTextAreaIS.java @@ -15,25 +15,23 @@ */ package ghidra.app.plugin.core.instructionsearch.ui; -import java.awt.Color; import java.awt.Font; import docking.widgets.textarea.HintTextArea; +import generic.theme.GThemeDefaults.Colors; /** * Allows users to provide a text hint in a text field, shown only when the text is empty. - * + *

* Hint text will be shown in light grey, italicized, and in angle brackets. Normal text will * be plain black. */ public class HintTextAreaIS extends HintTextArea { - private String hint; - /** * Constructs the class with the hint text to be shown. * - * @param hint + * @param hint the hint */ public HintTextAreaIS(final String hint) { super(hint); @@ -53,16 +51,12 @@ public class HintTextAreaIS extends HintTextArea { setAttributes(); } - /********************************************************************************************* - * PRIVATE METHODS - ********************************************************************************************/ - /** * Sets the text attributes to be used when there is an error in the input. */ private void setErrorAttributes() { this.setFont(getFont().deriveFont(Font.PLAIN)); - setForeground(Color.RED); + setForeground(Colors.ERROR); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java index 0b1743217a..154a7db003 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InsertBytesWidget.java @@ -15,7 +15,8 @@ */ package ghidra.app.plugin.core.instructionsearch.ui; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Dimension; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; @@ -25,6 +26,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import docking.DialogComponentProvider; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.instructionsearch.model.*; import ghidra.app.plugin.core.instructionsearch.ui.SelectionModeWidget.InputMode; import ghidra.app.plugin.core.instructionsearch.util.InstructionSearchUtils; @@ -290,7 +292,8 @@ public class InsertBytesWidget extends DialogComponentProvider implements KeyLis // there's a problem with the input. Just print a message to the user and // exit. if (allBytes.size() < instruction.getLength()) { - msgPanel.setMessageText("Input invalid: unknown disassembly error.", Color.RED); + msgPanel.setMessageText("Input invalid: unknown disassembly error.", + Messages.ERROR); return; } allBytes.subList(0, instruction.getLength()).clear(); @@ -300,7 +303,8 @@ public class InsertBytesWidget extends DialogComponentProvider implements KeyLis // If there's an exception, just stop and let the user figure out what went // wrong - no need to continue. - msgPanel.setMessageText("Input invalid: unknown disassembly error.", Color.RED); + msgPanel.setMessageText("Input invalid: unknown disassembly error.", + Messages.ERROR); Msg.debug(this, "Error disassembling instruction", e); return; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java index ec79cebaad..9d7beb1fdb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java @@ -23,6 +23,8 @@ import javax.swing.*; import docking.ComponentProvider; import docking.DialogComponentProvider; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.InstructionMetadata; @@ -61,6 +63,9 @@ import ghidra.util.task.TaskMonitor; public class InstructionSearchDialog extends DialogComponentProvider implements Observer { + private static final Color BG_COLOR_MARKERS = + new GColor("color.bg.plugin.instructionsearch.search.markers"); + // Panel containing the {@link InstructionTable} and {@link PreviewTable}. private InstructionSearchMainPanel tablePanel; @@ -136,7 +141,7 @@ public class InstructionSearchDialog extends DialogComponentProvider implements if (selection == null && getMessagePanel() != null) { getMessagePanel().setMessageText( "Select instructions from the listing (and hit reload) to populate the table.", - Color.BLUE); + Messages.NORMAL); } if (selection != null && plugin.isSelectionValid(selection, this)) { @@ -498,7 +503,7 @@ public class InstructionSearchDialog extends DialogComponentProvider implements model.setSelectionSize(matchSize); TableComponentProvider

tableProvider = table.showTableWithMarkers(title + " " + model.getName(), "InstructionSearch", - model, Color.GREEN, null, "Instruction Search Results", null); + model, BG_COLOR_MARKERS, null, "Instruction Search Results", null); tableProvider.installRemoveItemsAction(); }; SystemUtilities.runSwingLater(runnable); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java index 1723488baf..6499b49a69 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java @@ -15,7 +15,6 @@ */ package ghidra.app.plugin.core.instructionsearch.ui; -import java.awt.Color; import java.awt.event.*; import java.util.List; @@ -23,6 +22,8 @@ import javax.swing.*; import docking.DockingWindowManager; import docking.widgets.EmptyBorderButton; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.*; import ghidra.app.services.GoToService; @@ -32,6 +33,7 @@ import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.*; +import resources.Icons; import resources.ResourceManager; /** @@ -47,15 +49,6 @@ public class InstructionTable extends AbstractInstructionTable { // Defines the width/height for all icons on the toolbar private static final int ICON_SIZE = 16; - private static final String GO_HOME_ICON_OVERLAY = "images/go-home.png"; - private static final String ADDRESS_ICON_OVERLAY = "images/DOSA_A.png"; - private static final String SCALAR_ICON_OVERLAY = "images/DOSA_S.png"; - private static final String OPERAND_ICON_OVERLAY = "images/DOSA_O.png"; - private static final String UNDEFINED_ICON_OVERLAY = "images/DOSA_D.png"; - private static final String CLEAR_ICON_OVERLAY = "images/edit-clear.png"; - private static final String RELOAD_ICON_OVERLAY = "images/reload.png"; - private static final String MANUAL_ENTRY_ICON_OVERLAY = "images/editbytes.gif"; - // Need to keep track of the column in case the user clicks on the column header and we // need to display the context menu. private int selectedColumn = -1; @@ -168,7 +161,9 @@ public class InstructionTable extends AbstractInstructionTable { } InstructionTableDataObject[][] dataObjects = - new InstructionTableDataObject[dialog.getSearchData().getInstructions().size()][numColumns]; + new InstructionTableDataObject[dialog.getSearchData() + .getInstructions() + .size()][numColumns]; // Loop over all instructions, adding pertinent info to each data object. This could be a long-running // operation so put in a task that can be cancelled. @@ -285,21 +280,21 @@ public class InstructionTable extends AbstractInstructionTable { } private void createGoToAddressBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(GO_HOME_ICON_OVERLAY); + Icon icon = Icons.HOME_ICON; Action action = new NavAction("navigation", icon, "Navigate to the address defined by this instruction set"); createToolbarButton(buttonToolbar, icon, action, "nav button"); } private void createMaskClearAllBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(CLEAR_ICON_OVERLAY); + Icon icon = Icons.CLEAR_ICON; Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new ClearMasksAction("undefined", scaledIcon, "Unmask all"); createToolbarButton(buttonToolbar, icon, action, "unmask all button"); } private void createReloadBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(RELOAD_ICON_OVERLAY); + Icon icon = Icons.REFRESH_ICON; Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new ReloadAction("undefined", scaledIcon, "Load selected instructions from listing"); @@ -307,14 +302,14 @@ public class InstructionTable extends AbstractInstructionTable { } private void createManualEditBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(MANUAL_ENTRY_ICON_OVERLAY); + Icon icon = new GIcon("icon.plugin.instructiontable.manual.entry"); Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new ManualEntryAction("undefined", scaledIcon, "Enter bytes manually"); createToolbarButton(buttonToolbar, icon, action, "manual entry"); } private void createMaskDataBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(UNDEFINED_ICON_OVERLAY); + Icon icon = new GIcon("icon.plugin.instructiontable.undefined"); Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new MaskUndefinedAction("undefined", scaledIcon, "Mask all non-instructions (data)"); @@ -322,21 +317,21 @@ public class InstructionTable extends AbstractInstructionTable { } private void createMaskAddressesBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(ADDRESS_ICON_OVERLAY); + Icon icon = new GIcon("icon.plugin.instructiontable.address"); Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new MaskAddressesAction("addresses", scaledIcon, "Mask all addresses"); createToolbarButton(buttonToolbar, icon, action, "mask addresses button"); } private void createMaskScalarsBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(SCALAR_ICON_OVERLAY); + Icon icon = new GIcon("icon.plugin.instructiontable.scalar"); Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new MaskScalarsAction("scalars", scaledIcon, "Mask all scalars"); createToolbarButton(buttonToolbar, icon, action, "mask scalars button"); } private void createMaskOperandsBtn(JToolBar buttonToolbar) { - Icon icon = ResourceManager.loadImage(OPERAND_ICON_OVERLAY); + Icon icon = new GIcon("icon.plugin.instructiontable.operand"); Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = new MaskOperandsAction("operands", scaledIcon, "Mask all operands"); createToolbarButton(buttonToolbar, icon, action, "mask operands button"); @@ -516,9 +511,10 @@ public class InstructionTable extends AbstractInstructionTable { } else { if (dialog.getMessagePanel() != null) { - dialog.getMessagePanel().setMessageText( - "Instruction was loaded manually, no address in the listing to navigate to.", - Color.BLUE); + dialog.getMessagePanel() + .setMessageText( + "Instruction was loaded manually, no address in the listing to navigate to.", + Messages.NORMAL); } } } @@ -546,7 +542,6 @@ public class InstructionTable extends AbstractInstructionTable { /** * Creates a new {@link InstructionTableDataObject} for the given operand. * - * @param mnemonic the mnemonic ID * @param col the column in the table * @param dataObjects the set of data objects to modify */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java index 58fa759f76..d6833c37a8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java @@ -21,6 +21,7 @@ import javax.swing.*; import javax.swing.table.TableModel; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.Gui; import ghidra.app.plugin.core.instructionsearch.model.InstructionTableDataObject; import ghidra.util.table.GhidraTableCellRenderer; @@ -29,13 +30,10 @@ import ghidra.util.table.GhidraTableCellRenderer; * while adding some custom logic for changing background/foreground attributes. */ public class InstructionTableCellRenderer extends GhidraTableCellRenderer { + private static final String FONT_ID = "font.plugin.instruction.table.renderer"; - /** - * - * @param font - */ - public InstructionTableCellRenderer(Font font) { - super(font); + public InstructionTableCellRenderer() { + super(Gui.getFont(FONT_ID)); } /** @@ -76,24 +74,10 @@ public class InstructionTableCellRenderer extends GhidraTableCellRenderer { return this; } - /********************************************************************************************* - * PRIVATE METHODS - ********************************************************************************************/ - - /** - * - * @param dataObject - * @param theRenderer - */ private void setBorderAttributes(InstructionTableDataObject dataObject, JLabel theRenderer) { theRenderer.setBorder(dataObject.getBorder()); } - /** - * - * @param dataObject - * @param theRenderer - */ private void setForegroundAttributes(InstructionTableDataObject dataObject, JLabel theRenderer) { // Change the foreground to use a font of our choosing. The main reason is that we @@ -103,12 +87,6 @@ public class InstructionTableCellRenderer extends GhidraTableCellRenderer { theRenderer.setFont(newFont); } - /** - * - * @param isSelected - * @param hasFocus - * @param dataObject - */ private void setBackgroundAttributes(boolean isSelected, boolean hasFocus, InstructionTableDataObject dataObject) { // Set the background color based on what the cell says. If it's selected, make it a @@ -116,7 +94,7 @@ public class InstructionTableCellRenderer extends GhidraTableCellRenderer { Color backgroundColor = dataObject.getBackgroundColor(); if (backgroundColor != null) { if (isSelected || hasFocus) { - setBackground(backgroundColor.darker()); + setBackground(Gui.darker(backgroundColor)); } else { setBackground(backgroundColor); @@ -124,12 +102,6 @@ public class InstructionTableCellRenderer extends GhidraTableCellRenderer { } } - /** - * - * @param table - * @param value - * @param col - */ private void setTextAttributes(JTable table, Object value, int col) { setHorizontalAlignment(SwingConstants.LEFT); TableModel model = table.getModel(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/PreviewTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/PreviewTable.java index 9e4692de6f..f3ae5aa469 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/PreviewTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/PreviewTable.java @@ -31,6 +31,7 @@ import docking.action.DockingAction; import docking.action.MenuData; import docking.dnd.GClipboard; import docking.widgets.EmptyBorderButton; +import generic.theme.GIcon; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.*; import ghidra.app.plugin.core.instructionsearch.ui.SelectionModeWidget.InputMode; @@ -39,7 +40,7 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.util.Msg; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.*; -import resources.ResourceManager; +import resources.Icons; /** * Displays the preview string for all instructions in the @@ -231,12 +232,6 @@ public class PreviewTable extends AbstractInstructionTable { new TaskLauncher(task, PreviewTable.this); } - /********************************************************************************************* - * PROTECTED METHODS - ********************************************************************************************/ - /** - * - */ @Override protected Object[] createColumnHeaders() { @@ -246,9 +241,6 @@ public class PreviewTable extends AbstractInstructionTable { return colsNames; } - /** - * - */ @Override protected JToolBar createToolbar() { JToolBar toolbar1 = new JToolBar(); @@ -293,10 +285,6 @@ public class PreviewTable extends AbstractInstructionTable { return dataObjects; } - /********************************************************************************************* - * PRIVATE METHODS - ********************************************************************************************/ - private void buildPreviewString(int instrSize, String valueStr, String maskStr, int posptr, int row) { @@ -328,8 +316,8 @@ public class PreviewTable extends AbstractInstructionTable { } private void createCopyBtn(JToolBar toolbar1) { - Icon copyIcon = ResourceManager.loadImage("images/page_white_copy.png"); - Action copyAction = new CopyAction("copy", (ImageIcon) copyIcon, + Icon copyIcon = Icons.COPY_ICON; + Action copyAction = new CopyAction("copy", copyIcon, "Copy the full search string to clipboard"); EmptyBorderButton copyBtn = new EmptyBorderButton(); copyBtn.setAction(copyAction); @@ -339,8 +327,8 @@ public class PreviewTable extends AbstractInstructionTable { } private EmptyBorderToggleButton createHexViewBtn(JToolBar toolbar1) { - Icon hexIcon = ResourceManager.loadImage("images/hexData.png"); - Action hexAction = new HexAction("hex", (ImageIcon) hexIcon, "hex view"); + Icon hexIcon = new GIcon("icon.plugin.instructiontable.hex"); + Action hexAction = new HexAction("hex", hexIcon, "hex view"); EmptyBorderToggleButton hexBtn = new EmptyBorderToggleButton(); hexBtn.setAction(hexAction); hexBtn.setName("Hex View Button"); @@ -351,8 +339,8 @@ public class PreviewTable extends AbstractInstructionTable { } private EmptyBorderToggleButton createBinaryViewBtn(JToolBar toolbar1) { - Icon binaryIcon = ResourceManager.loadImage("images/binaryData.gif"); - Action binaryAction = new BinaryAction("binary", (ImageIcon) binaryIcon, "binary view"); + Icon binaryIcon = new GIcon("icon.plugin.instructiontable.binary"); + Action binaryAction = new BinaryAction("binary", binaryIcon, "binary view"); EmptyBorderToggleButton binaryBtn = new EmptyBorderToggleButton(); binaryBtn.setAction(binaryAction); binaryBtn.setName("binary view button"); @@ -449,19 +437,19 @@ public class PreviewTable extends AbstractInstructionTable { createCopyNoSpacesAction(owner); copyNoSpacesAction.setPopupMenuData( new MenuData(new String[] { "Copy Special", "Selected instructions (no spaces)" }, - ResourceManager.loadImage("images/page_white_copy.png"), actionMenuGroup, + Icons.COPY_ICON, actionMenuGroup, MenuData.NO_MNEMONIC, Integer.toString(1))); createCopyInstructionAction(owner); copyInstructionAction.setPopupMenuData( new MenuData(new String[] { "Copy Special", "Selected Instructions" }, - ResourceManager.loadImage("images/page_white_copy.png"), actionMenuGroup, + Icons.COPY_ICON, actionMenuGroup, MenuData.NO_MNEMONIC, Integer.toString(1))); createCopyInstructionWithCommentsAction(owner); copyInstructionWithCommentsAction.setPopupMenuData( new MenuData(new String[] { "Copy Special", "Selected Instructions (with comments)" }, - ResourceManager.loadImage("images/page_white_copy.png"), actionMenuGroup, + Icons.COPY_ICON, actionMenuGroup, MenuData.NO_MNEMONIC, Integer.toString(1))); dialog.addAction(copyNoSpacesAction); @@ -488,8 +476,12 @@ public class PreviewTable extends AbstractInstructionTable { if (comment != null) { StringBuilder builder = new StringBuilder(); - builder.append(val).append("\t").append("// ").append(comment).append( - "\n"); + builder.append(val) + .append("\t") + .append("// ") + .append(comment) + .append( + "\n"); val = builder.toString(); } } @@ -566,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); } @@ -580,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); } @@ -594,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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java index 833fc6a7b9..d3902ba782 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java @@ -15,19 +15,18 @@ */ package ghidra.app.plugin.core.instructionsearch.ui; -import java.awt.Color; import java.util.*; -import javax.swing.SwingUtilities; - +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.InstructionMetadata; import ghidra.app.plugin.core.instructionsearch.ui.SearchDirectionWidget.Direction; import ghidra.app.services.GoToService; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; -import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.*; import ghidra.program.util.BytesFieldLocation; +import ghidra.util.Swing; import ghidra.util.task.Task; import ghidra.util.task.TaskMonitor; @@ -73,8 +72,11 @@ class SearchInstructionsTask extends Task { // See if we're searching forward or backwards. boolean forward = - searchDialog.getControlPanel().getDirectionWidget().getSearchDirection().equals( - Direction.FORWARD); + searchDialog.getControlPanel() + .getDirectionWidget() + .getSearchDirection() + .equals( + Direction.FORWARD); // If we're searching backwards we need to process address ranges in reverse so reverse // the list. @@ -121,7 +123,7 @@ class SearchInstructionsTask extends Task { // // Note we put these on the swing thread or it will throw off the task monitor display. if (searchResults != null) { - SwingUtilities.invokeLater(() -> { + Swing.runLater(() -> { goToLocation(searchResults.getAddr()); searchDialog.getMessagePanel().clear(); }); @@ -134,7 +136,8 @@ class SearchInstructionsTask extends Task { // If we've gone through all the ranges and there are still no results, show an // error message. - searchDialog.getMessagePanel().setMessageText("No results found", Color.BLUE); + searchDialog.getMessagePanel() + .setMessageText("No results found", Messages.NORMAL); return; } @@ -157,13 +160,13 @@ class SearchInstructionsTask extends Task { // The reason for the getting the CodeUnit is that the instruction might be an off-cut, // and if that's the case, then we can't navigate directly to it. What we have to do // is find the CodeUnit containing the instruction and navigate to that. + Program currentProgram = searchPlugin.getCurrentProgram(); + Listing listing = currentProgram.getListing(); if (direction == Direction.FORWARD) { for (InstructionMetadata instr : searchResults) { - CodeUnit unit = searchPlugin.getCurrentProgram().getListing().getCodeUnitContaining( - instr.getAddr()); - - if (unit.getMinAddress().compareTo(currentAddress) > 0) { - return unit.getMinAddress(); + CodeUnit cu = listing.getCodeUnitContaining(instr.getAddr()); + if (cu.getMinAddress().compareTo(currentAddress) > 0) { + return cu.getMinAddress(); } } } @@ -173,14 +176,12 @@ class SearchInstructionsTask extends Task { // // See above for an explanation for why we need to get the CodeUnit in this block. if (direction == Direction.BACKWARD) { - ListIterator iter = - searchResults.listIterator(searchResults.size()); - while (iter.hasPrevious()) { - InstructionMetadata instr = iter.previous(); - CodeUnit unit = searchPlugin.getCurrentProgram().getListing().getCodeUnitContaining( - instr.getAddr()); - if (unit.getMinAddress().compareTo(currentAddress) < 0) { - return unit.getMinAddress(); + ListIterator it = searchResults.listIterator(searchResults.size()); + while (it.hasPrevious()) { + InstructionMetadata instr = it.previous(); + CodeUnit cu = listing.getCodeUnitContaining(instr.getAddr()); + if (cu.getMinAddress().compareTo(currentAddress) < 0) { + return cu.getMinAddress(); } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/AnsiRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/AnsiRenderer.java index 5d2231686f..a10b54c0c1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/AnsiRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/AnsiRenderer.java @@ -19,7 +19,9 @@ import java.awt.Color; import javax.swing.text.*; +import generic.theme.GColor; import ghidra.app.plugin.core.interpreter.AnsiParser.AnsiParserHandler; +import ghidra.util.ColorUtils; /** * An object for parsing and rendering ANSI-styled strings into a Swing {@link Document}. @@ -32,22 +34,6 @@ import ghidra.app.plugin.core.interpreter.AnsiParser.AnsiParserHandler; * renderers prevents the corruption of those escape sequences when interleaving the output streams. */ public class AnsiRenderer { - public static final Color BLACK = new Color(0, 0, 0); - public static final Color RED = new Color(194, 54, 33); - public static final Color GREEN = new Color(37, 188, 36); - public static final Color YELLOW = new Color(173, 173, 39); - public static final Color BLUE = new Color(73, 46, 225); - public static final Color MAGENTA = new Color(211, 56, 211); - public static final Color CYAN = new Color(51, 187, 200); - public static final Color WHITE = new Color(203, 204, 205); - public static final Color HI_BLACK = new Color(129, 131, 131); - public static final Color HI_RED = new Color(252, 57, 31); - public static final Color HI_GREEN = new Color(49, 231, 34); - public static final Color HI_YELLOW = new Color(234, 236, 35); - public static final Color HI_BLUE = new Color(88, 51, 255); - public static final Color HI_MAGENTA = new Color(249, 53, 248); - public static final Color HI_CYAN = new Color(20, 240, 240); - public static final Color HI_WHITE = new Color(233, 235, 235); /** * These colors are taken from Terminal.app as documented on Wikipedia as of 26 April 2022. @@ -58,23 +44,23 @@ public class AnsiRenderer { */ private static final Color[] BASIC_COLORS = { // standard colors - BLACK, - RED, - GREEN, - YELLOW, - BLUE, - MAGENTA, - CYAN, - WHITE, + new GColor("color.fg.plugin.interpreter.renderer.color.standard.1"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.2"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.3"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.4"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.5"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.6"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.7"), + new GColor("color.fg.plugin.interpreter.renderer.color.standard.8"), // high intensity colors - HI_BLACK, - HI_RED, - HI_GREEN, - HI_YELLOW, - HI_BLUE, - HI_MAGENTA, - HI_CYAN, - HI_WHITE, + new GColor("color.fg.plugin.interpreter.renderer.color.intense.1"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.2"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.3"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.4"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.5"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.6"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.7"), + new GColor("color.fg.plugin.interpreter.renderer.color.intense.8"), }; /** * This aids the implementation of the 6x6x6 color cube. @@ -98,12 +84,12 @@ public class AnsiRenderer { } /** - * Get the 8-bit ansi color. + * Get the 8-bit ANSI color. * *

- * Colors 0-15 are the {@link AnsiRenderer#BASIC_COLORS: standard + high-intensity. Colors + * Colors 0-15 are the {@link AnsiRenderer#AnsiRenderer}: standard + high-intensity. Colors * 16-231 come from a 6x6x6 RGB cube; see {@link AnsiRenderer#CUBE_STEPS}. Finally, colors - * 232-255 are 24 steps of grayscale. + * 232-255 are 24 steps of gray scale. * * @param v an 8-bit number * @return the ANSI color @@ -117,12 +103,12 @@ public class AnsiRenderer { int b = v % 6; int g = (v / 6) % 6; int r = (v / 36) % 6; - return new Color(CUBE_STEPS[r], CUBE_STEPS[g], CUBE_STEPS[b]); + return ColorUtils.getColor(CUBE_STEPS[r], CUBE_STEPS[g], CUBE_STEPS[b]); } else if (v < 256) { v -= 232; int gray = v * 10 + 8; - return new Color(gray, gray, gray); + return ColorUtils.getColor(gray, gray, gray); } else { /* invalid */ @@ -146,7 +132,7 @@ public class AnsiRenderer { private int handleSGRAttribute(String[] bits, int pos) throws NumberFormatException { int code = Integer.parseInt(bits[pos]); if (code >= 30 && code < 50) { - /* Colour codes */ + /* Color codes */ Object attributeName = (code < 40) ? StyleConstants.Foreground : StyleConstants.Background; int colorCode = code % 10; @@ -172,7 +158,7 @@ public class AnsiRenderer { int r = Integer.parseInt(bits[pos + 2]); int g = Integer.parseInt(bits[pos + 3]); int b = Integer.parseInt(bits[pos + 4]); - attributes.addAttribute(attributeName, new Color(r, g, b)); + attributes.addAttribute(attributeName, ColorUtils.getColor(r, g, b)); return 5; } return 1; @@ -314,6 +300,7 @@ public class AnsiRenderer { * @param document Document to render the string to * @param text A text string which may contain 7-bit ANSI escape codes * @param attributes Current text attributes; may be modified by this function + * @throws BadLocationException if there is an error parsing the text */ public void renderString(StyledDocument document, String text, MutableAttributeSet attributes) throws BadLocationException { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/CodeCompletionWindow.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/CodeCompletionWindow.java index ae2ff6e252..299cd4734b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/CodeCompletionWindow.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/CodeCompletionWindow.java @@ -25,6 +25,7 @@ import javax.swing.border.EmptyBorder; import javax.swing.event.ListDataListener; import docking.widgets.list.GListCellRenderer; +import generic.theme.GThemeDefaults.Colors; import generic.util.WindowUtilities; import ghidra.app.plugin.core.console.CodeCompletion; @@ -37,7 +38,7 @@ import ghidra.app.plugin.core.console.CodeCompletion; public class CodeCompletionWindow extends JDialog { private static final long serialVersionUID = 1L; /* from ReferenceHoverPlugin */ - private static final Color BACKGROUND_COLOR = new Color(255, 255, 230); + private static final Color BACKGROUND_COLOR = Colors.BACKGROUND_TOOLTIP; protected final InterpreterPanel console; protected final JTextPane outputTextField; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterComponentProvider.java index 4db22f295a..d868bfeb9a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterComponentProvider.java @@ -26,18 +26,15 @@ import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; import docking.widgets.OptionDialog; +import generic.theme.GIcon; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.util.HelpLocation; import resources.Icons; -import resources.ResourceManager; import utility.function.Callback; public class InterpreterComponentProvider extends ComponentProviderAdapter implements InterpreterConsole { - private static final String CONSOLE_GIF = "images/monitor.png"; - private static final String CLEAR_GIF = "images/erase16.png"; - private InterpreterPanel panel; private InterpreterConnection interpreter; private List firstActivationCallbacks; @@ -57,7 +54,7 @@ public class InterpreterComponentProvider extends ComponentProviderAdapter Icon icon = interpreter.getIcon(); if (icon == null) { - icon = ResourceManager.loadImage(CONSOLE_GIF); + icon = new GIcon("icon.plugin.interpreter.provider"); } setIcon(icon); @@ -73,7 +70,7 @@ public class InterpreterComponentProvider extends ComponentProviderAdapter } }; clearAction.setDescription("Clear Interpreter"); - clearAction.setToolBarData(new ToolBarData(ResourceManager.loadImage(CLEAR_GIF), null)); + clearAction.setToolBarData(new ToolBarData(Icons.CLEAR_ICON, null)); clearAction.setEnabled(true); addLocalAction(clearAction); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java index cc093ba06c..0d970baac9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterConnection.java @@ -17,7 +17,7 @@ package ghidra.app.plugin.core.interpreter; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import ghidra.app.plugin.core.console.CodeCompletion; @@ -38,7 +38,7 @@ public interface InterpreterConnection { * * @return The icon associated with the interpreter. Null if default icon is desired. */ - public ImageIcon getIcon(); + public Icon getIcon(); /** * Gets a {@link List} of {@link CodeCompletion code completions} for the given command. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterPanel.java index bf7f1f7ff1..6a9b7be33f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/interpreter/InterpreterPanel.java @@ -28,12 +28,15 @@ import javax.swing.text.*; import docking.DockingUtils; import docking.actions.KeyBindingUtils; +import generic.theme.GColor; +import generic.theme.Gui; import generic.util.WindowUtilities; import ghidra.app.plugin.core.console.CodeCompletion; import ghidra.framework.options.OptionsChangeListener; import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.PluginTool; -import ghidra.util.*; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; public class InterpreterPanel extends JPanel implements OptionsChangeListener { @@ -41,13 +44,14 @@ public class InterpreterPanel extends JPanel implements OptionsChangeListener { private static final String COMPLETION_WINDOW_TRIGGER_DESCRIPTION = "The key binding used to show the auto-complete window " + "(for those consoles that have auto-complete)."; + private static final String FONT_ID = "font.plugin.console"; private static final String FONT_OPTION_LABEL = "Font"; private static final String FONT_DESCRIPTION = "This is the font that will be used in the Console. " + "Double-click the font example to change it."; - private static final Color NORMAL_COLOR = Color.black; - private static final Color ERROR_COLOR = Color.red; + private static final Color NORMAL_COLOR = new GColor("color.fg.interpreterpanel"); + private static final Color ERROR_COLOR = new GColor("color.fg.interpreterpanel.error"); public enum TextType { STDOUT, STDERR, STDIN; @@ -68,8 +72,6 @@ public class InterpreterPanel extends JPanel implements OptionsChangeListener { private PrintWriter outWriter; private PrintWriter errWriter; - private Font basicFont = getBasicFont(); - private Font basicBoldFont = getBoldFont(basicFont); private SimpleAttributeSet STDOUT_SET; private SimpleAttributeSet STDERR_SET; private SimpleAttributeSet STDIN_SET; @@ -81,14 +83,6 @@ public class InterpreterPanel extends JPanel implements OptionsChangeListener { private boolean caretGuard = true; private PluginTool tool; - private static Font getBasicFont() { - return new Font(Font.MONOSPACED, Font.PLAIN, 20); - } - - private static Font getBoldFont(Font font) { - return font.deriveFont(Font.BOLD); - } - private static SimpleAttributeSet createAttributes(Font font, Color color) { SimpleAttributeSet attributeSet = new SimpleAttributeSet(); attributeSet.addAttribute(StyleConstants.FontFamily, font.getFamily()); @@ -368,15 +362,14 @@ public class InterpreterPanel extends JPanel implements OptionsChangeListener { } } - private void updateFontAttributes(Font newFont) { - basicFont = newFont; - basicBoldFont = getBoldFont(newFont); - STDOUT_SET = createAttributes(basicFont, NORMAL_COLOR); - STDERR_SET = createAttributes(basicFont, ERROR_COLOR); - STDIN_SET = createAttributes(basicBoldFont, NORMAL_COLOR); + private void updateFontAttributes(Font font) { + Font boldFont = font.deriveFont(Font.BOLD); + STDOUT_SET = createAttributes(font, NORMAL_COLOR); + STDERR_SET = createAttributes(font, ERROR_COLOR); + STDIN_SET = createAttributes(boldFont, NORMAL_COLOR); - setTextPaneFont(inputTextPane, basicBoldFont); - setTextPaneFont(promptTextPane, basicFont); + setTextPaneFont(inputTextPane, boldFont); + setTextPaneFont(promptTextPane, font); setPrompt(promptTextPane.getText()); } @@ -387,13 +380,13 @@ public class InterpreterPanel extends JPanel implements OptionsChangeListener { HelpLocation help = new HelpLocation(getName(), "ConsolePlugin"); options.setOptionsHelpLocation(help); - options.registerOption(FONT_OPTION_LABEL, basicFont, help, FONT_DESCRIPTION); + options.registerThemeFontBinding(FONT_OPTION_LABEL, FONT_ID, help, + FONT_DESCRIPTION); options.registerOption(COMPLETION_WINDOW_TRIGGER_LABEL, CompletionWindowTrigger.TAB, help, COMPLETION_WINDOW_TRIGGER_DESCRIPTION); - basicFont = options.getFont(FONT_OPTION_LABEL, basicFont); - basicFont = SystemUtilities.adjustForFontSizeOverride(basicFont); - updateFontAttributes(basicFont); + Font font = Gui.getFont(FONT_ID); + updateFontAttributes(font); completionWindowTrigger = options.getEnum(COMPLETION_WINDOW_TRIGGER_LABEL, CompletionWindowTrigger.TAB); @@ -411,8 +404,8 @@ public class InterpreterPanel extends JPanel implements OptionsChangeListener { public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { if (optionName.equals(FONT_OPTION_LABEL)) { - basicFont = SystemUtilities.adjustForFontSizeOverride((Font) newValue); - updateFontAttributes(basicFont); + Font font = Gui.getFont(FONT_ID); + updateFontAttributes(font); } else if (optionName.equals(COMPLETION_WINDOW_TRIGGER_LABEL)) { completionWindowTrigger = (CompletionWindowTrigger) newValue; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelHistoryPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelHistoryPanel.java index cd60813c14..b58a5832b2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelHistoryPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/label/LabelHistoryPanel.java @@ -27,6 +27,7 @@ import javax.swing.table.TableColumnModel; import docking.widgets.GenericDateCellRenderer; import docking.widgets.table.GTableCellRenderer; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.Gui; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.LabelHistory; import ghidra.util.table.GhidraTable; @@ -126,16 +127,11 @@ class LabelHistoryPanel extends JPanel { private Font monoFont; - LabelCellRenderer() { - Font f = getFont(); - monoFont = new Font("monospaced", f.getStyle(), f.getSize()); - } - @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { Component c = super.getTableCellRendererComponent(data); - c.setFont(monoFont); + c.setFont(Gui.getFont("font.monospaced")); return c; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java index 1df241ba0f..0c99f671b6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java @@ -35,6 +35,7 @@ import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.program.util.MarkerLocation; import ghidra.program.util.ProgramLocation; +import ghidra.util.ColorUtils; import ghidra.util.Swing; import ghidra.util.datastruct.SortedRangeList; @@ -262,7 +263,7 @@ abstract class MarkerSetImpl implements MarkerSet { int red = (c.getRed() + 3 * COLOR_VALUE) / 4; int green = (c.getGreen() + 3 * COLOR_VALUE) / 4; int blue = (c.getBlue() + 3 * COLOR_VALUE) / 4; - return new Color(red, green, blue); + return ColorUtils.getColor(red, green, blue); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java index 5e241effab..e055d7bb98 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java @@ -31,6 +31,7 @@ import ghidra.program.model.listing.Program; import ghidra.program.util.MarkerLocation; import ghidra.util.datastruct.Range; import ghidra.util.datastruct.SortedRangeList; +import resources.Icons; import resources.ResourceManager; class PointMarkerSet extends MarkerSetImpl { @@ -61,7 +62,7 @@ class PointMarkerSet extends MarkerSetImpl { colorBackground, markerColor, isPreferred); if (icon == null) { - icon = ResourceManager.loadImage("images/warning.png"); + icon = Icons.WARNING_ICON; } ImageIcon imageIcon = ResourceManager.getScaledIcon(icon, 16, 16, Image.SCALE_SMOOTH); image = imageIcon.getImage(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java index 07d3eb5c43..619dd824f3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java @@ -29,6 +29,7 @@ import docking.action.ToolBarData; import docking.widgets.label.GLabel; import docking.widgets.table.*; import docking.widgets.textfield.GValidatedTextField.MaxLengthField; +import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.framework.model.DomainFile; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -40,7 +41,6 @@ import ghidra.program.model.mem.MemoryBlockType; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.table.GhidraTable; -import resources.ResourceManager; /** * Provider for the memory map Component. @@ -65,16 +65,6 @@ class MemoryMapProvider extends ComponentProviderAdapter { private MemoryMapPlugin plugin = null; - private final static String ADD_IMAGE = "images/Plus.png"; - private final static String MOVE_IMAGE = "images/move.png"; - private final static String SPLIT_IMAGE = "images/verticalSplit.png"; - private final static String EXPAND_UP_IMAGE = "images/collapse.gif"; - private final static String EXPAND_DOWN_IMAGE = "images/expand.gif"; - private final static String MERGE_IMAGE = "images/Merge.png"; - private final static String DELETE_IMAGE = "images/edit-delete.png"; - private final static String IMAGE_BASE = "images/house.png"; - final static String MEMORY_IMAGE = "images/memory16.gif"; - private Program program; private MemoryMapManager memManager; @@ -84,7 +74,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { setHelpLocation(new HelpLocation(plugin.getName(), getName())); memManager = plugin.getMemoryMapManager(); - setIcon(ResourceManager.loadImage(MEMORY_IMAGE)); + setIcon(new GIcon("icon.plugin.memorymap.provider")); addToToolbar(); mainPanel = buildMainPanel(); addToTool(); @@ -185,7 +175,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { } private void addLocalActions() { - ImageIcon addImage = ResourceManager.loadImage(ADD_IMAGE); + Icon addImage = new GIcon("icon.plugin.memorymap.add"); addAction = new MemoryMapAction("Add Block", addImage) { @Override @@ -200,7 +190,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { addAction.setDescription("Add a new block to memory"); tool.addLocalAction(this, addAction); - ImageIcon moveImage = ResourceManager.loadImage(MOVE_IMAGE); + Icon moveImage = new GIcon("icon.plugin.memorymap.move"); moveAction = new MemoryMapAction("Move Block", moveImage) { @Override public void actionPerformed(ActionContext context) { @@ -213,7 +203,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { moveAction.setDescription("Move a block to another address"); tool.addLocalAction(this, moveAction); - ImageIcon splitImage = ResourceManager.loadImage(SPLIT_IMAGE); + Icon splitImage = new GIcon("icon.plugin.memorymap.split"); splitAction = new MemoryMapAction("Split Block", splitImage) { @Override @@ -228,7 +218,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { splitAction.setDescription("Split a block"); tool.addLocalAction(this, splitAction); - ImageIcon expandUpImage = ResourceManager.loadImage(EXPAND_UP_IMAGE); + Icon expandUpImage = new GIcon("icon.plugin.memorymap.expand.up"); expandUpAction = new MemoryMapAction("Expand Block Up", expandUpImage) { @Override @@ -242,7 +232,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { expandUpAction.setDescription("Expand block by setting new start address"); tool.addLocalAction(this, expandUpAction); - ImageIcon expandDownImage = ResourceManager.loadImage(EXPAND_DOWN_IMAGE); + Icon expandDownImage = new GIcon("icon.plugin.memorymap.expand.down"); expandDownAction = new MemoryMapAction("Expand Block Down", expandDownImage) { @Override @@ -256,7 +246,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { expandDownAction.setDescription("Expand block by setting new end address"); tool.addLocalAction(this, expandDownAction); - ImageIcon mergeImage = ResourceManager.loadImage(MERGE_IMAGE); + Icon mergeImage = new GIcon("icon.plugin.memorymap.merge"); mergeAction = new MemoryMapAction("Merge Blocks", mergeImage) { @Override public void actionPerformed(ActionContext context) { @@ -269,7 +259,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { mergeAction.setDescription("Merge blocks into a single block"); tool.addLocalAction(this, mergeAction); - ImageIcon deleteImage = ResourceManager.loadImage(DELETE_IMAGE); + Icon deleteImage = new GIcon("icon.plugin.memorymap.delete"); deleteAction = new MemoryMapAction("Delete Block", deleteImage) { @Override public void actionPerformed(ActionContext context) { @@ -282,7 +272,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { deleteAction.setDescription("Delete a block"); tool.addLocalAction(this, deleteAction); - ImageIcon setBaseIcon = ResourceManager.loadImage(IMAGE_BASE); + Icon setBaseIcon = new GIcon("icon.plugin.memorymap.image.base"); setBaseAction = new MemoryMapAction("Set Image Base", setBaseIcon) { @Override public void actionPerformed(ActionContext context) { @@ -687,7 +677,7 @@ class MemoryMapProvider extends ComponentProviderAdapter { } private abstract class MemoryMapAction extends DockingAction { - MemoryMapAction(String name, ImageIcon icon) { + MemoryMapAction(String name, Icon icon) { super(name, plugin.getName()); this.setToolBarData(new ToolBarData(icon, null)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/FontAdjustPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/FontAdjustPlugin.java new file mode 100644 index 0000000000..af5cc78ffb --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/FontAdjustPlugin.java @@ -0,0 +1,70 @@ +/* ### + * 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 ghidra.app.plugin.core.misc; + +import docking.ActionContext; +import docking.ComponentProvider; +import docking.action.builder.ActionBuilder; +import ghidra.app.CorePluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Manages the markers to display areas where changes have occurred + */ +@PluginInfo( //@formatter:off + status = PluginStatus.RELEASED, + packageName = CorePluginPackage.NAME, + category = PluginCategoryNames.MISC, + shortDescription = "Provides generic actions for increasing/decreasing fonts.", + description = "This plugin provides actions for increasing fonts used by component providers. "+ + "ComponentProviders can either override the \"changeFontSize()\" method or register a" + + "theme font id that can be automatically adjusted." +) //@formatter:on + +public class FontAdjustPlugin extends Plugin { + public FontAdjustPlugin(PluginTool tool) { + + super(tool); + + new ActionBuilder("Increment Font", "tool") + .keyBinding("ctrl EQUALS") + .onAction(this::incrementFont) + .buildAndInstall(tool); + + new ActionBuilder("Decrement Font", "tool") + .keyBinding("ctrl MINUS") + .onAction(this::decrementFont) + .buildAndInstall(tool); + + } + + private void incrementFont(ActionContext context) { + ComponentProvider provider = context.getComponentProvider(); + if (provider != null) { + provider.adjustFontSize(true); + } + } + + private void decrementFont(ActionContext context) { + ComponentProvider provider = context.getComponentProvider(); + if (provider != null) { + provider.adjustFontSize(false); + } + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java index 24aaf0a191..b375368cf5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java @@ -24,11 +24,13 @@ package ghidra.app.plugin.core.misc; import java.awt.Color; import java.io.IOException; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.ProgramPlugin; @@ -50,7 +52,6 @@ import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.TaskMonitor; import ghidra.util.worker.Job; import ghidra.util.worker.Worker; -import resources.ResourceManager; /** * Manages the markers to display areas where changes have occurred @@ -73,6 +74,15 @@ public class MyProgramChangesDisplayPlugin extends ProgramPlugin implements Doma private final static int OTHER_CHANGES_PRIORITY = MarkerService.CHANGE_PRIORITY + 2; private final static int CONFLICT_PRIORITY = MarkerService.CHANGE_PRIORITY + 3; + private static final Color BG_COLOR_MARKER_UNSAVED = + new GColor("color.bg.plugin.myprogramchangesdisplay.markers.changes.unsaved"); + private static final Color BG_COLOR_MARKER_CONFLICTING = + new GColor("color.bg.plugin.myprogramchangesdisplay.markers.changes.conflicting"); + private static final Color BG_COLOR_MARKER_LATEST = + new GColor("color.bg.plugin.myprogramchangesdisplay.markers.changes.latest.version"); + private static final Color BG_COLOR_MARKER_NOT_CHECKED_IN = + new GColor("color.bg.plugin.myprogramchangesdisplay.markers.changes.not.checked.in"); + private MarkerService markerService; private MarkerSet currentMyChangeMarks; // my changes since last save @@ -110,7 +120,7 @@ public class MyProgramChangesDisplayPlugin extends ProgramPlugin implements Doma private void createActions() { - ImageIcon icon = ResourceManager.loadImage("images/vcMerge.png"); + Icon icon = new GIcon("icon.plugin.myprogramchanges.merge"); mergeAction = new DockingAction("Update", getName()) { @Override public void actionPerformed(ActionContext context) { @@ -127,7 +137,7 @@ public class MyProgramChangesDisplayPlugin extends ProgramPlugin implements Doma mergeAction.setDescription("Update checked out file with latest version"); mergeAction.setHelpLocation(new HelpLocation("VersionControl", mergeAction.getName())); - icon = ResourceManager.loadImage("images/vcCheckIn.png"); + icon = new GIcon("icon.plugin.myprogramchanges.checkin"); checkInAction = new DockingAction("CheckIn", getName()) { @Override public void actionPerformed(ActionContext context) { @@ -191,7 +201,7 @@ public class MyProgramChangesDisplayPlugin extends ProgramPlugin implements Doma private void createMarkerSets(Program program) { currentMyChangeMarks = markerService.createAreaMarker("Changes: Unsaved", "My changes not yet saved", program, - MY_CHANGE_PRIORITY, true, true, false, Color.darkGray); + MY_CHANGE_PRIORITY, true, true, false, BG_COLOR_MARKER_UNSAVED); if (program.getDomainFile().isCheckedOut()) { trackServerChanges(program); @@ -201,15 +211,15 @@ public class MyProgramChangesDisplayPlugin extends ProgramPlugin implements Doma private void trackServerChanges(Program program) { currentChangesSinceCheckoutMarks = markerService.createAreaMarker("Changes: Not Checked-In", "My saved changes made since I checked it out", program, CHANGES_SINCE_CO_PRIORITY, - true, true, false, Color.GREEN); + true, true, false, BG_COLOR_MARKER_NOT_CHECKED_IN); currentOtherChangeMarks = markerService.createAreaMarker("Changes: Latest Version", "Changes made by others to this program since I checked it out", program, - OTHER_CHANGES_PRIORITY, true, true, false, Color.BLUE); + OTHER_CHANGES_PRIORITY, true, true, false, BG_COLOR_MARKER_LATEST); currentConflictChangeMarks = markerService.createAreaMarker("Changes: Conflicting", "Changes made by others to this program that conflict with my changes", program, - CONFLICT_PRIORITY, true, true, false, Color.RED); + CONFLICT_PRIORITY, true, true, false, BG_COLOR_MARKER_CONFLICTING); } private void disposeMarkerSets(Program program) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RegisterField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RegisterField.java index fa4d3f27ab..6431da816b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RegisterField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/RegisterField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,61 +23,63 @@ import javax.swing.*; import javax.swing.event.ChangeListener; import javax.swing.text.*; -/** - * - */ +import generic.theme.GThemeDefaults.Colors; + public class RegisterField extends JTextField { -// private static Color UNSET_COLOR = new Color(204,0,204); + private int bitSize; private Long currentValue; private long maxValue; - private PlainDocument doc; + private PlainDocument doc; private boolean inFocus; private boolean skipFilter; private ChangeListener listener; - private Color noValueColor = Color.LIGHT_GRAY; - private Color valueColor = Color.BLACK; - private boolean useNoValue; - /** - * Constructor for RegisterField. - */ - public RegisterField(int bitSize, Long initialValue) { - this(bitSize, initialValue, true); - } - - public RegisterField(int bitSize, Long initialValue, boolean useNoValue) { - this.useNoValue = useNoValue; - setBitSize( bitSize ); - - doc = new PlainDocument(); - doc.setDocumentFilter(new MyDocFilter()); - this.setDocument(doc); - doSetValue(initialValue); + private Color noValueColor = Colors.FOREGROUND_DISABLED; + private Color valueColor = Colors.FOREGROUND; + private boolean useNoValue; - this.addFocusListener(new FocusListener() { - public void focusGained(FocusEvent ev) { + public RegisterField(int bitSize, Long initialValue) { + this(bitSize, initialValue, true); + } + + public RegisterField(int bitSize, Long initialValue, boolean useNoValue) { + this.useNoValue = useNoValue; + setBitSize(bitSize); + + doc = new PlainDocument(); + doc.setDocumentFilter(new MyDocFilter()); + this.setDocument(doc); + doSetValue(initialValue); + + this.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent ev) { inFocus = true; doSetValue(currentValue); - } + } - public void focusLost(FocusEvent ev) { - inFocus = false; + @Override + public void focusLost(FocusEvent ev) { + inFocus = false; doSetValue(currentValue); - } - }); - } + } + }); + } + public Long getValue() { return currentValue; } - + public void setNoValueColor(Color c) { noValueColor = c; updateColor(); } + public void setValueColor(Color c) { valueColor = c; updateColor(); } + private void updateColor() { if (inFocus || currentValue != null) { setForeground(valueColor); @@ -89,104 +90,113 @@ public class RegisterField extends JTextField { setHorizontalAlignment(CENTER); } } - public void setBitSize( int bitSize ) { - this.bitSize = bitSize; - boolean isValid = bitSize >= 1 && bitSize < 64; + public void setBitSize(int bitSize) { + this.bitSize = bitSize; - this.setEditable(isValid); - this.setEnabled(isValid); + boolean isValid = bitSize >= 1 && bitSize < 64; - this.useNoValue = true; + this.setEditable(isValid); + this.setEnabled(isValid); - if (isValid) { - this.maxValue = (1L << bitSize) - 1; - } - else { - skipFilter = true; - this.maxValue = 1; - } + this.useNoValue = true; - /// if the value is no longer valid, then clear the value - if ( !isValidValue( getValue() ) ) { - doSetValue( null ); - } - } - public void setValue(Long value) { + if (isValid) { + this.maxValue = (1L << bitSize) - 1; + } + else { + skipFilter = true; + this.maxValue = 1; + } + + /// if the value is no longer valid, then clear the value + if (!isValidValue(getValue())) { + doSetValue(null); + } + } + + public void setValue(Long value) { if (isEqual(value, currentValue)) { return; } doSetValue(value); - } - private void doSetValue(Long value) { - if (value == null) { - if (inFocus) { + } + + private void doSetValue(Long value) { + if (value == null) { + if (inFocus) { setTextField(""); - } - else { - if (useNoValue) { + } + else { + if (useNoValue) { setTextField("-- No Value --"); - } - else { - setTextField(""); - } - } - } - else { - setTextField("0x"+Long.toHexString(value.longValue())); - } - currentValue = value; + } + else { + setTextField(""); + } + } + } + else { + setTextField("0x" + Long.toHexString(value.longValue())); + } + currentValue = value; updateColor(); - } - private boolean isEqual(Long l1, Long l2) { - if (l1 != null) { - return l1.equals(l2); - } - else if (l2 != null) { - return false; - } - return true; - } + } + + private boolean isEqual(Long l1, Long l2) { + if (l1 != null) { + return l1.equals(l2); + } + else if (l2 != null) { + return false; + } + return true; + } + private void setTextField(String text) { - if ( doc == null ) { - return; - } + if (doc == null) { + return; + } skipFilter = true; - try { - doc.replace(0, doc.getLength(), text, null); - } - catch (BadLocationException e) {} + try { + doc.replace(0, doc.getLength(), text, null); + } + catch (BadLocationException e) { + // ignore + } skipFilter = false; } + public void setChangeListener(ChangeListener listener) { this.listener = listener; } + private boolean processText() { String text = getText(); - - if (text.length() == 0){ + + if (text.length() == 0) { if (currentValue != null) { currentValue = null; notifyListeners(); } return true; } - + if (text.equals("0x") || text.equals("0X")) { - if ((currentValue == null) || (currentValue.longValue() != 0)) { - currentValue = new Long(0); + if ((currentValue == null) || (currentValue.longValue() != 0)) { + currentValue = 0L; notifyListeners(); } return true; } try { if (!text.startsWith("0x") && !text.startsWith("0X")) { - while(text.length() > 1 && text.charAt(0)== '0') { + while (text.length() > 1 && text.charAt(0) == '0') { text = text.substring(1); - } + } } - Long newValue = Long.decode(text); - if ( isValidValue( newValue ) ) { + Long newValue = Long.decode(text); + if (isValidValue(newValue)) { if (!newValue.equals(currentValue)) { currentValue = newValue; notifyListeners(); @@ -194,46 +204,42 @@ public class RegisterField extends JTextField { return true; } } - catch(Exception e) { + catch (Exception e) { + // handled by using beep below } + Toolkit.getDefaultToolkit().beep(); return false; } - private boolean isValidValue(Long value) { - if ( value == null ) { - return false; - } - long l = value.longValue(); - return (l >= 0) && (l <= maxValue); - } + private boolean isValidValue(Long value) { + if (value == null) { + return false; + } + long l = value.longValue(); + return (l >= 0) && (l <= maxValue); + } - class MyDocFilter extends DocumentFilter { - /** - * @see javax.swing.text.DocumentFilter#insertString(FilterBypass, int, String, AttributeSet) - */ - @Override - public void insertString(FilterBypass fb, int offset, String string, - AttributeSet attr) throws BadLocationException { + + @Override + public void insertString(FilterBypass fb, int offset, String string, + AttributeSet attr) throws BadLocationException { if (skipFilter) { super.insertString(fb, offset, string, attr); return; } String oldText = getText(); - fb.insertString(offset, string, attr); + fb.insertString(offset, string, attr); if (!processText()) { fb.replace(0, doc.getLength(), oldText, attr); } - } + } - /** - * @see javax.swing.text.DocumentFilter#remove(FilterBypass, int, int) - */ - @Override - public void remove(FilterBypass fb, int offset, int length) - throws BadLocationException { + @Override + public void remove(FilterBypass fb, int offset, int length) + throws BadLocationException { if (skipFilter) { super.remove(fb, offset, length); return; @@ -244,48 +250,45 @@ public class RegisterField extends JTextField { if (!processText()) { fb.replace(0, doc.getLength(), oldText, null); } - } + } - /** - * @see javax.swing.text.DocumentFilter#replace(FilterBypass, int, int, String, AttributeSet) - */ - @Override - public void replace(FilterBypass fb, int offset, int length, - String text, AttributeSet attrs) throws BadLocationException { + @Override + public void replace(FilterBypass fb, int offset, int length, + String text, AttributeSet attrs) throws BadLocationException { if (skipFilter) { super.replace(fb, offset, length, text, attrs); return; } String oldText = getText(); - fb.replace(offset, length, text, attrs); + fb.replace(offset, length, text, attrs); if (!processText()) { fb.replace(0, doc.getLength(), oldText, attrs); } - } - } + } + } public static void main(String[] args) { JFrame f = new JFrame("Test"); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JTextField("123"), BorderLayout.SOUTH); - RegisterField rf = new RegisterField(1, new Long(1)); + RegisterField rf = new RegisterField(1, 1L); panel.add(rf, BorderLayout.CENTER); f.getContentPane().add(panel); f.pack(); f.setVisible(true); - } - + } + private void notifyListeners() { if (listener != null) { - listener.stateChanged( null ); + listener.stateChanged(null); } - } + } + public int getBitSize() { return bitSize; } + public Color getValueColor() { return valueColor; } } - - diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/AbstractNextPreviousAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/AbstractNextPreviousAction.java index c5700ad5d6..f58852193e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/AbstractNextPreviousAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/AbstractNextPreviousAction.java @@ -42,7 +42,7 @@ import resources.*; public abstract class AbstractNextPreviousAction extends NavigatableContextAction { private static final Icon INVERTED_OVERLAY_ICON = - ImageUtils.makeTransparent(ResourceManager.loadImage("images/dialog-cancel.png"), .5f); + ImageUtils.makeTransparent(Icons.NOT_ALLOWED_ICON, .5f); private boolean isForward = true; private PluginTool tool; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextHighlightedRangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextHighlightedRangeAction.java index 9c2b667386..a178fc9fb4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextHighlightedRangeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextHighlightedRangeAction.java @@ -20,6 +20,7 @@ import java.awt.event.KeyEvent; import docking.DockingUtils; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.nav.NextRangeAction; import ghidra.app.plugin.PluginCategoryNames; @@ -27,19 +28,20 @@ import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.PluginTool; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class NextHighlightedRangeAction extends NextRangeAction { + private static final GIcon ICON = new GIcon("icon.plugin.navigation.highlight.range.next"); + public NextHighlightedRangeAction(PluginTool tool, String owner, NavigationOptions navOptions) { super(tool, "Next Highlighted Range", owner, navOptions); setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, - "Next Highlight Range" }, ResourceManager.loadImage("images/NextHighlightBlock16.gif"), + "Next Highlight Range" }, ICON, PluginCategoryNames.NAVIGATION, MenuData.NO_MNEMONIC, NextPrevHighlightRangePlugin.ACTION_SUB_GROUP)); setToolBarData(new ToolBarData( - ResourceManager.loadImage("images/NextHighlightBlock16.gif"), + ICON, ToolConstants.TOOLBAR_GROUP_THREE, NextPrevHighlightRangePlugin.ACTION_SUB_GROUP)); setKeyBindingData( new KeyBindingData(KeyEvent.VK_0, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevAddressPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevAddressPlugin.java index 9830bc6ba9..2745dfcb4b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevAddressPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevAddressPlugin.java @@ -21,12 +21,12 @@ import java.util.ArrayList; import java.util.List; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.ActionContext; import docking.action.*; import docking.menu.MultiActionDockingAction; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.context.NavigatableActionContext; import ghidra.app.context.ProgramActionContext; @@ -46,7 +46,6 @@ import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.SymbolTable; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * NextPrevAddressPlugin allows the user to go back and forth in @@ -65,8 +64,8 @@ import resources.ResourceManager; public class NextPrevAddressPlugin extends Plugin { private static final String HISTORY_MENU_GROUP = "1_Menu_History_Group"; - private static ImageIcon previousIcon = ResourceManager.loadImage("images/left.png"); - private static ImageIcon nextIcon = ResourceManager.loadImage("images/right.png"); + private static Icon PREVIOUS_ICON = new GIcon("icon.plugin.navigation.location.previous"); + private static Icon NEXT_ICON = new GIcon("icon.plugin.navigation.location.next"); private static final String PREVIOUS_ACTION_NAME = "Previous Location in History"; private static final String NEXT_ACTION_NAME = "Next Location in History"; @@ -301,7 +300,7 @@ public class NextPrevAddressPlugin extends Plugin { super(name, owner); this.isNext = isNext; - setToolBarData(new ToolBarData(isNext ? nextIcon : previousIcon, + setToolBarData(new ToolBarData(isNext ? NEXT_ICON : PREVIOUS_ICON, ToolConstants.TOOLBAR_GROUP_TWO)); setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, name)); int keycode = isNext ? KeyEvent.VK_RIGHT : KeyEvent.VK_LEFT; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPlugin.java index f136f996ac..424da1777d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPlugin.java @@ -23,6 +23,7 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import generic.util.image.ImageUtils; import ghidra.app.CorePluginPackage; import ghidra.app.context.NavigatableActionContext; @@ -33,7 +34,7 @@ import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.util.HelpLocation; -import resources.ResourceManager; +import resources.Icons; /** * The NextPrevCodeUnitPlugin generates a GoTo event based on where the cursor @@ -135,9 +136,9 @@ public class NextPrevCodeUnitPlugin extends Plugin { private class InvertStateAction extends ToggleDockingAction { private final Icon INVERTED_ICON_OFF = ImageUtils.makeTransparent( - ResourceManager.loadImage("images/dialog-cancel.png")); + Icons.NOT_ALLOWED_ICON); private final Icon INVERTED_ICON_ON = ImageUtils.makeTransparent( - ResourceManager.loadImage("images/dialog-cancel.png"), .8f); + Icons.NOT_ALLOWED_ICON, .8f); private boolean isInverted = false; public InvertStateAction(String subGroup) { @@ -146,10 +147,7 @@ public class NextPrevCodeUnitPlugin extends Plugin { setToolBarData(new ToolBarData(INVERTED_ICON_OFF, ToolConstants.TOOLBAR_GROUP_FOUR, subGroup)); - // TODO add help entry setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, getName())); - - // TODO setDescriptoin("..."); setSelected(false); addToWindowWhen(NavigatableActionContext.class); @@ -169,8 +167,8 @@ public class NextPrevCodeUnitPlugin extends Plugin { } private class ToggleDirectionAction extends NavigatableContextAction { - private final Icon FORWARD_ICON = ResourceManager.loadImage("images/down.png"); - private final Icon BACKWARD_ICON = ResourceManager.loadImage("images/up.png"); + private final Icon FORWARD_ICON = new GIcon("icon.down"); + private final Icon BACKWARD_ICON = new GIcon("icon.up"); private boolean isForward = true; ToggleDirectionAction(String subGroup) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousBookmarkAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousBookmarkAction.java index c72345c884..d002ecc7dc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousBookmarkAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousBookmarkAction.java @@ -18,7 +18,8 @@ package ghidra.app.plugin.core.navigation; import java.awt.event.*; import java.util.Iterator; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.KeyStroke; import docking.ActionContext; import docking.action.*; @@ -26,6 +27,7 @@ import docking.menu.ActionState; import docking.menu.MultiStateDockingAction; import docking.tool.ToolConstants; import docking.widgets.EventTrigger; +import generic.theme.GIcon; import generic.util.image.ImageUtils; import ghidra.app.context.ListingActionContext; import ghidra.app.context.NavigatableActionContext; @@ -45,26 +47,21 @@ public class NextPreviousBookmarkAction extends MultiStateDockingAction public static final String ALL_BOOKMARK_TYPES = "All Bookmark Types"; private static final Icon INVERTED_OVERLAY_ICON = - ImageUtils.makeTransparent(ResourceManager.loadImage("images/dialog-cancel.png"), .5f); + ImageUtils.makeTransparent(Icons.NOT_ALLOWED_ICON, .5f); private PluginTool tool; private boolean isForward = true; private boolean isInverted; - private static final ImageIcon BOOKMARK_ICON = ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/B.gif"), 16, 16); - private static final ImageIcon BOOKMARK_ANALYSIS_ICON = - ResourceManager.loadImage("images/applications-system.png"); - private static final ImageIcon BOOKMARK_ERROR_ICON = - ResourceManager.loadImage("images/edit-delete.png"); - private static final ImageIcon BOOKMARK_INFO_ICON = - ResourceManager.loadImage("images/information.png"); - private static final ImageIcon BOOKMARK_NOTE_ICON = - ResourceManager.loadImage("images/notes.gif"); - private static final ImageIcon BOOKMARK_WARNING_ICON = - ResourceManager.loadImage("images/warning.png"); - private static final ImageIcon BOOKMARK_UNKNOWN_ICON = - ResourceManager.loadImage("images/unknown.gif"); + //@formatter:off + private static final Icon BOOKMARK_ICON = new GIcon("icon.plugin.navigation.bookmark"); + private static final Icon BOOKMARK_ANALYSIS_ICON = new GIcon("icon.plugin.navigation.bookmark.analysis"); + private static final Icon BOOKMARK_ERROR_ICON = new GIcon("icon.plugin.navigation.bookmark.error"); + private static final Icon BOOKMARK_INFO_ICON = new GIcon("icon.plugin.navigation.bookmark.info"); + private static final Icon BOOKMARK_NOTE_ICON = new GIcon("icon.plugin.navigation.bookmark.note"); + private static final Icon BOOKMARK_WARNING_ICON = new GIcon("icon.plugin.navigation.bookmark.warning"); + private static final Icon BOOKMARK_UNKNOWN_ICON = new GIcon("icon.plugin.navigation.bookmark.unknown"); + //@formatter:on public NextPreviousBookmarkAction(PluginTool tool, String owner, String subGroup) { super("Next Bookmark", owner); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousDefinedDataAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousDefinedDataAction.java index 9e3a4214c2..112fa274f4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousDefinedDataAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousDefinedDataAction.java @@ -21,15 +21,17 @@ import java.awt.event.KeyEvent; import javax.swing.Icon; import javax.swing.KeyStroke; +import generic.theme.GIcon; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class NextPreviousDefinedDataAction extends AbstractNextPreviousAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.data"); + public NextPreviousDefinedDataAction(PluginTool tool, String owner, String subGroup) { super(tool, "Next Data", owner, subGroup); } @@ -41,7 +43,7 @@ public class NextPreviousDefinedDataAction extends AbstractNextPreviousAction { @Override protected Icon getIcon() { - return ResourceManager.loadImage("images/D.gif"); + return ICON; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousFunctionAction.java index 05ab11ae15..208785c82a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousFunctionAction.java @@ -21,6 +21,7 @@ import java.awt.event.KeyEvent; import javax.swing.Icon; import javax.swing.KeyStroke; +import generic.theme.GIcon; import ghidra.app.nav.Navigatable; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.PluginTool; @@ -30,17 +31,18 @@ import ghidra.program.model.listing.*; import ghidra.program.util.FunctionSignatureFieldLocation; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class NextPreviousFunctionAction extends AbstractNextPreviousAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.function"); + public NextPreviousFunctionAction(PluginTool tool, String owner, String subGroup) { super(tool, "Next Function", owner, subGroup); } @Override protected Icon getIcon() { - return ResourceManager.loadImage("images/F.gif"); + return ICON; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousInstructionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousInstructionAction.java index 62149fd9a1..cdae9cdaef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousInstructionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousInstructionAction.java @@ -21,22 +21,24 @@ import java.awt.event.KeyEvent; import javax.swing.Icon; import javax.swing.KeyStroke; +import generic.theme.GIcon; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class NextPreviousInstructionAction extends AbstractNextPreviousAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.instruction"); + public NextPreviousInstructionAction(PluginTool tool, String owner, String subGroup) { super(tool, "Next Instruction", owner, subGroup); } @Override protected Icon getIcon() { - return ResourceManager.loadImage("images/I.gif"); + return ICON; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousLabelAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousLabelAction.java index e73bc6233b..975287a9c7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousLabelAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousLabelAction.java @@ -21,6 +21,7 @@ import java.awt.event.KeyEvent; import javax.swing.Icon; import javax.swing.KeyStroke; +import generic.theme.GIcon; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressIterator; @@ -28,17 +29,18 @@ import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class NextPreviousLabelAction extends AbstractNextPreviousAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.label"); + public NextPreviousLabelAction(PluginTool tool, String owner, String subGroup) { super(tool, "Next Label", owner, subGroup); } @Override protected Icon getIcon() { - return ResourceManager.loadImage("images/L.gif"); + return ICON; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousSameBytesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousSameBytesAction.java index 366dd942bc..0aced61f54 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousSameBytesAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousSameBytesAction.java @@ -22,6 +22,7 @@ import java.util.Iterator; import javax.swing.Icon; import javax.swing.KeyStroke; +import generic.theme.GIcon; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; @@ -33,7 +34,6 @@ import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Navigates to the same byte pattern value under the current code unit. When negated, the search @@ -42,7 +42,7 @@ import resources.ResourceManager; */ public class NextPreviousSameBytesAction extends AbstractNextPreviousAction { - private static final Icon ICON = ResourceManager.loadImage("images/V.png"); + private static final Icon ICON = new GIcon("icon.plugin.navigation.bytes"); NextPreviousSameBytesAction(PluginTool tool, String owner, String subGroup) { super(tool, "Next Matching Byte Values", owner, subGroup); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousUndefinedAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousUndefinedAction.java index c2c0f5793b..67733e7cfe 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousUndefinedAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextPreviousUndefinedAction.java @@ -21,22 +21,24 @@ import java.awt.event.KeyEvent; import javax.swing.Icon; import javax.swing.KeyStroke; +import generic.theme.GIcon; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class NextPreviousUndefinedAction extends AbstractNextPreviousAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.undefined"); + public NextPreviousUndefinedAction(PluginTool tool, String owner, String subGroup) { super(tool, "Next Undefined", owner, subGroup); } @Override protected Icon getIcon() { - return ResourceManager.loadImage("images/U.gif"); + return ICON; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextSelectedRangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextSelectedRangeAction.java index 2bc0c9e7fb..ac32d83bed 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextSelectedRangeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/NextSelectedRangeAction.java @@ -18,9 +18,12 @@ package ghidra.app.plugin.core.navigation; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import javax.swing.Icon; + import docking.DockingUtils; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.nav.NextRangeAction; import ghidra.app.plugin.PluginCategoryNames; @@ -28,21 +31,22 @@ import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.PluginTool; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class NextSelectedRangeAction extends NextRangeAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.selection.range.next"); + public NextSelectedRangeAction(PluginTool tool, String ownerName, NavigationOptions navOptions) { super(tool, "Next Selected Range", ownerName, navOptions); setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, - "Next Selected Range" }, ResourceManager.loadImage("images/NextSelectionBlock16.gif"), + "Next Selected Range" }, ICON, PluginCategoryNames.NAVIGATION, MenuData.NO_MNEMONIC, NextPrevSelectedRangePlugin.ACTION_SUB_GROUP)); setToolBarData(new ToolBarData( - ResourceManager.loadImage("images/NextSelectionBlock16.gif"), + ICON, ToolConstants.TOOLBAR_GROUP_THREE, NextPrevSelectedRangePlugin.ACTION_SUB_GROUP)); setKeyBindingData( new KeyBindingData(KeyEvent.VK_OPEN_BRACKET, DockingUtils.CONTROL_KEY_MODIFIER_MASK | diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousHighlightedRangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousHighlightedRangeAction.java index f83cadee78..2ead540e82 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousHighlightedRangeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousHighlightedRangeAction.java @@ -17,9 +17,12 @@ package ghidra.app.plugin.core.navigation; import java.awt.event.KeyEvent; +import javax.swing.Icon; + import docking.DockingUtils; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.nav.PreviousRangeAction; import ghidra.app.plugin.PluginCategoryNames; @@ -27,21 +30,22 @@ import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.PluginTool; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class PreviousHighlightedRangeAction extends PreviousRangeAction { + private static final Icon ICON = new GIcon("icon.plugin.navigation.highlight.range.previous"); + public PreviousHighlightedRangeAction(PluginTool tool, String owner, NavigationOptions navOptions) { super(tool, "Previous Highlighted Range", owner, navOptions); setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, "Previous Highlight Range" }, - ResourceManager.loadImage("images/PreviousHighlightBlock16.gif"), + ICON, PluginCategoryNames.NAVIGATION, MenuData.NO_MNEMONIC, NextPrevHighlightRangePlugin.ACTION_SUB_GROUP)); setToolBarData(new ToolBarData( - ResourceManager.loadImage("images/PreviousHighlightBlock16.gif"), + ICON, ToolConstants.TOOLBAR_GROUP_THREE, NextPrevHighlightRangePlugin.ACTION_SUB_GROUP)); setKeyBindingData( new KeyBindingData(KeyEvent.VK_9, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousSelectedRangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousSelectedRangeAction.java index 7ef4a1ad07..9aa8c0c341 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousSelectedRangeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/PreviousSelectedRangeAction.java @@ -18,11 +18,12 @@ package ghidra.app.plugin.core.navigation; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.DockingUtils; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.context.ProgramLocationActionContext; import ghidra.app.nav.PreviousRangeAction; import ghidra.app.plugin.PluginCategoryNames; @@ -30,20 +31,20 @@ import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.PluginTool; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class PreviousSelectedRangeAction extends PreviousRangeAction { + private Icon ICON = new GIcon("icon.plugin.navigation.selection.range.previous"); + public PreviousSelectedRangeAction(PluginTool tool, String ownerName, NavigationOptions navOptions) { super(tool, "Previous Selected Range", ownerName, navOptions); - ImageIcon icon = ResourceManager.loadImage("images/PreviousSelectionBlock16.gif"); setMenuBarData(new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, - "Previous Selected Range" }, icon, PluginCategoryNames.NAVIGATION, + "Previous Selected Range" }, ICON, PluginCategoryNames.NAVIGATION, MenuData.NO_MNEMONIC, NextPrevSelectedRangePlugin.ACTION_SUB_GROUP)); - setToolBarData(new ToolBarData(icon, ToolConstants.TOOLBAR_GROUP_THREE, + setToolBarData(new ToolBarData(ICON, ToolConstants.TOOLBAR_GROUP_THREE, NextPrevSelectedRangePlugin.ACTION_SUB_GROUP)); setKeyBindingData( new KeyBindingData(KeyEvent.VK_CLOSE_BRACKET, DockingUtils.CONTROL_KEY_MODIFIER_MASK | diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java index 50e0090637..db1fd6dd2c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesHighlighter.java @@ -18,6 +18,7 @@ package ghidra.app.plugin.core.navigation.locationreferences; import java.awt.Color; import docking.widgets.fieldpanel.support.Highlight; +import generic.theme.GColor; import ghidra.GhidraOptions; import ghidra.app.nav.Navigatable; import ghidra.app.services.*; @@ -42,7 +43,8 @@ class LocationReferencesHighlighter { "Reference Search" + GhidraOptions.DELIMITER + "Highlight Match Color"; private static final String HIGHLIGHT_COLOR_DESCRIPTION = "The highlight color of matches for the 'Show References' searcher"; - private static Color DEFAULT_HIGHLIGHT_COLOR = new Color(168, 202, 242); + private static GColor DEFAULT_HIGHLIGHT_COLOR = + new GColor("color.bg.plugin.locationreferences.highlight"); private boolean isHighlighting = false; private final Navigatable navigatable; @@ -52,13 +54,9 @@ class LocationReferencesHighlighter { private HighlightProvider highlightProvider; private MarkerRemover markerRemover; private Color highlightColor; - private OptionsChangeListener optionsListener = new OptionsChangeListener() { - @Override - public void optionsChanged(ToolOptions options, String name, Object oldValue, - Object newValue) { - if (name.equals(HIGHLIGHT_COLOR_KEY)) { - highlightColor = (Color) newValue; - } + private OptionsChangeListener optionsListener = (options, name, oldValue, newValue) -> { + if (name.equals(HIGHLIGHT_COLOR_KEY)) { + highlightColor = (Color) newValue; } }; @@ -67,7 +65,7 @@ class LocationReferencesHighlighter { // tool until a search has happened, which is odd. static void registerHighlighterOptions(LocationReferencesPlugin plugin) { ToolOptions options = plugin.getTool().getOptions(OPTIONS_TITLE); - options.registerOption(HIGHLIGHT_COLOR_KEY, DEFAULT_HIGHLIGHT_COLOR, + options.registerThemeColorBinding(HIGHLIGHT_COLOR_KEY, DEFAULT_HIGHLIGHT_COLOR.getId(), plugin.getHelpLocation(), HIGHLIGHT_COLOR_DESCRIPTION); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java index 6422fbdebf..911b1c1893 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java @@ -25,6 +25,7 @@ import javax.swing.event.ChangeListener; import docking.ActionContext; import docking.action.*; import docking.widgets.table.GTable; +import generic.theme.GIcon; import ghidra.app.nav.Navigatable; import ghidra.app.nav.NavigatableRemovalListener; import ghidra.app.services.GoToService; @@ -51,8 +52,8 @@ import resources.ResourceManager; public class LocationReferencesProvider extends ComponentProviderAdapter implements DomainObjectListener, NavigatableRemovalListener { - private static Icon HIGHLIGHT_ICON = ResourceManager.loadImage("images/tag_yellow.png"); - private static Icon HOME_ICON = ResourceManager.loadImage("images/go-home.png"); + private static Icon HIGHLIGHT_ICON = new GIcon("icon.plugin.locationreferences.highlight"); + private static Icon HOME_ICON = Icons.HOME_ICON; private static Icon REFRESH_ICON = Icons.REFRESH_ICON; private static Icon REFRESH_NOT_NEEDED_ICON = ResourceManager.getDisabledIcon(Icons.REFRESH_ICON, 60); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesTableModel.java index 3f77196d72..671955bdab 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesTableModel.java @@ -15,13 +15,13 @@ */ package ghidra.app.plugin.core.navigation.locationreferences; -import java.awt.Color; import java.awt.Component; import java.util.*; import org.apache.commons.lang3.StringUtils; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; @@ -171,7 +171,7 @@ class LocationReferencesTableModel extends AddressBasedTableModel showAddBundlesFileChooser()) .buildAndInstallLocal(this); - icon = ResourceManager.loadImage("images/edit-delete.png"); + icon = Icons.DELETE_ICON; new ActionBuilder("RemoveBundles", this.getName()) .popupMenuPath("Remove selected bundle(s)") .popupMenuIcon(icon) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusTableModel.java index 7f7a957baa..d30d509af6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusTableModel.java @@ -15,9 +15,9 @@ */ package ghidra.app.plugin.core.osgi; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; import java.util.*; -import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -29,6 +29,7 @@ import org.osgi.framework.Bundle; import docking.widgets.table.*; import generic.jar.ResourceFile; +import generic.theme.GColor; import generic.util.Path; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; @@ -42,11 +43,14 @@ import ghidra.util.table.column.GColumnRenderer; */ public class BundleStatusTableModel extends GDynamicColumnTableModel> { - private static final Color COLOR_BUNDLE_ERROR = Color.RED; - private static final Color COLOR_BUNDLE_DISABLED = Color.DARK_GRAY; - private static final Color COLOR_BUNDLE_BUSY = Color.GRAY; - private static final Color COLOR_BUNDLE_INACTIVE = Color.BLACK; - private static final Color COLOR_BUNDLE_ACTIVE = new Color(0.0f, .6f, 0.0f); // a dark green + + //@formatter:off + private static final Color COLOR_BUNDLE_ERROR = new GColor("color.fg.error"); + private static final Color COLOR_BUNDLE_DISABLED = new GColor("color.fg.table.bundle.disabled"); + private static final Color COLOR_BUNDLE_BUSY = new GColor("color.fg.table.bundle.busy"); + private static final Color COLOR_BUNDLE_INACTIVE = new GColor("color.fg.table.bundle.inactive"); + private static final Color COLOR_BUNDLE_ACTIVE = new GColor("color.fg.table.bundle.active"); + //@formatter:on private BundleHost bundleHost; private BundleStatusComponentProvider provider; @@ -146,8 +150,6 @@ public class BundleStatusTableModel }); } - /***************************************************/ - @Override public boolean isCellEditable(int rowIndex, int columnIndex) { BundleStatus status = statuses.get(rowIndex); @@ -553,7 +555,6 @@ public class BundleStatusTableModel BundleStatus status = (BundleStatus) data.getRowObject(); ResourceFile file = (ResourceFile) data.getValue(); JLabel label = (JLabel) super.getTableCellRendererComponent(data); - label.setFont(defaultFont.deriveFont(defaultFont.getStyle() | Font.BOLD)); label.setText(Path.toPathString(file)); GhidraBundle bundle = bundleHost.getGhidraBundle(file); if (bundle == null || bundle instanceof GhidraPlaceholderBundle || !file.exists()) { @@ -573,6 +574,7 @@ public class BundleStatusTableModel label.setForeground(COLOR_BUNDLE_INACTIVE); } } + return label; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java index 5cd4bb09ef..3f89bba1cb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java @@ -25,6 +25,7 @@ import java.util.List; import javax.swing.*; import docking.action.DockingActionIf; +import generic.theme.GColor; import ghidra.app.nav.Navigatable; import ghidra.app.services.GoToService; import ghidra.app.util.viewer.listingpanel.OverviewProvider; @@ -40,7 +41,7 @@ import help.Help; * Uses an {@link OverviewColorService} to get the appropriate color for an address. */ public class OverviewColorComponent extends JPanel implements OverviewProvider { - private static final Color DEFAULT_COLOR = Color.GRAY; + private static final Color DEFAULT_COLOR = new GColor("color.bg.plugin.overview.defalt"); private OverviewColorService service; private Color[] colors = new Color[0]; private final SwingUpdateManager refreshUpdater = @@ -158,7 +159,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider { } BigInteger indexCount = map.getIndexCount(); if (indexCount.equals(BigInteger.ZERO)) { - Arrays.fill(colors, Color.GRAY); + Arrays.fill(colors, DEFAULT_COLOR); repaint(); return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorPlugin.java index c4b89cfbe5..b334936956 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorPlugin.java @@ -23,6 +23,7 @@ import javax.swing.SwingUtilities; import docking.ActionContext; import docking.action.*; import docking.menu.MultiActionDockingAction; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.ProgramPlugin; @@ -35,7 +36,6 @@ import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.classfinder.ClassSearcher; -import resources.ResourceManager; /** * Plugin to manage {@link OverviewColorService}s. It creates actions for each service and installs @@ -132,7 +132,7 @@ public class OverviewColorPlugin extends ProgramPlugin { multiAction = new MultiActionDockingAction("Overview", getName()); multiAction.setActions(new ArrayList(actionMap.values())); multiAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/x-office-document-template.png"))); + new ToolBarData(new GIcon("icon.plugin.overview.provider"))); codeViewerService.addLocalAction(multiAction); multiAction.setDescription("Toggles overview margin displays."); multiAction.setHelpLocation( diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java index 9817106f1f..26b590edeb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/addresstype/AddressTypeOverviewColorService.java @@ -22,6 +22,7 @@ import java.util.List; import docking.ActionContext; import docking.DialogComponentProvider; import docking.action.DockingActionIf; +import generic.theme.GColor; import ghidra.app.plugin.core.overview.*; import ghidra.framework.model.*; import ghidra.framework.options.OptionsChangeListener; @@ -44,13 +45,18 @@ import ghidra.util.HelpLocation; public class AddressTypeOverviewColorService implements OverviewColorService, OptionsChangeListener, DomainObjectListener { private static final String OPTIONS_NAME = "Overview"; - private static final Color DEFAULT_INSTRUCTION_COLOR = new Color(192, 192, 255); - private static final Color DEFAULT_DATA_COLOR = new Color(128, 255, 128); - private static final Color DEFAULT_FUNCTION_COLOR = new Color(204, 150, 255); - private static final Color DEFAULT_UNDEFINED_COLOR = new Color(255, 51, 102); - private static final Color DEFAULT_UNINITIALIZED_COLOR = Color.BLACK; - private static final Color DEFAULT_EXTERNAL_REF_COLOR = new Color(255, 150, 150); - private static final Color DEFAULT_MARKER_COLOR = Color.WHITE; + private static final GColor DEFAULT_INSTRUCTION_COLOR = + new GColor("color.bg.plugin.overview.address.instruction"); + private static final GColor DEFAULT_DATA_COLOR = + new GColor("color.bg.plugin.overview.address.data"); + private static final GColor DEFAULT_FUNCTION_COLOR = + new GColor("color.bg.plugin.overview.address.function"); + private static final GColor DEFAULT_UNDEFINED_COLOR = + new GColor("color.bg.plugin.overview.address.undefined"); + private static final GColor DEFAULT_UNINITIALIZED_COLOR = + new GColor("color.bg.plugin.overview.address.uninitialized"); + private static final GColor DEFAULT_EXTERNAL_REF_COLOR = + new GColor("color.bg.plugin.overview.address.external.ref"); Color instructionColor = DEFAULT_INSTRUCTION_COLOR; Color dataColor = DEFAULT_DATA_COLOR; @@ -274,16 +280,20 @@ public class AddressTypeOverviewColorService ToolOptions options = tool.getOptions(OPTIONS_NAME); HelpLocation help = new HelpLocation(OverviewColorPlugin.HELP_TOPIC, "OverviewOptions"); - options.registerOption("Instruction Color", DEFAULT_INSTRUCTION_COLOR, help, + options.registerThemeColorBinding("Instruction Color", DEFAULT_INSTRUCTION_COLOR.getId(), + help, "Color for instructions"); - options.registerOption("Data Color", DEFAULT_DATA_COLOR, help, "Color for data"); - options.registerOption("Function Color", DEFAULT_FUNCTION_COLOR, help, + options.registerThemeColorBinding("Data Color", DEFAULT_DATA_COLOR.getId(), help, + "Color for data"); + options.registerThemeColorBinding("Function Color", DEFAULT_FUNCTION_COLOR.getId(), help, "Color for functions"); - options.registerOption("Undefined Color", DEFAULT_UNDEFINED_COLOR, help, + options.registerThemeColorBinding("Undefined Color", DEFAULT_UNDEFINED_COLOR.getId(), help, "Color for undefined bytes"); - options.registerOption("Uninitialized Color", DEFAULT_UNINITIALIZED_COLOR, help, + options.registerThemeColorBinding("Uninitialized Color", + DEFAULT_UNINITIALIZED_COLOR.getId(), help, "Color for uninitialize memory"); - options.registerOption("External Reference Color", DEFAULT_EXTERNAL_REF_COLOR, help, + options.registerThemeColorBinding("External Reference Color", + DEFAULT_EXTERNAL_REF_COLOR.getId(), help, "Color for external references"); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java index 16d2b5d6f8..ff26592b01 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewColorService.java @@ -42,7 +42,7 @@ public class EntropyOverviewColorService implements OverviewColorService { private byte[] chunkBuffer; private double[] logtable; private int[] histogram = new int[256]; - private Palette palette; + private OverviewPalette palette; private EntropyOverviewOptionsManager entropyOptionsManager; private OverviewColorComponent overviewComponent; private OverviewColorLegendDialog legendDialog; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewOptionsManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewOptionsManager.java index cdb0a1bb80..7ee5058bcc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewOptionsManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/EntropyOverviewOptionsManager.java @@ -17,6 +17,7 @@ package ghidra.app.plugin.core.overview.entropy; import java.awt.Color; +import generic.theme.GColor; import ghidra.app.plugin.core.overview.OverviewColorPlugin; import ghidra.framework.options.OptionsChangeListener; import ghidra.framework.options.ToolOptions; @@ -28,46 +29,53 @@ import ghidra.util.HelpLocation; * the color Palette for that service. */ public class EntropyOverviewOptionsManager implements OptionsChangeListener { - private static final Color uninitializedColor = Color.decode("0x0000ff"); + private static final Color UNINITIALIZED_COLOR = + new GColor("color.bg.plugin.overview.entropy.uninitialized"); private static final String OPTIONS_NAME = "Entropy"; - private final static String CHUNKSIZE_STRING = "Chunk size"; - private final static String CHUNKSIZE_DESC_STRING = "Number of bytes per entropy score"; - private final static EntropyChunkSize chunksize_def = EntropyChunkSize.LARGE; - private final static String KNOT_COLOR_STRING = + private static final String CHUNKSIZE_STRING = "Chunk size"; + private static final String CHUNKSIZE_DESC_STRING = "Number of bytes per entropy score"; + private static final EntropyChunkSize CHUNKSIZE_DEF = EntropyChunkSize.LARGE; + private static final String KNOT_COLOR_STRING = "Color to use for highlighting a specific range of entropy values"; - private final static String KNOT_TYPE_STRING = "Type of range to highlight"; - private final static String KNOT1_COLOR_STRING = "Range 1 color"; - private final static String KNOT1_TYPE_STRING = "Entropy Range 1"; - private final static Color knot1_def_color = Color.decode("0xff0000"); - private final static EntropyKnot knot1_def_type = EntropyKnot.COMPRESSED; - private final static String KNOT2_COLOR_STRING = "Range 2 color"; - private final static String KNOT2_TYPE_STRING = "Entropy Range 2"; - private final static Color knot2_def_color = Color.decode("0x0000ff"); - private final static EntropyKnot knot2_def_type = EntropyKnot.X86; - private final static String KNOT3_COLOR_STRING = "Range 3 color"; - private final static String KNOT3_TYPE_STRING = "Entropy Range 3"; - private final static Color knot3_def_color = Color.decode("0x00ff00"); - private final static EntropyKnot knot3_def_type = EntropyKnot.ASCII; - private final static String KNOT4_COLOR_STRING = "Range 4 color"; - private final static String KNOT4_TYPE_STRING = "Entropy Range 4"; - private final static Color knot4_def_color = Color.decode("0xffff00"); - private final static EntropyKnot knot4_def_type = EntropyKnot.UTF16; - private final static String KNOT5_COLOR_STRING = "Range 5 color"; - private final static String KNOT5_TYPE_STRING = "Entropy Range 5"; - private final static Color knot5_def_color = Color.decode("0x0000ff"); - private final static EntropyKnot knot5_def_type = EntropyKnot.NONE; + private static final String KNOT_TYPE_STRING = "Type of range to highlight"; + + private static final String KNOT1_COLOR_OPTION_NAME = "Range 1 color"; + private static final String KNOT1_TYPE_OPTION_NAME = "Entropy Range 1"; + private static final GColor KNOT1_COLOR = new GColor("color.bg.plugin.overview.entropy.knot.1"); + private static final EntropyKnot KNOT1_DEF_TYPE = EntropyKnot.COMPRESSED; + + private static final String KNOT2_COLOR_OPTION_NAME = "Range 2 color"; + private static final String KNOT2_TYPE_OPTION_NAME = "Entropy Range 2"; + private static final GColor KNOT2_COLOR = new GColor("color.bg.plugin.overview.entropy.knot.2"); + private static final EntropyKnot KNOT2_DEF_TYPE = EntropyKnot.X86; + + private static final String KNOT3_COLOR_OPTION_NAME = "Range 3 color"; + private static final String KNOT3_TYPE_OPTION_NAME = "Entropy Range 3"; + private static final GColor KNOT3_COLOR = new GColor("color.bg.plugin.overview.entropy.knot.3"); + private static final EntropyKnot KNOT3_DEF_TYPE = EntropyKnot.ASCII; + + private static final String KNOT4_COLOR_OPTION_NAME = "Range 4 color"; + private static final String KNOT4_TYPE_OPTION_NAME = "Entropy Range 4"; + private static final GColor KNOT4_COLOR = new GColor("color.bg.plugin.overview.entropy.knot.4"); + private static final EntropyKnot KNOT4_DEF_TYPE = EntropyKnot.UTF16; + + private static final String KNOT5_COLOR_OPTION_NAME = "Range 5 color"; + private static final String KNOT5_TYPE_OPTION_NAME = "Entropy Range 5"; + private static final GColor KNOT5_COLOR = new GColor("color.bg.plugin.overview.entropy.knot.5"); + private static final EntropyKnot KNOT5_DEF_TYPE = EntropyKnot.NONE; + + private static final GColor PALETTE_COLOR_HIGH = + new GColor("color.bg.plugin.overview.entropy.palette.base.high"); + private static final GColor PALETTE_COLOR_LOW = + new GColor("color.bg.plugin.overview.entropy.palette.base.low"); + private EntropyChunkSize chunksize; - private Color knot1color; private EntropyKnot knot1type; - private Color knot2color; private EntropyKnot knot2type; - private Color knot3color; private EntropyKnot knot3type; - private Color knot4color; private EntropyKnot knot4type; - private Color knot5color; private EntropyKnot knot5type; - private Palette palette = new Palette(256, uninitializedColor); + private OverviewPalette palette = new OverviewPalette(256, UNINITIALIZED_COLOR); private EntropyOverviewColorService service; public EntropyOverviewOptionsManager(PluginTool tool, EntropyOverviewColorService service) { @@ -78,18 +86,23 @@ public class EntropyOverviewOptionsManager implements OptionsChangeListener { options.addOptionsChangeListener(this); options.setOptionsHelpLocation(help); - options.registerOption(CHUNKSIZE_STRING, chunksize_def, help, CHUNKSIZE_DESC_STRING); - options.registerOption(KNOT1_COLOR_STRING, knot1_def_color, help, KNOT_COLOR_STRING); - options.registerOption(KNOT2_COLOR_STRING, knot2_def_color, help, KNOT_COLOR_STRING); - options.registerOption(KNOT3_COLOR_STRING, knot3_def_color, help, KNOT_COLOR_STRING); - options.registerOption(KNOT4_COLOR_STRING, knot4_def_color, help, KNOT_COLOR_STRING); - options.registerOption(KNOT5_COLOR_STRING, knot5_def_color, help, KNOT_COLOR_STRING); + options.registerOption(CHUNKSIZE_STRING, CHUNKSIZE_DEF, help, CHUNKSIZE_DESC_STRING); + options.registerThemeColorBinding(KNOT1_COLOR_OPTION_NAME, KNOT1_COLOR.getId(), help, + KNOT_COLOR_STRING); + options.registerThemeColorBinding(KNOT2_COLOR_OPTION_NAME, KNOT2_COLOR.getId(), help, + KNOT_COLOR_STRING); + options.registerThemeColorBinding(KNOT3_COLOR_OPTION_NAME, KNOT3_COLOR.getId(), help, + KNOT_COLOR_STRING); + options.registerThemeColorBinding(KNOT4_COLOR_OPTION_NAME, KNOT4_COLOR.getId(), help, + KNOT_COLOR_STRING); + options.registerThemeColorBinding(KNOT5_COLOR_OPTION_NAME, KNOT5_COLOR.getId(), help, + KNOT_COLOR_STRING); - options.registerOption(KNOT1_TYPE_STRING, knot1_def_type, help, KNOT_TYPE_STRING); - options.registerOption(KNOT2_TYPE_STRING, knot2_def_type, help, KNOT_TYPE_STRING); - options.registerOption(KNOT3_TYPE_STRING, knot3_def_type, help, KNOT_TYPE_STRING); - options.registerOption(KNOT4_TYPE_STRING, knot4_def_type, help, KNOT_TYPE_STRING); - options.registerOption(KNOT5_TYPE_STRING, knot5_def_type, help, KNOT_TYPE_STRING); + options.registerOption(KNOT1_TYPE_OPTION_NAME, KNOT1_DEF_TYPE, help, KNOT_TYPE_STRING); + options.registerOption(KNOT2_TYPE_OPTION_NAME, KNOT2_DEF_TYPE, help, KNOT_TYPE_STRING); + options.registerOption(KNOT3_TYPE_OPTION_NAME, KNOT3_DEF_TYPE, help, KNOT_TYPE_STRING); + options.registerOption(KNOT4_TYPE_OPTION_NAME, KNOT4_DEF_TYPE, help, KNOT_TYPE_STRING); + options.registerOption(KNOT5_TYPE_OPTION_NAME, KNOT5_DEF_TYPE, help, KNOT_TYPE_STRING); readOptions(options); updatePalettes(); @@ -104,23 +117,17 @@ public class EntropyOverviewOptionsManager implements OptionsChangeListener { } private void readOptions(ToolOptions options) { - chunksize = options.getEnum(CHUNKSIZE_STRING, chunksize_def); + chunksize = options.getEnum(CHUNKSIZE_STRING, CHUNKSIZE_DEF); - knot1color = options.getColor(KNOT1_COLOR_STRING, knot1_def_color); - knot2color = options.getColor(KNOT2_COLOR_STRING, knot2_def_color); - knot3color = options.getColor(KNOT3_COLOR_STRING, knot3_def_color); - knot4color = options.getColor(KNOT4_COLOR_STRING, knot4_def_color); - knot5color = options.getColor(KNOT5_COLOR_STRING, knot5_def_color); - - knot1type = options.getEnum(KNOT1_TYPE_STRING, knot1_def_type); - knot2type = options.getEnum(KNOT2_TYPE_STRING, knot2_def_type); - knot3type = options.getEnum(KNOT3_TYPE_STRING, knot3_def_type); - knot4type = options.getEnum(KNOT4_TYPE_STRING, knot4_def_type); - knot5type = options.getEnum(KNOT5_TYPE_STRING, knot5_def_type); + knot1type = options.getEnum(KNOT1_TYPE_OPTION_NAME, KNOT1_DEF_TYPE); + knot2type = options.getEnum(KNOT2_TYPE_OPTION_NAME, KNOT2_DEF_TYPE); + knot3type = options.getEnum(KNOT3_TYPE_OPTION_NAME, KNOT3_DEF_TYPE); + knot4type = options.getEnum(KNOT4_TYPE_OPTION_NAME, KNOT4_DEF_TYPE); + knot5type = options.getEnum(KNOT5_TYPE_OPTION_NAME, KNOT5_DEF_TYPE); } - private void addPaletteKnot(String name, Color col, double point, double width) { + private void addPaletteKnot(String name, Color color, double point, double width) { int palettewidth = 256; int pointint = (int) Math.floor((palettewidth / 8.0) * point); if (pointint > 255) { @@ -131,11 +138,11 @@ public class EntropyOverviewOptionsManager implements OptionsChangeListener { if (start < 0) { start = 0; } - palette.addKnot(name, col, start, pointint); + palette.addKnot(name, color, start, pointint); } private void updatePalettes() { - palette.setBase(Color.decode("0x000000"), Color.decode("0xffffff")); + palette.setBase(PALETTE_COLOR_LOW, PALETTE_COLOR_HIGH); addPaletteKnots(); service.paletteChanged(); } @@ -143,23 +150,23 @@ public class EntropyOverviewOptionsManager implements OptionsChangeListener { private void addPaletteKnots() { EntropyRecord rec = knot1type.getRecord(); if (rec != null) { - addPaletteKnot(rec.name, knot1color, rec.center, rec.width); + addPaletteKnot(rec.name, KNOT1_COLOR, rec.center, rec.width); } rec = knot2type.getRecord(); if (rec != null) { - addPaletteKnot(rec.name, knot2color, rec.center, rec.width); + addPaletteKnot(rec.name, KNOT2_COLOR, rec.center, rec.width); } rec = knot3type.getRecord(); if (rec != null) { - addPaletteKnot(rec.name, knot3color, rec.center, rec.width); + addPaletteKnot(rec.name, KNOT3_COLOR, rec.center, rec.width); } rec = knot4type.getRecord(); if (rec != null) { - addPaletteKnot(rec.name, knot4color, rec.center, rec.width); + addPaletteKnot(rec.name, KNOT4_COLOR, rec.center, rec.width); } rec = knot5type.getRecord(); if (rec != null) { - addPaletteKnot(rec.name, knot5color, rec.center, rec.width); + addPaletteKnot(rec.name, KNOT5_COLOR, rec.center, rec.width); } } @@ -175,7 +182,7 @@ public class EntropyOverviewOptionsManager implements OptionsChangeListener { * Returns the palette computed after reading the options. * @return the color palette for the {@link EntropyOverviewColorService} */ - public Palette getPalette() { + public OverviewPalette getPalette() { return palette; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotLabelPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotLabelPanel.java index efc614aee3..20453c9c9c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotLabelPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotLabelPanel.java @@ -20,16 +20,19 @@ import java.util.ArrayList; import javax.swing.JPanel; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.Gui; + public class KnotLabelPanel extends JPanel { - private static final Font FONT = new Font("Times New Roman", Font.BOLD, 16); + private static final String FONT_ID = "font.plugin.entropy.label.knot"; private int topBottomMargin = 10; - private Palette palette; + private OverviewPalette palette; public KnotLabelPanel(int topBottomMargin) { this.topBottomMargin = topBottomMargin; } - public void setPalette(Palette palette) { + public void setPalette(OverviewPalette palette) { this.palette = palette; } @@ -45,14 +48,14 @@ public class KnotLabelPanel extends JPanel { g.setColor(getBackground()); g.fillRect(0, 0, width, height); int paletteSize = palette.getSize(); - g.setFont(FONT); + g.setFont(Gui.getFont(FONT_ID)); FontMetrics fontMetrics = g.getFontMetrics(); int ascent = fontMetrics.getAscent(); int descent = fontMetrics.getDescent(); int fontOffset = ascent / 3; // this looks about right ArrayList knots = palette.getKnots(); - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); g.drawLine(5, topBottomMargin - 6, 10, topBottomMargin - ascent + 2); g.drawString("min entropy (0.0)", 20, topBottomMargin - ascent - descent); @@ -67,7 +70,7 @@ public class KnotLabelPanel extends JPanel { g.drawLine(5, y, 10, y); } - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); g.drawLine(5, height + topBottomMargin + 4, 10, height + topBottomMargin + 8); g.drawString("max entropy (8.0)", 20, topBottomMargin + height + ascent + descent); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotPanel.java deleted file mode 100644 index bde94c8cbc..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/KnotPanel.java +++ /dev/null @@ -1,195 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.plugin.core.overview.entropy; - -import java.awt.*; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.util.ArrayList; - -import javax.swing.*; -import javax.swing.border.LineBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import docking.util.GraphicsUtils; -import docking.widgets.label.GLabel; - -/** - * Class used by the entropy legend panel to show known entropy ranges. - */ -public class KnotPanel extends JPanel implements ComponentListener { - private static final long serialVersionUID = 1L; - private static final int SPACING = 5; - private static final Font FONT = new Font("SansSerif", Font.PLAIN, 10); - private Palette palette = null; - private FontMetrics metrics; - - private ChangeListener paletteListener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - buildLabels(); - } - }; - - public KnotPanel() { - super(); - addComponentListener(this); - metrics = getFontMetrics(FONT); - setPreferredSize( - new Dimension(100, SPACING + metrics.getMaxAscent() + metrics.getMaxDescent())); - } - - public void oldPaintComponent(Graphics g) { - super.paintComponent(g); - g.setColor(getBackground()); - Rectangle clip = g.getClipBounds(); - g.fillRect(clip.x, clip.y, clip.width, clip.height); - - if (palette == null) { - return; - } - - g.setColor(Color.BLACK); - g.setFont(FONT); - int height = getHeight(); - int width = getWidth(); - int palsize = palette.getSize(); - int fontHeight = metrics.getMaxAscent() + metrics.getMaxDescent(); - int baseline = (height - fontHeight - 1) / 2 + metrics.getMaxAscent(); - - ArrayList knots = palette.getKnots(); - for (int i = 0; i < knots.size(); i++) { - KnotRecord rec = knots.get(i); - int start = (rec.start * width) / palsize; - int end = (rec.end * width) / palsize; - g.drawLine(start, 0, start, height - 1); - g.drawLine(end, 0, end, height - 1); - g.drawLine(start, height - 1, end, height - 1); - - FontMetrics currentMetrics = metrics; - int w = currentMetrics.stringWidth(rec.name); - int knotwidth = end - start; - while (w > knotwidth) { - currentMetrics = getSmallerFontMetrics(currentMetrics); - w = currentMetrics.stringWidth(rec.name); - - if (currentMetrics.getFont().getSize() <= 4) { - break; // can't go any smaller - } - } - - if (w < knotwidth) { // we found a suitable font - g.setFont(currentMetrics.getFont()); - GraphicsUtils.drawString(this, g, rec.name, start + (knotwidth - 1) / 2 - w / 2, - baseline); - g.setFont(FONT); - } - else { // must be no room to paint the string, even with a small font - String ellipsis = "..."; - w = metrics.stringWidth(ellipsis); - GraphicsUtils.drawString(this, g, ellipsis, start + (knotwidth - 1) / 2 - w / 2, - baseline); - } - - // reset the font - currentMetrics = metrics; - } - - } - - private FontMetrics getSmallerFontMetrics(FontMetrics fontMetrics) { - Font currentFont = fontMetrics.getFont(); - int size = currentFont.getSize(); - Font newFont = currentFont.deriveFont((float) --size); - return getFontMetrics(newFont); - } - - public void setPalette(Palette pal) { - palette = pal; - palette.addPaletteListener(paletteListener); - buildLabels(); - repaint(); - } - - private void buildLabels() { - removeAll(); - setLayout(null); - - int paletteSize = palette.getSize(); - Container parent = getParent(); - - ArrayList knots = palette.getKnots(); - for (KnotRecord record : knots) { - JLabel label = new GLabel(record.name); - label.setFont(FONT); - label.setBorder(new ToplessLineBorder(Color.BLACK)); - label.setHorizontalAlignment(SwingConstants.CENTER); - label.setToolTipText(record.name); - - int height = getHeight(); - int width = getWidth(); - int start = (record.start * width) / paletteSize; - int end = (record.end * width) / paletteSize; - - int labelWidth = end - start; - int labelHeight = height - 1; - int x = start + ((end - start >> 1) - (labelWidth >> 1)); - int y = 0; - - label.setBounds(x, y, labelWidth, labelHeight); - add(label); - } - invalidate(); - if (parent != null) { - parent.validate(); - } - } - - public void refresh() { - buildLabels(); - repaint(); - } - - @Override - public void componentResized(ComponentEvent e) { - refresh(); - } - - @Override - public void componentHidden(ComponentEvent e) { - } - - @Override - public void componentMoved(ComponentEvent e) { - } - - @Override - public void componentShown(ComponentEvent e) { - } - - private class ToplessLineBorder extends LineBorder { - - public ToplessLineBorder(Color color) { - super(color); - } - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - super.paintBorder(c, g, x, y - 1, width, height + 1); - } - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/LegendPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/LegendPanel.java index e466589ab4..d06dfe1ee5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/LegendPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/LegendPanel.java @@ -48,7 +48,7 @@ public class LegendPanel extends JPanel { return new Dimension(210, 300); } - public void setPalette(Palette pal) { + public void setPalette(OverviewPalette pal) { palettePanel.setPalette(pal); knotPanel.setPalette(pal); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/Palette.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/OverviewPalette.java similarity index 93% rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/Palette.java rename to Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/OverviewPalette.java index 74b1c64a18..78f0b8bf0c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/Palette.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/OverviewPalette.java @@ -21,13 +21,14 @@ import java.util.ArrayList; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import ghidra.util.ColorUtils; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; /** * Manages the colors used by the entropy overview bar. */ -public class Palette { +public class OverviewPalette { private Color uninitializedColor; private Color[] colors; private ArrayList knots; @@ -35,7 +36,7 @@ public class Palette { private WeakSet listeners = WeakDataStructureFactory.createSingleThreadAccessWeakSet(); - public Palette(int sz, Color uninit) { + public OverviewPalette(int sz, Color uninit) { uninitializedColor = uninit; colors = new Color[sz]; knots = new ArrayList<>(); @@ -75,7 +76,7 @@ public class Palette { int green = (int) (lo.getGreen() * (1.0 - t) + hi.getGreen() * t); int blue = (int) (lo.getBlue() * (1.0 - t) + hi.getGreen() * t); t += step; - colors[i] = new Color(red, green, blue); + colors[i] = ColorUtils.getColor(red, green, blue); } knots.clear(); firePaletteChanged(); @@ -111,7 +112,7 @@ public class Palette { int green = (int) Math.floor(tmp); tmp = (knot.getBlue() - oldcolor.getBlue()) * t + oldcolor.getBlue(); int blue = (int) Math.floor(tmp); - colors[start] = new Color(red, green, blue); + colors[start] = ColorUtils.getColor(red, green, blue); cur += radianstep; start += 1; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/PalettePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/PalettePanel.java index 0fb78759f6..3ab95ed958 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/PalettePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/entropy/PalettePanel.java @@ -19,9 +19,11 @@ import java.awt.*; import javax.swing.JPanel; +import generic.theme.GThemeDefaults.Colors.Java; + public class PalettePanel extends JPanel { - private Palette palette; + private OverviewPalette palette; private final int topBottomMargin; PalettePanel(int topBottomMargin) { @@ -33,7 +35,7 @@ public class PalettePanel extends JPanel { return new Dimension(20, 10); } - public void setPalette(Palette palette) { + public void setPalette(OverviewPalette palette) { this.palette = palette; } @@ -45,12 +47,12 @@ public class PalettePanel extends JPanel { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); if (palette == null) { - g.setColor(Color.BLACK); g.drawRect(0, 0, width - 1, height - 1); return; } + int palsize = palette.getSize(); //Draw the rectangles for each pixel for (int i = 0; i < height; i++) { @@ -62,7 +64,7 @@ public class PalettePanel extends JPanel { g.setColor(c); g.fillRect(0, topBottomMargin + i, width, 1); } - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); g.drawRect(0, topBottomMargin, width - 1, height); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/CodeUnitPrintable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/CodeUnitPrintable.java index 8a6a2115e9..1cc065b393 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/CodeUnitPrintable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/CodeUnitPrintable.java @@ -27,13 +27,14 @@ import docking.widgets.fieldpanel.LayoutModel; import docking.widgets.fieldpanel.internal.EmptyLayoutBackgroundColorManager; import docking.widgets.fieldpanel.internal.LayoutBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.util.DateUtils; import ghidra.util.Msg; import ghidra.util.task.TaskMonitor; public class CodeUnitPrintable implements Printable { - //private FieldPanel panel; private LayoutModel lm; private int startIndex; private int endIndex; @@ -48,12 +49,11 @@ public class CodeUnitPrintable implements Printable { private static final PaintContext PAINT_CONTEXT = new PaintContext(); static { - PAINT_CONTEXT.setForegroundColor(Color.BLACK); - PAINT_CONTEXT.setDefaultBackgroundColor(Color.WHITE); - PAINT_CONTEXT.setBackgroundColor(Color.white); - PAINT_CONTEXT.setCursorColor(Color.RED); - PAINT_CONTEXT.setSelectionColor(new Color(180, 255, 180)); - PAINT_CONTEXT.setHighlightColor(new Color(255, 255, 150)); + PAINT_CONTEXT.setForegroundColor(Colors.FOREGROUND); + PAINT_CONTEXT.setBackgroundColor(Colors.BACKGROUND); + PAINT_CONTEXT.setCursorColor(Colors.CURSOR); + PAINT_CONTEXT.setSelectionColor(new GColor("color.bg.selection")); + PAINT_CONTEXT.setHighlightColor(new GColor("color.bg.highlight")); PAINT_CONTEXT.setPrinting(true); } @@ -70,13 +70,6 @@ public class CodeUnitPrintable implements Printable { this.book = book; this.job = job; this.startDate = startDate; - - if (pod.getMonochrome()) { - PAINT_CONTEXT.setPrintColor(Color.BLACK); - } - else { - PAINT_CONTEXT.setPrintColor(null); - } } public CodeUnitPrintable(LayoutModel lm, java.util.List layouts, double scaleAmount, @@ -90,20 +83,13 @@ public class CodeUnitPrintable implements Printable { this.book = book; this.job = job; this.startDate = startDate; - - if (pod.getMonochrome()) { - PAINT_CONTEXT.setPrintColor(Color.BLACK); - } - else { - PAINT_CONTEXT.setPrintColor(null); - } } @Override public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { Graphics2D g2 = GraphicsUtils.getGraphics2D(graphics); - g2.setColor(Color.BLACK); + g2.setColor(Colors.FOREGROUND); monitor.setMessage("Printing Page " + (pageIndex + 1)); monitor.initialize(100); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java index 6ea1b7ed7a..059cd32b20 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/printing/PrintOptionsDialog.java @@ -23,13 +23,12 @@ import javax.swing.*; import docking.DialogComponentProvider; import docking.widgets.button.GRadioButton; import docking.widgets.checkbox.GCheckBox; +import generic.theme.Gui; import ghidra.util.HelpLocation; public class PrintOptionsDialog extends DialogComponentProvider { - private final Font HEADER_FONT = new Font("SansSerif", Font.PLAIN, 10); - private final FontMetrics HEADER_METRICS = rootPanel.getFontMetrics(HEADER_FONT); - + private static final String FONT_ID = "font.print"; private boolean selectionEnabled; private boolean cancelled = false; @@ -163,11 +162,11 @@ public class PrintOptionsDialog extends DialogComponentProvider { } public Font getHeaderFont() { - return HEADER_FONT; + return Gui.getFont(FONT_ID); } public FontMetrics getHeaderMetrics() { - return HEADER_METRICS; + return rootPanel.getFontMetrics(getHeaderFont()); } public boolean showHeader() { @@ -183,7 +182,8 @@ public class PrintOptionsDialog extends DialogComponentProvider { } public int getHeaderHeight() { - return HEADER_METRICS.getMaxAscent() + HEADER_METRICS.getMaxDescent(); + FontMetrics metrics = getHeaderMetrics(); + return metrics.getMaxAscent() + metrics.getMaxDescent(); } public void setSelectionEnabled(boolean selectionEnabled) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java index 9cad4e9a0c..6f3397b4b4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java @@ -21,6 +21,7 @@ import javax.swing.*; import javax.swing.table.DefaultTableModel; import docking.widgets.checkbox.GCheckBox; +import generic.theme.Gui; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger.SleighDebugMode; import ghidra.framework.model.DomainObjectChangedEvent; @@ -38,6 +39,7 @@ import ghidra.util.table.GhidraTable; * */ class InstructionInfoProvider extends ComponentProviderAdapter implements DomainObjectListener { + private static final String FONT_ID = "font.plugin.instruction.info"; private JPanel mainPanel; private JSplitPane pane; private ShowInstructionInfoPlugin plugin; @@ -99,14 +101,12 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain mainPanel = new JPanel(new BorderLayout()); instructionText = new JTextArea(); - Font defaultFont = instructionText.getFont(); - Font fixedWidthFont = new Font("monospaced", defaultFont.getStyle(), 14); - instructionText.setFont(fixedWidthFont); + Gui.registerFont(instructionText, FONT_ID); instructionText.setEditable(false); operandModel = new OperandModel(); opTable = new GhidraTable(operandModel); - opTable.setFont(fixedWidthFont); + Gui.registerFont(opTable, FONT_ID); opTable.setPreferredScrollableViewportSize(new Dimension(425, 105)); //opTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/AbstractUndoRedoAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/AbstractUndoRedoAction.java index a16ca582db..54367cf564 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/AbstractUndoRedoAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/AbstractUndoRedoAction.java @@ -22,6 +22,7 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.app.services.GoToService; import ghidra.app.services.NavigationHistoryService; @@ -31,7 +32,6 @@ import ghidra.framework.model.TransactionListener; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.listing.Program; import ghidra.util.*; -import resources.ResourceManager; /** * Abstract base class for the undo and redo actions. These actions add a listener to the @@ -44,14 +44,14 @@ public abstract class AbstractUndoRedoAction extends DockingAction { private TransactionListener transactionListener; public AbstractUndoRedoAction(PluginTool tool, ProgramManagerPlugin plugin, String name, - String iconPath, String keyBinding, String subGroup) { + String iconId, String keyBinding, String subGroup) { super(name, plugin.getName()); this.tool = tool; this.plugin = plugin; String[] menuPath = { ToolConstants.MENU_EDIT, "&" + name }; - Icon icon = ResourceManager.loadImage(iconPath); + Icon icon = new GIcon(iconId); String group = "Undo"; MenuData menuData = new MenuData(menuPath, icon, group); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java index 91c25c1b1e..739e66634e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/MultiTabPanel.java @@ -27,33 +27,40 @@ import javax.swing.border.*; import docking.actions.KeyBindingUtils; import docking.widgets.label.GDLabel; import docking.widgets.label.GIconLabel; +import generic.theme.*; import generic.util.WindowUtilities; import ghidra.framework.model.ProjectLocator; import ghidra.program.model.listing.Program; import ghidra.util.layout.HorizontalLayout; -import resources.ResourceManager; +import resources.Icons; /** * Panel to show a "tab" for an object. ChangeListeners are notified when a tab is selected. */ public class MultiTabPanel extends JPanel { + private static final String FONT_TABS_ID = "font.plugin.tabs"; + private static final String FONT_TABS_LIST_ID = "font.plugin.tabs.list"; + //@formatter:off + private final static Color SELECTED_TAB_COLOR = new GColor("color.bg.listing.tabs.selected"); + private final static Color HIGHLIGHTED_TAB_BG_COLOR = new GColor("color.bg.listing.tabs.highlighted"); + private final static Icon EMPTY16_ICON = Icons.EMPTY_ICON; + private final static Icon EMPTY8_ICON = new GIcon("icon.plugin.programmanager.empty.small"); + private final static Icon CLOSE_ICON = new GIcon("icon.plugin.programmanager.close"); + private final static Icon HIGHLIGHT_CLOSE_ICON = new GIcon("icon.plugin.programmanager.close.highlight"); + private final static Icon LIST_ICON = new GIcon("icon.plugin.programmanager.list"); + private final static Icon TRANSIENT_ICON = new GIcon("icon.plugin.programmanager.transient"); + //@formatter:on - private final static Color SELECTED_TAB_COLOR = new Color(120, 140, 189); - private final static Color HIGHLIGHTED_TAB_COLOR = SELECTED_TAB_COLOR.brighter(); - private final static Icon EMPTY16_ICON = ResourceManager.loadImage("images/EmptyIcon16.gif"); - private final static Icon EMPTY8_ICON = ResourceManager.loadImage("images/empty8x16.png"); - private final static Icon CLOSE_ICON = ResourceManager.loadImage("images/x.gif"); - private final static Icon HIGHLIGHT_CLOSE_ICON = ResourceManager.loadImage("images/pinkX.gif"); - private final static Icon LIST_ICON = ResourceManager.loadImage("images/VCRFastForward.gif"); - private final static Icon TRANSIENT_ICON = ResourceManager.loadImage("images/link.png", 8, 16); - - private final static Color TEXT_SELECTION_COLOR = Color.WHITE; - private final static Color TEXT_NON_SELECTION_COLOR = UIManager.getColor("Tree.textForeground"); + private final static Color TEXT_SELECTION_COLOR = + new GColor("color.fg.listing.tabs.text.selected"); + private final static Color TEXT_NON_SELECTION_COLOR = + new GColor("color.fg.listing.tabs.text.unselected"); private final static Color BG_SELECTION_COLOR = SELECTED_TAB_COLOR; - private final static Color BG_NON_SELECTION_COLOR = UIManager.getColor("Panel.background"); + private final static Color BG_NON_SELECTION_COLOR = + new GColor("color.bg.listing.tabs.unselected"); + private static final Color BG_COLOR_MORE_TABS_HOVER = + new GColor("color.bg.listing.tabs.more.tabs.hover"); - private static final Font LABEL_FONT = new Font("Tahoma", Font.PLAIN, 11); - private static final Font LIST_LABEL_FONT = new Font("Tahoma", Font.BOLD, 9); private static final String DEFAULT_HIDDEN_COUNT_STR = "99"; /** A list of tabs that are hidden from view due to space constraints */ @@ -70,8 +77,6 @@ public class MultiTabPanel extends JPanel { private MultiTabPlugin multiTabPlugin; private ProgramListPanel programListPanel; private Border defaultListLabelBorder; - private Border noTabsBorder; - private Border tabbedBorder; private JLabel showHiddenListLabel; private JDialog listWindow; private JTextField filterField; @@ -126,8 +131,8 @@ public class MultiTabPanel extends JPanel { currentProgram = null; ArrayList list = new ArrayList<>(linkedProgramMap.keySet()); - for (int i = 0; i < list.size(); i++) { - doRemoveProgram(list.get(i)); + for (Program element : list) { + doRemoveProgram(element); } linkedProgramMap.clear(); visibleTabList.clear(); @@ -206,8 +211,6 @@ public class MultiTabPanel extends JPanel { return false; } - //////////////////////////////////////////////////////////// - private TabPanel createProgramTab(final Program program, boolean isSelected) { final JPanel labelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 1)); labelPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 10)); @@ -215,7 +218,7 @@ public class MultiTabPanel extends JPanel { JLabel nameLabel = new GDLabel(); nameLabel.setIconTextGap(1); nameLabel.setName("objectName"); // junit access - nameLabel.setFont(LABEL_FONT); + Gui.registerFont(nameLabel, FONT_TABS_ID); Color foregroundColor = isSelected ? TEXT_SELECTION_COLOR : TEXT_NON_SELECTION_COLOR; nameLabel.setForeground(foregroundColor); @@ -632,11 +635,11 @@ public class MultiTabPanel extends JPanel { private JLabel createLabel() { JLabel newLabel = new GDLabel(DEFAULT_HIDDEN_COUNT_STR, LIST_ICON, SwingConstants.LEFT); newLabel.setIconTextGap(0); - newLabel.setFont(LIST_LABEL_FONT); + Gui.registerFont(newLabel, FONT_TABS_LIST_ID); newLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 0, 4)); newLabel.setToolTipText("Show Tab List"); newLabel.setName("showList"); - newLabel.setBackground(new Color(255, 226, 213)); + newLabel.setBackground(BG_COLOR_MORE_TABS_HOVER); defaultListLabelBorder = newLabel.getBorder(); final Border hoverBorder = BorderFactory.createBevelBorder(BevelBorder.RAISED); @@ -912,7 +915,8 @@ public class MultiTabPanel extends JPanel { //================================================================================================== private class TabPanel extends JPanel { - private Color defaultBackgroundColor; + private Color defaultBgColor; + private Color defaultFgColor; protected final JLabel nameLabel; protected final JPanel labelPanel; protected final JLabel iconLabel; @@ -920,7 +924,8 @@ public class MultiTabPanel extends JPanel { private TabPanel(Color backgroundColor, Program program, JLabel nameLabel, JPanel labelPanel, JLabel iconLabel) { - this.defaultBackgroundColor = backgroundColor; + this.defaultBgColor = backgroundColor; + this.defaultFgColor = nameLabel.getForeground(); this.program = program; this.nameLabel = nameLabel; this.labelPanel = labelPanel; @@ -942,14 +947,19 @@ public class MultiTabPanel extends JPanel { } void paintHighlightedColor(boolean paintHighlight) { - Color newBackgroundColor = defaultBackgroundColor; + Color newBgColor = defaultBgColor; + Color newFgColor = defaultFgColor; if (paintHighlight) { - newBackgroundColor = HIGHLIGHTED_TAB_COLOR; + newBgColor = HIGHLIGHTED_TAB_BG_COLOR; + newFgColor = TEXT_SELECTION_COLOR; + } - setBackground(newBackgroundColor); - nameLabel.setBackground(newBackgroundColor); - labelPanel.setBackground(newBackgroundColor); - iconLabel.setBackground(newBackgroundColor); + + setBackground(newBgColor); + nameLabel.setBackground(newBgColor); + nameLabel.setForeground(newFgColor); + labelPanel.setBackground(newBgColor); + iconLabel.setBackground(newBgColor); } } @@ -985,9 +995,9 @@ public class MultiTabPanel extends JPanel { @Override void paintHighlightedColor(boolean paintHighlight) { super.paintHighlightedColor(paintHighlight); - Color foreground = Color.WHITE; + Color foreground = TEXT_NON_SELECTION_COLOR; if (paintHighlight) { - foreground = Color.BLACK; + foreground = TEXT_SELECTION_COLOR; } // this tab is selected, so change the foreground to be readable diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java index 1a05165d30..95a0e4fb21 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramListPanel.java @@ -30,16 +30,20 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Document; import docking.widgets.list.GListCellRenderer; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.program.model.listing.Program; /** - * Panel that displays the overflow of currently open programs that can be choosen. + * Panel that displays the overflow of currently open programs that can be chosen. *

* Programs that don't have a visible tab are displayed in bold. */ class ProgramListPanel extends JPanel { - private static final Color BACKGROUND_COLOR = new Color(255, 255, 230); + private static final Color BACKGROUND_COLOR = new GColor("color.bg.listing.tabs.list"); + private static final Color FOREGROUND_COLOR = new GColor("color.fg.listing.tabs.list"); + private List hiddenList; private List shownList; private JList programList; @@ -74,9 +78,6 @@ class ProgramListPanel extends JPanel { programList.clearSelection(); } - /** - * Return the JList component. - */ JList getList() { return programList; } @@ -115,6 +116,7 @@ class ProgramListPanel extends JPanel { initListModel(); programList = new JList<>(listModel); programList.setBackground(BACKGROUND_COLOR); + programList.setForeground(FOREGROUND_COLOR); programList.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); programList.addMouseMotionListener(new MouseMotionAdapter() { @Override @@ -147,7 +149,7 @@ class ProgramListPanel extends JPanel { // add some padding around the panel Border innerBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5); - Border outerBorder = BorderFactory.createLineBorder(Color.BLACK); + Border outerBorder = BorderFactory.createLineBorder(Java.BORDER); Border compoundBorder = BorderFactory.createCompoundBorder(outerBorder, innerBorder); setBorder(compoundBorder); @@ -157,6 +159,7 @@ class ProgramListPanel extends JPanel { private JTextField createFilterField() { JTextField newFilterField = new JTextField(20); newFilterField.setBackground(BACKGROUND_COLOR); + newFilterField.setForeground(FOREGROUND_COLOR); newFilterField.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); newFilterField.getDocument().addDocumentListener(new DocumentListener() { @@ -222,11 +225,11 @@ class ProgramListPanel extends JPanel { private void initListModel() { listModel.clear(); - for (int i = 0; i < hiddenList.size(); i++) { - listModel.addElement(hiddenList.get(i)); + for (Program element : hiddenList) { + listModel.addElement(element); } - for (int i = 0; i < shownList.size(); i++) { - listModel.addElement(shownList.get(i)); + for (Program element : shownList) { + listModel.addElement(element); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/RedoAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/RedoAction.java index e7ffcd1c18..1728e08b7d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/RedoAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/RedoAction.java @@ -27,7 +27,7 @@ public class RedoAction extends AbstractUndoRedoAction { public static final String SUBGROUP = "2Redo"; public RedoAction(ProgramManagerPlugin plugin, PluginTool tool) { - super(tool, plugin, "Redo", "images/redo.png", "ctrl shift Z", SUBGROUP); + super(tool, plugin, "Redo", "icon.redo", "ctrl shift Z", SUBGROUP); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/SaveProgramAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/SaveProgramAction.java index f44a331334..607b2b882a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/SaveProgramAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/SaveProgramAction.java @@ -15,12 +15,12 @@ */ package ghidra.app.plugin.core.progmgr; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.*; import docking.tool.ToolConstants; import ghidra.program.model.listing.Program; -import resources.ResourceManager; +import resources.Icons; /** * Action class for the "Save Program" action @@ -33,7 +33,7 @@ public class SaveProgramAction extends AbstractProgramNameSwitchingAction { menuData.setMenuGroup(group); menuData.setMenuSubGroup(Integer.toString(subGroup)); setMenuBarData(menuData); - ImageIcon icon = ResourceManager.loadImage("images/disk.png"); + Icon icon = Icons.SAVE_ICON; setToolBarData(new ToolBarData(icon, ToolConstants.TOOLBAR_GROUP_ONE)); setKeyBindingData(new KeyBindingData("ctrl S")); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/TransactionMonitor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/TransactionMonitor.java index eda5259631..91fcd6eb40 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/TransactionMonitor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/TransactionMonitor.java @@ -22,17 +22,17 @@ import java.util.List; import javax.swing.*; +import generic.theme.GIcon; import ghidra.framework.data.DomainObjectAdapterDB; import ghidra.framework.model.Transaction; import ghidra.framework.model.TransactionListener; import ghidra.program.database.ProgramDB; import ghidra.program.model.listing.Program; import ghidra.util.HTMLUtilities; -import resources.ResourceManager; class TransactionMonitor extends JComponent implements TransactionListener { - private static ImageIcon busyIcon; + private static Icon busyIcon; private static Dimension prefSize; ProgramDB program; @@ -40,7 +40,7 @@ class TransactionMonitor extends JComponent implements TransactionListener { TransactionMonitor() { super(); - busyIcon = ResourceManager.loadImage("images/editbytes.gif"); + busyIcon = new GIcon("icon.plugin.programmanager.busy"); prefSize = new Dimension(busyIcon.getIconWidth(), busyIcon.getIconHeight()); ToolTipManager.sharedInstance().registerComponent(this); } @@ -60,27 +60,18 @@ class TransactionMonitor extends JComponent implements TransactionListener { repaint(); } - /** - * @see ghidra.framework.model.TransactionListener#transactionStarted(ghidra.framework.data.DomainObjectAdapterDB, ghidra.framework.model.Transaction) - */ @Override public void transactionStarted(DomainObjectAdapterDB domainObj, Transaction tx) { lastTx = tx; repaint(); } - /** - * @see ghidra.framework.model.TransactionListener#transactionEnded(ghidra.framework.data.DomainObjectAdapterDB) - */ @Override public void transactionEnded(DomainObjectAdapterDB domainObj) { lastTx = null; repaint(); } - /** - * @see ghidra.framework.model.TransactionListener#undoStackChanged(ghidra.framework.data.DomainObjectAdapterDB) - */ @Override public void undoStackChanged(DomainObjectAdapterDB domainObj) { // don't care @@ -91,17 +82,11 @@ class TransactionMonitor extends JComponent implements TransactionListener { // don't care } - /** - * @see java.awt.Component#getPreferredSize() - */ @Override public Dimension getPreferredSize() { return new Dimension(prefSize); } - /** - * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) - */ @Override protected void paintComponent(Graphics g) { g.setColor(getBackground()); @@ -111,9 +96,6 @@ class TransactionMonitor extends JComponent implements TransactionListener { } } - /** - * @see javax.swing.JComponent#getToolTipText() - */ @Override public String getToolTipText() { if (lastTx != null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/UndoAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/UndoAction.java index 899f85be41..b01591fd5f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/UndoAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/UndoAction.java @@ -27,7 +27,7 @@ public class UndoAction extends AbstractUndoRedoAction { public static final String SUBGROUP = "1Undo"; public UndoAction(ProgramManagerPlugin plugin, PluginTool tool) { - super(tool, plugin, "Undo", "images/undo.png", "ctrl Z", SUBGROUP); + super(tool, plugin, "Undo", "icon.undo", "ctrl Z", SUBGROUP); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DnDTreeCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DnDTreeCellRenderer.java index bc28bf23ab..43c2e48d82 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DnDTreeCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DnDTreeCellRenderer.java @@ -19,10 +19,14 @@ import java.awt.*; import java.awt.image.BufferedImage; import java.util.*; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; import docking.widgets.GComponent; +import generic.theme.GColor; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; import ghidra.program.model.listing.Group; import resources.ResourceManager; @@ -30,11 +34,10 @@ import resources.ResourceManager; * Cell renderer for the drag and drop tree. */ class DnDTreeCellRenderer extends DefaultTreeCellRenderer { + private static final Color BACKGROUND_UNSELECTED = new GColor("color.bg.tree"); + private static final Color BACKGROUND_SELECTED = new GColor("color.bg.tree.selected"); - private static final String DOCS = "images/openBookBlue.png"; private static final String DISABLED_DOCS = "DisabledDocument.gif"; - static final String FRAGMENT = "images/codeNotInView.gif"; - private static final String EMPTY_FRAGMENT = "images/emptyFragment.gif"; private static final String DISABLED_FRAGMENT = "DisabledFragment"; private static final String DISABLED_VIEWED_FRAGMENT = "DisabledViewedFragment"; private static final String DISABLED_EMPTY_FRAGMENT = "DisabledEmptyFragment"; @@ -46,13 +49,18 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer { private static final String DISABLED_CLOSED_FOLDER = "DisabledClosedFolder"; private static final String DISABLED_OPEN_FOLDER = "DisabledOpenedFolder"; - static final String VIEWED_FRAGMENT = "images/codeInView.gif"; - static final String VIEWED_EMPTY_FRAGMENT = "images/emptyFragmentInView.gif"; - static final String VIEWED_CLOSED_FOLDER = "images/closedFolderInView.png"; - static final String VIEWED_OPEN_FOLDER = "images/openFolderInView.png"; - static final String VIEWED_CLOSED_FOLDER_WITH_DESC = "images/closedDescendantsInView.png"; - static final String CLOSED_FOLDER = "images/closedFolder.png"; // closed folder not in view - static final String OPEN_FOLDER = "images/openFolder.png"; + private static final String DOCS = "icon.plugin.programtree.docs"; + static final String FRAGMENT = "icon.plugin.programtree.fragment"; + private static final String EMPTY_FRAGMENT = "icon.plugin.programtree.fragment.empty"; + + static final String VIEWED_FRAGMENT = "icon.plugin.programtree.fragment.viewed"; + static final String VIEWED_EMPTY_FRAGMENT = "icon.plugin.programtree.fragment.viewed.empty"; + static final String VIEWED_CLOSED_FOLDER = "icon.plugin.programtree.fragment.closed.folder"; + static final String VIEWED_OPEN_FOLDER = "icon.plugin.programtree.fragment.open.folder"; + static final String VIEWED_CLOSED_FOLDER_WITH_DESC = + "icon.plugin.programtree.fragment.viewed.closed.folder.with.description"; + static final String CLOSED_FOLDER = "icon.plugin.programtree.closed.folder"; + static final String OPEN_FOLDER = "icon.plugin.programtree.open.folder"; private Map iconMap; @@ -67,8 +75,8 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer { */ DnDTreeCellRenderer() { super(); - defaultNonSelectionColor = getBackgroundNonSelectionColor(); - defaultSelectionColor = getBackgroundSelectionColor(); + defaultNonSelectionColor = BACKGROUND_UNSELECTED; + defaultSelectionColor = BACKGROUND_SELECTED; rowForFeedback = -1; // disable HTML rendering @@ -142,7 +150,7 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer { /** * Set colors for background according to the draw feedback state. - * @param selected + * @param selected true if selected * @param row row of the node * @param node node to render * @param dtree tree @@ -307,24 +315,21 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer { private void loadImages() { // try to load icon images iconMap = new HashMap<>(); - String[] filenames = + String[] iconIds = { DOCS, FRAGMENT, EMPTY_FRAGMENT, VIEWED_FRAGMENT, VIEWED_EMPTY_FRAGMENT, - VIEWED_CLOSED_FOLDER, VIEWED_OPEN_FOLDER, VIEWED_CLOSED_FOLDER_WITH_DESC, // descendants in view - CLOSED_FOLDER, // closed folder not in view - OPEN_FOLDER, // opened folder not in the view + VIEWED_CLOSED_FOLDER, VIEWED_OPEN_FOLDER, VIEWED_CLOSED_FOLDER_WITH_DESC, + CLOSED_FOLDER, OPEN_FOLDER, }; - String[] disabledFilenames = { DISABLED_DOCS, DISABLED_FRAGMENT, DISABLED_EMPTY_FRAGMENT, + String[] disabledNames = { DISABLED_DOCS, DISABLED_FRAGMENT, DISABLED_EMPTY_FRAGMENT, DISABLED_VIEWED_EMPTY_FRAGMENT, DISABLED_VIEWED_FRAGMENT, DISABLED_VIEWED_CLOSED_FOLDER, DISABLED_VIEWED_OPEN_FOLDER, DISABLED_VIEWED_CLOSED_FOLDER_WITH_DESC, DISABLED_CLOSED_FOLDER, DISABLED_OPEN_FOLDER, }; - for (int i = 0; i < filenames.length; i++) { - ImageIcon icon = ResourceManager.loadImage(filenames[i]); - if (icon != null) { - iconMap.put(filenames[i], icon); - Icon disabledIcon = getDisabledIcon(filenames[i], icon); - iconMap.put(disabledFilenames[i], disabledIcon); - } + for (int i = 0; i < iconIds.length; i++) { + GIcon icon = new GIcon(iconIds[i]); + iconMap.put(iconIds[i], icon); + Icon disabledIcon = getDisabledIcon(iconIds[i], icon); + iconMap.put(disabledNames[i], disabledIcon); } } @@ -337,13 +342,13 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer { return dim; } - static Icon getDisabledIcon(String imageName, ImageIcon icon) { - Image cutImage = icon.getImage(); + static Icon getDisabledIcon(String imageName, GIcon icon) { + Image cutImage = icon.getImageIcon().getImage(); BufferedImage bufferedImage = new BufferedImage(cutImage.getWidth(null), cutImage.getHeight(null), BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = bufferedImage.createGraphics(); g2d.drawImage(cutImage, 0, 0, null); - g2d.setColor(new Color(255, 255, 255, 128)); + g2d.setColor(Colors.DISABLED); g2d.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight()); return ResourceManager.getImageIconFromImage(imageName, bufferedImage); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java index e0852ccc6a..5d7e59c13a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/DragNDropTree.java @@ -29,6 +29,8 @@ import docking.DockingUtils; import docking.actions.KeyBindingUtils; import docking.dnd.*; import docking.widgets.table.AutoscrollAdapter; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; /** * Class to support Drag and Drop; it is also responsible for @@ -37,6 +39,9 @@ import docking.widgets.table.AutoscrollAdapter; */ public abstract class DragNDropTree extends JTree implements Draggable, Droppable, Autoscroll { + private static final Color BG_COLOR_DRAG_NO_SELECTION = + new GColor("color.bg.tree.drag.no.selection"); + private AutoscrollAdapter autoscroller; protected DefaultTreeModel treeModel; @@ -63,15 +68,9 @@ public abstract class DragNDropTree extends JTree implements Draggable, Droppabl protected Color nonSelectionDragColor; protected int relativeMousePos; // mouse position within the node: - // -1 --> above node, - // 0 --> at the node - // 1 --> below the node - - /** - * Construct a new DragNDropTree. - */ public DragNDropTree(DefaultTreeModel model) { super(model); + setBackground(new GColor("color.bg.tree")); treeModel = model; this.root = (ProgramNode) model.getRoot(); //setEditable(true); // edit interferes with drag gesture listener @@ -82,7 +81,7 @@ public abstract class DragNDropTree extends JTree implements Draggable, Droppabl dndCellRenderer = new DnDTreeCellRenderer(); setCellRenderer(dndCellRenderer); plafSelectionColor = dndCellRenderer.getBackgroundSelectionColor(); - nonSelectionDragColor = new Color(204, 204, 255); + nonSelectionDragColor = BG_COLOR_DRAG_NO_SELECTION; initDragNDrop(); ToolTipManager.sharedInstance().registerComponent(this); autoscroller = new AutoscrollAdapter(this, getRowHeight()); @@ -164,7 +163,8 @@ public abstract class DragNDropTree extends JTree implements Draggable, Droppabl public void dragCanceled(DragSourceDropEvent event) { draggedNodes = null; dndCellRenderer.setBackgroundSelectionColor(plafSelectionColor); - dndCellRenderer.setBackgroundNonSelectionColor(dndCellRenderer.getBackgroundNonSelectionColor()); + dndCellRenderer + .setBackgroundNonSelectionColor(dndCellRenderer.getBackgroundNonSelectionColor()); } ////////////////////////////////////////////////////////////////////// @@ -263,8 +263,8 @@ public abstract class DragNDropTree extends JTree implements Draggable, Droppabl } else { destinationNode = null; - dndCellRenderer.setSelectionForDrag(Color.red); - dndCellRenderer.setNonSelectionForDrag(Color.red); + dndCellRenderer.setSelectionForDrag(Colors.ERROR); + dndCellRenderer.setNonSelectionForDrag(Colors.ERROR); } Point p = e.getLocation(); dndCellRenderer.setRowForFeedback(getRowForLocation(p.x, p.y)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java index 2da9e4d094..81878f9acf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java @@ -315,8 +315,9 @@ public class ProgramDnDTree extends DragNDropTree { return false; } try { - Object data = e.getTransferable().getTransferData( - SelectionTransferable.localProgramSelectionFlavor); + Object data = e.getTransferable() + .getTransferData( + SelectionTransferable.localProgramSelectionFlavor); SelectionTransferData transferData = (SelectionTransferData) data; return program.getDomainFile().getPathname().equals(transferData.getProgramPath()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin.java index 6f38511c1e..c242f8b982 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin.java @@ -23,6 +23,7 @@ import javax.swing.tree.TreePath; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.cmd.module.*; import ghidra.app.events.ProgramActivatedPluginEvent; @@ -46,7 +47,6 @@ import ghidra.util.datastruct.StringKeyIndexer; import ghidra.util.exception.AssertException; import ghidra.util.task.RunManager; import resources.Icons; -import resources.ResourceManager; /** * Plugin that creates view provider services to show the trees in a program. @@ -81,8 +81,6 @@ public class ProgramTreePlugin extends ProgramPlugin private static final String TREE_NAME = "TreeName"; private static final String TOGGLE_STATE = "NavigationToggleState"; - private final static String OPEN_VIEW_ICON_NAME = "images/openSmallFolder.png"; - private final static String CREATE_ICON_NAME = "images/layout_add.png"; private final static Icon NAVIGATION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; private HashMap providerMap;// map of view providers, key is the name @@ -480,7 +478,8 @@ public class ProgramTreePlugin extends ProgramPlugin /** * Close the view if we are not trying to close the last view. * - * @param treeViewProvider + * + * @param treeViewProvider the provider * @return true if the view can be closed */ boolean closeView(TreeViewProvider treeViewProvider) { @@ -516,10 +515,9 @@ public class ProgramTreePlugin extends ProgramPlugin /** * Method renameView. - * - * @param treeViewProvider - * @param newName - * @return boolean + * @param treeViewProvider the provider + * @param newName the new name + * @return true if renamed */ boolean renameView(TreeViewProvider treeViewProvider, String newName) { Listing listing = currentProgram.getListing(); @@ -932,7 +930,7 @@ public class ProgramTreePlugin extends ProgramPlugin } }; - Icon icon = ResourceManager.loadImage(OPEN_VIEW_ICON_NAME); + Icon icon = new GIcon("icon.plugin.programtree.open.tree"); openAction.setToolBarData(new ToolBarData(icon)); openAction.setEnabled(false); openAction.setDescription("Open Tree View"); @@ -945,7 +943,7 @@ public class ProgramTreePlugin extends ProgramPlugin } }; - icon = ResourceManager.loadImage(CREATE_ICON_NAME); + icon = new GIcon("icon.plugin.programtree.new.tree"); createAction.setToolBarData(new ToolBarData(icon)); createAction.setEnabled(false); createAction.setDescription(HTMLUtilities.toHTML("Create a new default tree view; shows\n" + diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/TreeDragSrcAdapter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/TreeDragSrcAdapter.java index bb0244c6ab..774b549507 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/TreeDragSrcAdapter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/TreeDragSrcAdapter.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,50 +15,41 @@ */ package ghidra.app.plugin.core.programtree; - import java.awt.*; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragSource; -import javax.swing.ImageIcon; - import docking.dnd.DragSrcAdapter; import docking.dnd.Draggable; - -import resources.ResourceManager; - +import generic.theme.GIcon; /** - * Drag source adapter on tree to set the custom cursors for the drag under - * feedback. + * Drag source adapter on tree to set the custom cursors for the drag under feedback. */ class TreeDragSrcAdapter extends DragSrcAdapter { - - private static String MOVE_CURSOR_FILENAME = "images/dragMoveCursor.gif"; - private static String COPY_CURSOR_FILENAME = "images/dragCopyCursor.gif"; - - private static String MOVE_NAME = "MoveCursor"; - private static String COPY_NAME = "CopyCursor"; - + + private static final String MOVE_CURSOR_ID = "icon.plugin.programtree.drag.move"; + private static final String COPY_CURSOR_ID = "icon.plugin.programtree.drag.copy"; + + private static final String MOVE_NAME = "MoveCursor"; + private static final String COPY_NAME = "CopyCursor"; + private Cursor feedbackCursor; private Cursor copyCursor; - private Cursor moveCursor; - + private Cursor moveCursor; + public TreeDragSrcAdapter(Draggable dragComponent) { super(dragComponent); } - - /** - * @see docking.dnd.DragSrcAdapter#getDropOkCursor(int) - */ + @Override - protected Cursor getDropOkCursor(int action) { + protected Cursor getDropOkCursor(int action) { if (feedbackCursor != null) { return feedbackCursor; } return super.getDropOkCursor(action); } - + /** * Get the appropriate cursor for the action and mouse position within the node. * @param action move, copy, link @@ -79,14 +69,14 @@ class TreeDragSrcAdapter extends DragSrcAdapter { } } else { - c = DragSource.DefaultCopyDrop; - if (relativeMousePos != 0) { - c = getCopyCursor(); - } + c = DragSource.DefaultCopyDrop; + if (relativeMousePos != 0) { + c = getCopyCursor(); + } } - return c; + return c; } - + /** * Set the cursor for drag under feedback. * @param c cursor for feedback; may be null if there is no feedback. @@ -94,34 +84,26 @@ class TreeDragSrcAdapter extends DragSrcAdapter { void setFeedbackCursor(Cursor c) { feedbackCursor = c; } - - private Cursor getMoveCursor() { - if ( moveCursor == null ) { - moveCursor = createCursor(MOVE_CURSOR_FILENAME, MOVE_NAME, new Point(0, 16)); - } - return moveCursor; - } - private Cursor getCopyCursor() { - if ( copyCursor == null ) { - copyCursor = createCursor(COPY_CURSOR_FILENAME, COPY_NAME, new Point(0, 24)); - } - return copyCursor; - } - - /** - * Create a cursor with the filename and cursor name. - * @param filename a name from the images resource - * @param cursorName name to use int the createCustomCursor() - * method on Toolkit - */ - private static Cursor createCursor(String filename, String cursorName, - Point hotSpot) { - ImageIcon icon = ResourceManager.loadImage(filename); - Image image = icon.getImage(); + private Cursor getMoveCursor() { + if (moveCursor == null) { + moveCursor = createCursor(MOVE_CURSOR_ID, MOVE_NAME, new Point(0, 16)); + } + return moveCursor; + } + + private Cursor getCopyCursor() { + if (copyCursor == null) { + copyCursor = createCursor(COPY_CURSOR_ID, COPY_NAME, new Point(0, 24)); + } + return copyCursor; + } + + private static Cursor createCursor(String id, String cursorName, Point hotSpot) { + GIcon icon = new GIcon(id); + Image image = icon.getImageIcon().getImage(); Toolkit tk = Toolkit.getDefaultToolkit(); - Cursor cursor = tk.createCustomCursor(image, hotSpot, cursorName); - return cursor; + return tk.createCustomCursor(image, hotSpot, cursorName); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityPlugin.java index f3bf1fa77f..7c4f0b7771 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityPlugin.java @@ -23,6 +23,7 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.context.ListingActionContext; import ghidra.app.plugin.PluginCategoryNames; @@ -32,8 +33,6 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.program.util.*; import ghidra.util.HelpLocation; -import resources.ResourceManager; -import resources.icons.RotateIcon; //@formatter:off @PluginInfo( @@ -49,8 +48,7 @@ import resources.icons.RotateIcon; public class FunctionReachabilityPlugin extends ProgramPlugin { // TODO - static final Icon ICON = new RotateIcon( - ResourceManager.loadImage("images/function_graph_curvey.png"), 90); + static final Icon ICON = new GIcon("icon.plugin.reachability.provider"); private DockingAction showProviderAction; private List providers = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditMemoryReferencePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditMemoryReferencePanel.java index 353a696771..bc66418267 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditMemoryReferencePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditMemoryReferencePanel.java @@ -24,16 +24,18 @@ import java.util.List; import javax.swing.*; import javax.swing.border.LineBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.table.AbstractTableModel; import org.jdom.Element; +import docking.DropDownMenuIcon; import docking.widgets.checkbox.GCheckBox; import docking.widgets.combobox.GhidraComboBox; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.app.util.AddressInput; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; @@ -41,12 +43,13 @@ import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.*; import ghidra.program.util.OperandFieldLocation; import ghidra.program.util.ProgramLocation; +import ghidra.util.Swing; import ghidra.util.layout.PairLayout; -import resources.ResourceManager; class EditMemoryReferencePanel extends EditReferencePanel { - private static ImageIcon PULLDOWN_ICON = ResourceManager.loadImage("images/menu16.gif"); + private static final Color BUTTON_COLOR = new GColor("color.fg.button"); + private static final Icon MENU_ICON = new DropDownMenuIcon(BUTTON_COLOR); private static final RefType[] MEM_REF_TYPES = RefTypeFactory.getMemoryRefTypes(); @@ -83,13 +86,7 @@ class EditMemoryReferencePanel extends EditReferencePanel { @Override public void requestFocus() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - // do later to override the default later nature of focus - toAddressField.requestFocus(); - } - }); + Swing.runLater(() -> toAddressField.requestFocus()); } private void buildPanel() { @@ -97,12 +94,7 @@ class EditMemoryReferencePanel extends EditReferencePanel { offsetCheckbox = new GCheckBox("Offset:"); offsetCheckbox.setHorizontalAlignment(SwingConstants.RIGHT); - offsetCheckbox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - enableOffsetField(offsetCheckbox.isSelected()); - } - }); + offsetCheckbox.addChangeListener(e -> enableOffsetField(offsetCheckbox.isSelected())); offsetField = new JTextField(); addrLabel = new GDLabel("Base Address:"); @@ -112,7 +104,7 @@ class EditMemoryReferencePanel extends EditReferencePanel { toAddressField = new AddressInput(); - addrHistoryButton = new JButton(PULLDOWN_ICON); + addrHistoryButton = new JButton(MENU_ICON); addrHistoryButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { @@ -150,11 +142,11 @@ class EditMemoryReferencePanel extends EditReferencePanel { enableOffsetField(false); } - private void enableOffsetField(boolean state) { - offsetCheckbox.setSelected(state); - offsetField.setEnabled(state); - offsetField.setBackground(state ? Color.WHITE : getBackground()); - if (!state) { + private void enableOffsetField(boolean enabled) { + offsetCheckbox.setSelected(enabled); + offsetField.setEnabled(enabled); + offsetField.setBackground(enabled ? Colors.BACKGROUND : getBackground()); + if (!enabled) { offsetField.setText("0x0"); } else { @@ -173,7 +165,7 @@ class EditMemoryReferencePanel extends EditReferencePanel { } } } - addrLabel.setText(state ? "Base Address:" : "To Address:"); + addrLabel.setText(enabled ? "Base Address:" : "To Address:"); } private void populateRefTypes(RefType adhocType) { @@ -304,8 +296,9 @@ class EditMemoryReferencePanel extends EditReferencePanel { toAddr = fromCu.getAddress(fromOpIndex); } if (toAddr != null) { - Reference r = p.getReferenceManager().getReference(fromCu.getMinAddress(), toAddr, - fromOpIndex); + Reference r = p.getReferenceManager() + .getReference(fromCu.getMinAddress(), toAddr, + fromOpIndex); if (r != null) { toAddr = null; if (r.isOffsetReference()) { @@ -540,7 +533,7 @@ class EditMemoryReferencePanel extends EditReferencePanel { model = new HistoryTableModel(fromCodeUnit.getProgram()); displayTable = new JTable(model); displayTable.setTableHeader(null); - displayTable.setBorder(new LineBorder(Color.BLACK)); + displayTable.setBorder(new LineBorder(Java.BORDER)); displayTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); displayTable.addMouseListener(new MouseAdapter() { @@ -588,24 +581,26 @@ class EditMemoryReferencePanel extends EditReferencePanel { p.y += toAddressField.getHeight(); historyWin.setLocation(p); - KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener( - "focusOwner", new PropertyChangeListener() { - boolean hasFocus = false; + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .addPropertyChangeListener( + "focusOwner", new PropertyChangeListener() { + boolean hasFocus = false; - @Override - public void propertyChange(PropertyChangeEvent evt) { - Object focusOwner = evt.getNewValue(); - if (focusOwner == displayTable || focusOwner == historyWin) { - hasFocus = true; - } - else if (hasFocus) { - hasFocus = false; - KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener( - "focusOwner", this); - hideAddressHistoryPopup(); - } - } - }); + @Override + public void propertyChange(PropertyChangeEvent evt) { + Object focusOwner = evt.getNewValue(); + if (focusOwner == displayTable || focusOwner == historyWin) { + hasFocus = true; + } + else if (hasFocus) { + hasFocus = false; + KeyboardFocusManager.getCurrentKeyboardFocusManager() + .removePropertyChangeListener( + "focusOwner", this); + hideAddressHistoryPopup(); + } + } + }); historyWin.setVisible(true); @@ -627,19 +622,9 @@ class EditMemoryReferencePanel extends EditReferencePanel { @Override public void componentShown(ComponentEvent e) { + // stub } }); - - //displayList.requestFocus(); - -// historyWin.addFocusListener(new FocusListener() { -// public void focusGained(FocusEvent e) { -// } -// public void focusLost(FocusEvent e) { -// toggleAddressHistoryPopup(); -// } -// }); - } private void updateTableSelectionForEvent(MouseEvent anEvent) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferencesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferencesProvider.java index b883b22de3..41dbbd3899 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferencesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/EditReferencesProvider.java @@ -35,6 +35,9 @@ import docking.dnd.DropTgtAdapter; import docking.dnd.Droppable; import docking.widgets.checkbox.GCheckBox; import docking.widgets.table.*; +import generic.theme.GColor; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.util.SelectionTransferData; import ghidra.app.util.SelectionTransferable; @@ -52,31 +55,31 @@ import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTable; import ghidra.util.task.SwingUpdateManager; import resources.Icons; -import resources.ResourceManager; public class EditReferencesProvider extends ComponentProviderAdapter implements DomainObjectListener, ChangeListener { private static final String ADD_REFS_GROUP = "AddReferences"; + //@formatter:off private static final HelpLocation HELP = new HelpLocation("ReferencesPlugin", "View_Edit_References_From"); - private static Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static Icon EDIT_ICON = ResourceManager.loadImage("images/editbytes.gif"); - private static Icon DELETE_ICON = ResourceManager.loadImage("images/edit-delete.png"); - private static Icon RECV_LOCATION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; - //private static Icon RECV_LOCATION_OFF_ICON = ResourceManager.loadImage("images/locationInOff.gif"); - private static Icon SEND_LOCATION_ICON = Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON; - //private static Icon SEND_LOCATION_OFF_ICON = ResourceManager.loadImage("images/locationOutOff.gif"); - private static Icon HOME_ICON = ResourceManager.loadImage("images/go-home.png"); - private static Icon SELECT_ICON = ResourceManager.loadImage("images/text_align_justify.png"); + private static final Icon ADD_ICON = Icons.ADD_ICON; + private static final Icon EDIT_ICON = new GIcon("icon.base.edit.bytes"); + private static final Icon DELETE_ICON = Icons.DELETE_ICON; + private static final Icon RECV_LOCATION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; + private static final Icon SEND_LOCATION_ICON = Icons.NAVIGATE_ON_OUTGOING_EVENT_ICON; + private static final Icon HOME_ICON = Icons.HOME_ICON; + private static final Icon SELECT_ICON = Icons.MAKE_SELECTION_ICON; + //@formatter:on private static final String TITLE_PREFIX = "References Editor "; static int MNEMONIC_OPINDEX = ReferenceManager.MNEMONIC; - static Color HIGHLIGHT_COLOR = new Color(205, 205, 205); + static Color BG_COLOR_ACTIVE_OPERAND = + new GColor("color.bg.plugin.references.table.active.operand"); private static final DataFlavor[] ACCEPTABLE_DROP_FLAVORS = new DataFlavor[] { SelectionTransferable.localProgramSelectionFlavor }; @@ -132,8 +135,9 @@ public class EditReferencesProvider extends ComponentProviderAdapter if (currentCodeUnit != null) { Memory memory = currentCodeUnit.getProgram().getMemory(); try { - Object data = e.getTransferable().getTransferData( - SelectionTransferable.localProgramSelectionFlavor); + Object data = e.getTransferable() + .getTransferData( + SelectionTransferable.localProgramSelectionFlavor); AddressSetView view = ((SelectionTransferData) data).getAddressSet(); if (memory.contains(view)) { return true; @@ -530,7 +534,7 @@ public class EditReferencesProvider extends ComponentProviderAdapter private Data findComponent(Data data, Address addr) { while (addr.compareTo(data.getMinAddress()) >= 0) { long offset = addr.subtract(data.getMinAddress()); - Data d = data.getComponentAt((int) offset); + Data d = data.getComponentContaining((int) offset); if (d == null) { break; } @@ -954,8 +958,8 @@ public class EditReferencesProvider extends ComponentProviderAdapter if (!isSelected) { if (ref.getOperandIndex() == instrPanel.getSelectedOpIndex()) { - cb.setBackground(HIGHLIGHT_COLOR); - setBackground(HIGHLIGHT_COLOR); + cb.setBackground(BG_COLOR_ACTIVE_OPERAND); + setBackground(BG_COLOR_ACTIVE_OPERAND); cb.setOpaque(true); } } @@ -1004,7 +1008,7 @@ public class EditReferencesProvider extends ComponentProviderAdapter else { if (ref.getOperandIndex() == instrPanel.getSelectedOpIndex()) { checkbox.setForeground(table.getForeground()); - checkbox.setBackground(HIGHLIGHT_COLOR); + checkbox.setBackground(BG_COLOR_ACTIVE_OPERAND); checkbox.setOpaque(true); } else { @@ -1022,8 +1026,7 @@ public class EditReferencesProvider extends ComponentProviderAdapter RefCellTextRenderer() { defaultFont = getFont(); - boldFont = new Font(defaultFont.getName(), defaultFont.getStyle() | Font.BOLD, - defaultFont.getSize()); + boldFont = defaultFont.deriveFont(defaultFont.getStyle() | Font.BOLD); setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0)); } @@ -1047,7 +1050,7 @@ public class EditReferencesProvider extends ComponentProviderAdapter if (isSelected) { if (bad) { - setForeground(Color.pink); + setForeground(Tables.FG_ERROR_SELECTED); setFont(boldFont); } else { @@ -1060,14 +1063,14 @@ public class EditReferencesProvider extends ComponentProviderAdapter // set color to red if address does not exist in memory if (bad) { - setForeground(Color.red); + setForeground(Tables.FG_ERROR_UNSELECTED); setFont(boldFont); } else { setFont(defaultFont); } if (ref.getOperandIndex() == instrPanel.getSelectedOpIndex()) { - setBackground(HIGHLIGHT_COLOR); + setBackground(BG_COLOR_ACTIVE_OPERAND); setOpaque(true); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java index c1363e5505..5d286166c6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java @@ -27,6 +27,7 @@ import docking.ActionContext; import docking.action.builder.ActionBuilder; import docking.widgets.dialogs.InputDialog; import docking.widgets.table.AbstractSortedTableModel; +import generic.theme.GIcon; import ghidra.app.cmd.refs.*; import ghidra.framework.cmd.Command; import ghidra.framework.cmd.CompoundCmd; @@ -41,17 +42,17 @@ import ghidra.program.model.symbol.SourceType; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.table.GhidraTable; -import resources.ResourceManager; +import resources.Icons; /** * ComponentProvider that displays a table of External Programs. *

*/ public class ExternalReferencesProvider extends ComponentProviderAdapter { - private static ImageIcon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static ImageIcon DELETE_ICON = ResourceManager.loadImage("images/edit-delete.png"); - private static ImageIcon EDIT_ICON = ResourceManager.loadImage("images/editbytes.gif"); - private static ImageIcon CLEAR_ICON = ResourceManager.loadImage("images/erase16.png"); + private static Icon ADD_ICON = Icons.ADD_ICON; + private static Icon DELETE_ICON = Icons.DELETE_ICON; + private static Icon EDIT_ICON = new GIcon("icon.base.edit.bytes"); + private static Icon CLEAR_ICON = Icons.CLEAR_ICON; private JPanel mainPanel; private ExternalNamesTableModel tableModel; @@ -343,7 +344,8 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter { } ExternalNamesRow path = - new ExternalNamesRow(programName, extMgr.getExternalLibraryPath(programName)); + new ExternalNamesRow(programName, + extMgr.getExternalLibraryPath(programName)); paths.add(path); } } @@ -364,7 +366,6 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter { return -1; } - @Override public void dispose() { super.dispose(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java index 7b76ffc81f..98d27c2227 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/InstructionPanel.java @@ -32,6 +32,8 @@ import docking.actions.KeyBindingUtils; import docking.dnd.DropTgtAdapter; import docking.dnd.Droppable; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.Gui; import ghidra.app.util.*; import ghidra.app.util.viewer.field.BrowserCodeUnitFormat; import ghidra.program.model.address.Address; @@ -43,15 +45,13 @@ import ghidra.program.model.symbol.*; class InstructionPanel extends JPanel implements ChangeListener { - private static final int ETCHED_BORDER_THICKNESS = 2; + private static final int BORDER_SIZE = 2; + private static final Border EMPTY_BORDER = new EmptyBorder(BORDER_SIZE, + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE); + private static final Border ETCHED_BORDER = new EtchedBorder(); - private static final Border ETCHED_BORDER = new EtchedBorder(Color.BLACK, Color.GRAY); - private static final Border EMPTY_BORDER = new EmptyBorder(ETCHED_BORDER_THICKNESS, - ETCHED_BORDER_THICKNESS, ETCHED_BORDER_THICKNESS, ETCHED_BORDER_THICKNESS); - - private final static Color UNLOCKED_LABEL_COLOR = Color.blue; - private final static Color NOT_IN_MEMORY_COLOR = Color.red; - private final static Color DEFAULT_FG_COLOR = Color.black; + private final static Color NOT_IN_MEMORY_COLOR = Colors.ERROR; + private final static Color DEFAULT_FG_COLOR = Colors.FOREGROUND; private static final DataFlavor[] ACCEPTABLE_DROP_FLAVORS = new DataFlavor[] { SelectionTransferable.localProgramSelectionFlavor }; @@ -65,7 +65,6 @@ class InstructionPanel extends JPanel implements ChangeListener { private JLabel[] operandLabels; private DropTarget[] dropTargets; // 0: mnemonic, >= 1: operands private JPanel innerPanel; - private Font monoFont; private int activeIndex; private int activeSubIndex; private CodeUnit currentCodeUnit; @@ -85,13 +84,13 @@ class InstructionPanel extends JPanel implements ChangeListener { */ @Override public void dragUnderFeedback(boolean ok, DropTargetDragEvent e) { + // stub } /** * Return true if is OK to drop the transferable at the location * specified the event. * @param e event that has current state of drag and drop operation - * @param data data that is being dragged */ @Override public boolean isDropOk(DropTargetDragEvent e) { @@ -102,26 +101,27 @@ class InstructionPanel extends JPanel implements ChangeListener { updateLabels(getLabelIndex((JLabel) targetComp), -1); try { - Object data = e.getTransferable().getTransferData( - SelectionTransferable.localProgramSelectionFlavor); + Object data = e.getTransferable() + .getTransferData( + SelectionTransferable.localProgramSelectionFlavor); AddressSetView view = ((SelectionTransferData) data).getAddressSet(); if (memory.contains(view)) { return true; } } catch (UnsupportedFlavorException e1) { + // return false } catch (IOException e1) { + // return false } } return false; } - /** - * Revert back to normal if any drag feedback was set. - */ @Override public void undoDragUnderFeedback() { + // stub } /** @@ -156,9 +156,6 @@ class InstructionPanel extends JPanel implements ChangeListener { create(topPad, leftPad, bottomPad, rightPad); } - /** - * Returns the current code unit displayed. - */ CodeUnit getCurrentCodeUnit() { return currentCodeUnit; } @@ -168,14 +165,6 @@ class InstructionPanel extends JPanel implements ChangeListener { updateLabels(activeIndex, activeSubIndex); } - /** - * Set the code unit location. - * @param cu code unit - * @param loc location - * @param opIndex operand index - * @param showBlockID ID for what to show for the block name in the - * operand - */ void setCodeUnitLocation(CodeUnit cu, int opIndex, int subIndex, boolean locked) { if (cu != null) { this.locked = locked; @@ -218,14 +207,11 @@ class InstructionPanel extends JPanel implements ChangeListener { setBorder(border); addressLabel = new GDLabel("FFFFFFFF"); // use a default - - Font font = addressLabel.getFont(); - monoFont = new Font("monospaced", font.getStyle(), font.getSize()); - addressLabel.setFont(monoFont); + Gui.registerFont(addressLabel, "font.monospaced"); addressLabel.setName("addressLabel"); mnemonicLabel = new GDLabel("movl"); - mnemonicLabel.setFont(monoFont); + Gui.registerFont(mnemonicLabel, "font.monospaced"); mnemonicLabel.setName("mnemonicLabel"); mnemonicLabel.addMouseListener(mouseListener); @@ -233,8 +219,8 @@ class InstructionPanel extends JPanel implements ChangeListener { for (int i = 0; i < operandLabels.length; i++) { operandLabels[i] = new GDLabel("%ebp, "); operandLabels[i].setName("operandLabels[" + i + "]"); - operandLabels[i].setFont(monoFont); operandLabels[i].addMouseListener(mouseListener); + Gui.registerFont(operandLabels[i], "font.monospaced"); } innerPanel = new JPanel(); @@ -286,7 +272,7 @@ class InstructionPanel extends JPanel implements ChangeListener { /** * Enable drop on specified number of operands. * A value of -1 will disable all drop targets. - * @param numOperands + * @param numOperands the number of operands */ private void updateDropTargets(int numOperands) { ++numOperands; @@ -374,7 +360,7 @@ class InstructionPanel extends JPanel implements ChangeListener { if (activeIndex == opIndex) { operandLabels[opIndex].setBorder(ETCHED_BORDER); - operandLabels[opIndex].setBackground(EditReferencesProvider.HIGHLIGHT_COLOR); + operandLabels[opIndex].setBackground(EditReferencesProvider.BG_COLOR_ACTIVE_OPERAND); operandLabels[opIndex].setOpaque(true); } else { @@ -393,7 +379,7 @@ class InstructionPanel extends JPanel implements ChangeListener { mnemonicLabel.setForeground(DEFAULT_FG_COLOR); if (activeIndex == ReferenceManager.MNEMONIC) { - mnemonicLabel.setBackground(EditReferencesProvider.HIGHLIGHT_COLOR); + mnemonicLabel.setBackground(EditReferencesProvider.BG_COLOR_ACTIVE_OPERAND); mnemonicLabel.setBorder(ETCHED_BORDER); mnemonicLabel.setOpaque(true); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java index ef19bb0c9d..c0c5d62f6c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java @@ -22,6 +22,7 @@ import javax.swing.*; import docking.ActionContext; import docking.WindowPosition; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.framework.model.*; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -33,15 +34,12 @@ import ghidra.program.util.ChangeManager; import ghidra.util.HelpLocation; import ghidra.util.task.SwingUpdateManager; import resources.Icons; -import resources.ResourceManager; public class RegisterManagerProvider extends ComponentProviderAdapter { - private static final Icon DELETE_REGISTER_VALUES_ICON = - ResourceManager.loadImage("images/edit-delete.png"); - private static final Icon SELECT_REGISTER_VALUES_ICON = - ResourceManager.loadImage("images/text_align_justify.png"); - private static final Icon FILTER_ICON = ResourceManager.loadImage("images/textfield.png"); - static final ImageIcon REGISTER_ICON = ResourceManager.loadImage("images/registerGroup.png"); + private static final Icon DELETE_REGISTER_VALUES_ICON = Icons.DELETE_ICON; + private static final Icon SELECT_REGISTER_VALUES_ICON = Icons.MAKE_SELECTION_ICON; + private static final Icon FILTER_ICON = Icons.CONFIGURE_FILTER_ICON; + static final Icon REGISTER_ICON = new GIcon("icon.plugin.register.provider"); private static Icon RECV_LOCATION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; private Program program; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterTree.java index ccdddf20ce..94e58dd78f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterTree.java @@ -20,15 +20,15 @@ import java.awt.Point; import java.util.*; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; -import docking.widgets.tree.*; +import docking.widgets.tree.GTree; +import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.Program; -import resources.ResourceManager; +import resources.Icons; public class RegisterTree extends GTree { private Program program; @@ -48,15 +48,12 @@ public class RegisterTree extends GTree { // never have a horizontal scroll bar. JScrollPane scrollPane = getScrollPane(); final JViewport viewport = scrollPane.getViewport(); - scrollPane.getViewport().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - Point viewPosition = viewport.getViewPosition(); - if (viewPosition.x != 0) { - // if it scrolls horizontally, put it back - viewPosition.x = 0; - viewport.setViewPosition(viewPosition); - } + scrollPane.getViewport().addChangeListener(e -> { + Point viewPosition = viewport.getViewPosition(); + if (viewPosition.x != 0) { + // if it scrolls horizontally, put it back + viewPosition.x = 0; + viewport.setViewPosition(viewPosition); } }); setMinimumSize(new Dimension(175, 30)); @@ -78,7 +75,7 @@ public class RegisterTree extends GTree { } private static Register[] getNonHiddenRegisters(Program program) { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); for (Register reg : program.getProgramContext().getRegisters()) { if (!reg.isHidden()) { list.add(reg); @@ -191,9 +188,9 @@ class RegisterTreeRootNode extends SearchableRegisterTreeNode { lastRegisters = registers; HashMap groups = - new HashMap(); + new HashMap<>(); - List nodes = new ArrayList(); + List nodes = new ArrayList<>(); for (Register register : registers) { if (register.getBaseRegister() != register && @@ -220,8 +217,8 @@ class RegisterTreeRootNode extends SearchableRegisterTreeNode { } class RegisterTreeNode extends SearchableRegisterTreeNode { - private static ImageIcon REG_ICON = ResourceManager.loadImage("images/registerIcon.png"); - private static ImageIcon REG_GROUP_ICON = ResourceManager.loadImage("images/registerGroup.png"); + private static Icon REG_ICON = new GIcon("icon.plugin.register"); + private static Icon REG_GROUP_ICON = new GIcon("icon.plugin.register.provider"); private final Register register; public RegisterTreeNode(Register register) { @@ -274,9 +271,8 @@ class RegisterTreeNode extends SearchableRegisterTreeNode { } class RegisterTreeGroupNode extends SearchableRegisterTreeNode { - private static ImageIcon OPEN_ICON = ResourceManager.loadImage("images/openSmallFolder.png"); - private static ImageIcon CLOSED_ICON = - ResourceManager.loadImage("images/closedSmallFolder.png"); + private static Icon OPEN_ICON = Icons.OPEN_FOLDER_ICON; + private static Icon CLOSED_ICON = Icons.CLOSED_FOLDER_ICON; private String name; public RegisterTreeGroupNode(String name) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterValuesPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterValuesPanel.java index 4e561a4053..ba003a05ed 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterValuesPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterValuesPanel.java @@ -26,6 +26,9 @@ import javax.swing.*; import docking.widgets.OptionDialog; import docking.widgets.table.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; +import generic.theme.Gui; import ghidra.app.cmd.register.SetRegisterCmd; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.services.*; @@ -45,7 +48,8 @@ class RegisterValuesPanel extends JPanel { private static final String VALUE_COLUMN_NAME = "Value"; private static final String START_ADDRESS_COLUMN_NAME = "Start Address"; private static final String END_ADDRESS_COLUMN_NAME = "End Address"; - private static final Color REGISTER_MARKER_COLOR = new Color(0, 153, 153); + private static final Color REGISTER_MARKER_COLOR = + new GColor("color.bg.plugin.register.marker"); private Program currentProgram; private GhidraTable table; @@ -490,11 +494,11 @@ class RegisterValueRange { class RegisterValueRenderer extends GTableCellRenderer { - private Color defaultColor = Color.LIGHT_GRAY; + private Color defaultColor = Palette.LIGHT_GRAY; RegisterValueRenderer(JTable table) { setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); - setFont(new Font("monospaced", Font.PLAIN, 12)); + Gui.registerFont(this, "font.monospaced"); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/SetRegisterValueDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/SetRegisterValueDialog.java index 8a6c51ff82..a077bf5ceb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/SetRegisterValueDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/SetRegisterValueDialog.java @@ -28,6 +28,7 @@ import javax.swing.event.ChangeListener; import docking.DialogComponentProvider; import docking.widgets.combobox.GComboBox; import docking.widgets.label.GLabel; +import generic.theme.Gui; import ghidra.app.util.bean.FixedBitSizeValueField; import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; @@ -92,7 +93,7 @@ public class SetRegisterValueDialog extends DialogComponentProvider { registerChanged(); } }); - f = new Font("monospaced", Font.PLAIN, 13); + f = Gui.getFont("font.monospaced"); addressRangeList = new JList(); addressRangeList.setEnabled(false); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchProvider.java index 4c26b9fcdb..5699fc0aef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchProvider.java @@ -26,6 +26,7 @@ import docking.*; import docking.widgets.label.GLabel; import docking.widgets.table.GTableFilterPanel; import docking.widgets.table.TableFilter; +import generic.theme.GIcon; import ghidra.app.plugin.core.scalartable.RangeFilterTextField.FilterType; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -38,7 +39,6 @@ import ghidra.util.table.*; import ghidra.util.table.actions.DeleteTableRowAction; import ghidra.util.table.actions.MakeProgramSelectionAction; import help.HelpService; -import resources.ResourceManager; /** * Displays the results of a query from the {@link ScalarSearchPlugin}. Consists of 2 components: @@ -49,7 +49,7 @@ import resources.ResourceManager; */ public class ScalarSearchProvider extends ComponentProviderAdapter { - public static final ImageIcon ICON = ResourceManager.loadImage("images/dataW.gif"); + public static final Icon ICON = new GIcon("icon.plugin.scalartable.provider"); private ScalarSearchPlugin plugin; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java index d580e9cea3..d7170bf635 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptActionManager.java @@ -38,6 +38,7 @@ import docking.actions.KeyBindingUtils; import docking.tool.ToolConstants; import docking.widgets.table.GTable; import generic.jar.ResourceFile; +import generic.theme.GIcon; import ghidra.app.script.GhidraScriptInfoManager; import ghidra.app.script.ScriptInfo; import ghidra.framework.Application; @@ -45,7 +46,6 @@ import ghidra.framework.options.SaveState; import ghidra.util.*; import ghidra.util.task.*; import resources.Icons; -import resources.ResourceManager; import utilities.util.FileUtilities; class GhidraScriptActionManager { @@ -210,7 +210,7 @@ class GhidraScriptActionManager { private void createActions() { createScriptAction("Run", "Run Script", "Run Script", - ResourceManager.loadImage("images/play.png"), RESOURCE_FILE_ACTION_RUN_GROUP, + new GIcon("icon.plugin.scriptmanager.run"), RESOURCE_FILE_ACTION_RUN_GROUP, provider::runScript); runLastAction = new RerunLastScriptAction(RESOURCE_FILE_ACTION_RUN_GROUP); @@ -220,30 +220,31 @@ class GhidraScriptActionManager { plugin.getTool().addAction(globalRunLastAction); createScriptAction("Edit", "Edit with basic editor", "Edit Script with basic editor", - ResourceManager.loadImage("images/accessories-text-editor.png"), null, + new GIcon("icon.plugin.scriptmanager.edit"), null, provider::editScriptBuiltin); createScriptAction("EditEclipse", "Edit with Eclipse", "Edit Script with Eclipse", - ResourceManager.loadImage("images/eclipse.png"), null, provider::editScriptEclipse); + new GIcon("icon.plugin.scriptmanager.edit.eclipse"), null, provider::editScriptEclipse); keyBindingAction = createScriptAction("Key Binding", "Assign Key Binding", "Assign Key Binding", - ResourceManager.loadImage("images/key.png"), null, provider::assignKeyBinding); + new GIcon("icon.plugin.scriptmanager.keybinding"), null, + provider::assignKeyBinding); createScriptAction("Delete", "Delete", "Delete Script", - ResourceManager.loadImage("images/edit-delete.png"), null, provider::deleteScript); + new GIcon("icon.plugin.scriptmanager.delete"), null, provider::deleteScript); renameAction = createScriptAction("Rename", "Rename", "Rename Script", - ResourceManager.loadImage("images/textfield_rename.png"), null, provider::renameScript); + new GIcon("icon.plugin.scriptmanager.rename"), null, provider::renameScript); newAction = createScriptTableAction("New", "Create New Script", - ResourceManager.loadImage("images/script_add.png"), provider::newScript); + new GIcon("icon.plugin.scriptmanager.new"), provider::newScript); createScriptTableAction("Refresh", "Refresh Script List", Icons.REFRESH_ICON, provider::refresh); showBundleStatusAction = createScriptTableAction("Script Directories", - "Manage Script Directories", ResourceManager.loadImage("images/text_list_bullets.png"), + "Manage Script Directories", new GIcon("icon.plugin.scriptmanager.manage"), provider::showBundleStatusComponent); new ActionBuilder("Script Quick Launch", plugin.getName()) @@ -252,7 +253,7 @@ class GhidraScriptActionManager { .onAction(this::chooseScript) .buildAndInstall(plugin.getTool()); - Icon icon = ResourceManager.loadImage("images/red-cross.png"); + Icon icon = new GIcon("icon.plugin.scriptmanager.api"); Predicate test = context -> { Object contextObject = context.getContextObject(); return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile); @@ -506,7 +507,7 @@ class GhidraScriptActionManager { super(RERUN_LAST_SHARED_ACTION_NAME, plugin.getName(), KeyBindingType.SHARED); setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/play_again.png"), toolbarGroup)); + new ToolBarData(new GIcon("icon.plugin.scriptmanager.run.again"), toolbarGroup)); setDescription("Rerun the last run script"); setHelpLocation(new HelpLocation(plugin.getName(), "Run_Last")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java index ebc7b8fb07..2862efc947 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java @@ -46,6 +46,7 @@ import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; import docking.widgets.tree.support.BreadthFirstIterator; import generic.jar.ResourceFile; +import generic.theme.GIcon; import ghidra.app.plugin.core.osgi.*; import ghidra.app.script.*; import ghidra.app.services.ConsoleService; @@ -57,7 +58,6 @@ import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.task.*; -import resources.ResourceManager; import util.CollectionUtils; import utilities.util.FileUtilities; @@ -126,7 +126,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter { scriptList.addListener(scriptListListener); setHelpLocation(new HelpLocation(plugin.getName(), plugin.getName())); - setIcon(ResourceManager.loadImage("images/play.png")); + setIcon(new GIcon("icon.plugin.scriptmanager.provider")); addToToolbar(); setWindowGroup(WINDOW_GROUP); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java index 6c39be52a5..62bbdf4135 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptEditorComponentProvider.java @@ -20,8 +20,6 @@ import java.awt.Font; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.io.*; -import java.util.Collection; -import java.util.Iterator; import javax.swing.*; import javax.swing.text.Document; @@ -30,19 +28,20 @@ import javax.swing.undo.UndoableEdit; import docking.*; import docking.action.*; import docking.actions.KeyBindingUtils; -import docking.options.editor.FontPropertyEditor; +import docking.options.editor.FontEditor; import docking.widgets.OptionDialog; import generic.jar.ResourceFile; +import generic.theme.*; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.script.GhidraScriptUtil; -import ghidra.framework.options.SaveState; import ghidra.util.*; import ghidra.util.datastruct.FixedSizeStack; import resources.Icons; -import resources.ResourceManager; public class GhidraScriptEditorComponentProvider extends ComponentProvider { - static final String EDITOR_COMPONENT_NAME="EDITOR"; - + static final String EDITOR_COMPONENT_NAME = "EDITOR"; + private static final String FONT_ID = "font.plugin.scripts.text.editor"; + static final String CHANGE_DESTINATION_TITLE = "Where Would You Like to Store Your Changes?"; static final String FILE_ON_DISK_CHANGED_TITLE = "File Changed on Disk"; static final String FILE_ON_DISK_MISSING_TITLE = "File on Disk is Missing"; @@ -54,22 +53,6 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { private static final int MAX_UNDO_REDO_SIZE = 50; - private static Font defaultFont = new Font("monospaced", Font.PLAIN, 12); - - static void restoreState(SaveState saveState) { - String name = saveState.getString("DEFAULT_FONT_NAME", "Monospaced"); - int style = saveState.getInt("DEFAULT_FONT_STYLE", Font.PLAIN); - int size = saveState.getInt("DEFAULT_FONT_SIZE", 12); - defaultFont = new Font(name, style, size); - } - - static void saveState(SaveState saveState) { - saveState.putString("DEFAULT_FONT_NAME", defaultFont.getName()); - saveState.putInt("DEFAULT_FONT_STYLE", defaultFont.getStyle()); - saveState.putInt("DEFAULT_FONT_SIZE", defaultFont.getSize()); - } - - private GhidraScriptMgrPlugin plugin; private GhidraScriptComponentProvider provider; private String title; @@ -227,12 +210,13 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { @Override public boolean isEnabledForContext(ActionContext context) { Object contextObject = context.getContextObject(); - return contextObject == GhidraScriptEditorComponentProvider.this && !undoStack.isEmpty(); + return contextObject == GhidraScriptEditorComponentProvider.this && + !undoStack.isEmpty(); } }; undoAction.setDescription("Undo"); undoAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/undo.png"), "UndoRedo")); + new ToolBarData(new GIcon("icon.undo"), "UndoRedo")); undoAction.setEnabled(false); undoAction.setKeyBindingData(new KeyBindingData( KeyStroke.getKeyStroke(KeyEvent.VK_Z, DockingUtils.CONTROL_KEY_MODIFIER_MASK))); @@ -247,12 +231,13 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { @Override public boolean isEnabledForContext(ActionContext context) { Object contextObject = context.getContextObject(); - return contextObject == GhidraScriptEditorComponentProvider.this && !redoStack.isEmpty(); + return contextObject == GhidraScriptEditorComponentProvider.this && + !redoStack.isEmpty(); } }; redoAction.setDescription("Redo"); redoAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/redo.png"), "UndoRedo")); + new ToolBarData(new GIcon("icon.redo"), "UndoRedo")); redoAction.setKeyBindingData(new KeyBindingData( KeyStroke.getKeyStroke(KeyEvent.VK_Y, DockingUtils.CONTROL_KEY_MODIFIER_MASK))); redoAction.setEnabled(false); @@ -280,7 +265,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { }; saveAction.setDescription("Save"); saveAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/disk.png"), "Save")); + new ToolBarData(Icons.SAVE_ICON, "Save")); saveAction.setKeyBindingData(new KeyBindingData( KeyStroke.getKeyStroke(KeyEvent.VK_S, DockingUtils.CONTROL_KEY_MODIFIER_MASK))); @@ -317,7 +302,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { }; saveAsAction.setDescription("Save As..."); saveAsAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/disk_save_as.png"), "Save")); + new ToolBarData(Icons.SAVE_AS_ICON, "Save")); saveAsAction.setEnabled(true); plugin.getTool().addLocalAction(this, saveAsAction); @@ -341,7 +326,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { } }; runAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/play.png"), "ZRun")); + new ToolBarData(new GIcon("icon.plugin.scriptmanager.run"), "ZRun")); runAction.setDescription("Run Editor's Script"); runAction.setPopupMenuData(new MenuData(new String[] { "Run" }, "ZRun")); runAction.setEnabled(true); @@ -355,7 +340,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { } }; fontAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/text_lowercase.png"), "ZZFont")); + new ToolBarData(new GIcon("icon.font"), "ZZFont")); fontAction.setDescription("Select Font"); fontAction.setEnabled(true); plugin.getTool().addLocalAction(this, fontAction); @@ -447,7 +432,8 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { int choice = OptionDialog.showOptionDialog(scrollPane, FILE_ON_DISK_CHANGED_TITLE, "The contents of the script file have changed on disk.

Would " + - "you like to keep your changes in the editor or " + + "you like to keep your changes in the editor or " + "discard your changes?", KEEP_CHANGES_TEXT, DISCARD_CHANGES_TEXT, OptionDialog.QUESTION_MESSAGE); @@ -469,7 +455,9 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { // choice = OptionDialog.showOptionDialog(scrollPane, CHANGE_DESTINATION_TITLE, "You can save your current changes to another file or " + - "overwrite the contents of the file on disk.", + "overwrite the contents of the file on disk.", SAVE_CHANGES_AS_TEXT, OVERWRITE_CHANGES_TEXT, OptionDialog.QUESTION_MESSAGE); // @@ -515,18 +503,11 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { } } - private void doSelectFont() { - FontPropertyEditor editor = new FontPropertyEditor(); - editor.setValue(defaultFont); + protected void doSelectFont() { + FontEditor editor = new FontEditor(); + editor.setValue(Gui.getFont(FONT_ID)); editor.showDialog(); - defaultFont = (Font) editor.getValue(); - - Collection values = provider.getEditorMap().values(); - Iterator iterator = values.iterator(); - while (iterator.hasNext()) { - GhidraScriptEditorComponentProvider editorComponent = iterator.next(); - editorComponent.textArea.setFont(defaultFont); - } + ThemeManager.getInstance().setFont(FONT_ID, (Font) editor.getValue()); } private void save() { @@ -676,7 +657,7 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider { private KeyMasterTextArea(String text) { super(text); - setFont(defaultFont); + Gui.registerFont(this, FONT_ID); setName(EDITOR_COMPONENT_NAME); setWrapStyleWord(false); Document document = getDocument(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin.java index f8d22be170..1aba81aaae 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin.java @@ -78,14 +78,12 @@ public class GhidraScriptMgrPlugin extends ProgramPlugin implements GhidraScript public void readConfigState(SaveState saveState) { super.readConfigState(saveState); provider.readConfigState(saveState); - GhidraScriptEditorComponentProvider.restoreState(saveState); } @Override public void writeConfigState(SaveState saveState) { super.writeConfigState(saveState); provider.writeConfigState(saveState); - GhidraScriptEditorComponentProvider.saveState(saveState); } GhidraState getCurrentState() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java index eb2f335742..884a93febd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java @@ -24,6 +24,8 @@ import javax.swing.event.TableModelEvent; import docking.widgets.table.*; import generic.jar.ResourceFile; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.app.script.GhidraScriptInfoManager; import ghidra.app.script.ScriptInfo; import ghidra.docking.settings.Settings; @@ -39,7 +41,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel scriptList = new ArrayList<>(); @@ -217,8 +219,8 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel super.fireTableChanged(e)); } - private class StatusColumn extends AbstractDynamicTableColumn { - private Comparator comparator = (i1, i2) -> { + private class StatusColumn extends AbstractDynamicTableColumn { + private Comparator comparator = (i1, i2) -> { if (i1 == i2) { return 0; } @@ -234,12 +236,19 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel renderer = new AbstractGColumnRenderer<>() { + private String getDescription(Icon icon) { + if (icon instanceof ImageIcon imageIcon) { + return imageIcon.getDescription(); + } + return icon.getClass().getName(); + } + + private GColumnRenderer renderer = new AbstractGColumnRenderer<>() { @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { JLabel label = (JLabel) super.getTableCellRendererComponent(data); @@ -269,14 +278,14 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel getColumnRenderer() { + public GColumnRenderer getColumnRenderer() { return renderer; } @@ -286,7 +295,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel getComparator() { + public Comparator getComparator() { return comparator; } } @@ -363,7 +372,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel"); - buffy.append(" "); + buffy.append(" "); buffy.append(keyBinding.toString()); buffy.append(""); buffy.append("

"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java index 5dcfe23bee..257c23cb7f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchmem/MemSearchPlugin.java @@ -19,7 +19,7 @@ import java.awt.Color; import java.awt.event.KeyEvent; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import docking.*; @@ -27,6 +27,7 @@ import docking.action.*; import docking.tool.ToolConstants; import docking.widgets.fieldpanel.support.Highlight; import docking.widgets.table.threaded.*; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.context.NavigatableActionContext; @@ -57,7 +58,6 @@ import ghidra.util.bean.opteditor.OptionsVetoException; import ghidra.util.search.memory.*; import ghidra.util.table.GhidraProgramTableModel; import ghidra.util.task.*; -import resources.ResourceManager; /** * Class to handle memory searching of code bytes in a program. @@ -92,10 +92,8 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, private MemSearchDialog searchDialog; private GoToService goToService; private int searchLimit; - private ImageIcon searchIcon; + private static final Icon SEARCH_MARKER_ICON = new GIcon("icon.base.search.marker"); - private Color defaultHighlightColor; - private Color activeHighlightColor; private boolean doHighlight; private int byteGroupSize; private String byteDelimiter; @@ -115,7 +113,6 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, public MemSearchPlugin(PluginTool tool) { super(tool); - searchIcon = ResourceManager.loadImage("images/searchm_obj.gif"); createActions(); initializeOptionListeners(); @@ -390,10 +387,11 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_NAME, true, null, "Toggles highlight search results"); - opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_COLOR, null, "The search result highlight color"); - opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR, null, + opt.registerThemeColorBinding(PluginConstants.SEARCH_HIGHLIGHT_COLOR_OPTION_NAME, + PluginConstants.SEARCH_HIGHLIGHT_COLOR.getId(), null, + "The search result highlight color"); + opt.registerThemeColorBinding(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_OPTION_NAME, + PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR.getId(), null, "The search result highlight color for the currently selected match"); opt.addOptionsChangeListener(this); @@ -414,10 +412,6 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, prepopulateSearch = opt.getBoolean(PluginConstants.PRE_POPULATE_MEM_SEARCH, true); autoRestrictSelection = opt.getBoolean(PluginConstants.AUTO_RESTRICT_SELECTION, true); doHighlight = opt.getBoolean(PluginConstants.SEARCH_HIGHLIGHT_NAME, true); - defaultHighlightColor = opt.getColor(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_COLOR); - activeHighlightColor = opt.getColor(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR); opt = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS); byteGroupSize = opt.getInt(BytesFieldFactory.BYTE_GROUP_SIZE_MSG, 1); @@ -510,7 +504,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, String type = "Search"; if (navigatable.supportsMarkers()) { return tableService.showTableWithMarkers(title, type, model, - PluginConstants.SEARCH_HIGHLIGHT_COLOR, searchIcon, type, navigatable); + PluginConstants.SEARCH_HIGHLIGHT_COLOR, SEARCH_MARKER_ICON, type, navigatable); } return tableService.showTable(title, type, model, type, navigatable); } @@ -748,7 +742,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, private Color getHighlightColor(Address highlightStart, int highlightLength) { ProgramLocation location = navigatable != null ? navigatable.getLocation() : null; if (!(location instanceof BytesFieldLocation)) { - return defaultHighlightColor; + return PluginConstants.SEARCH_HIGHLIGHT_COLOR; } BytesFieldLocation byteLoc = (BytesFieldLocation) location; @@ -756,11 +750,12 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener, if (highlightStart.hasSameAddressSpace(byteAddress)) { long diff = byteAddress.subtract(highlightStart); if (diff >= 0 && diff < highlightLength) { - return activeHighlightColor; // the current location is in the highlight + // the current location is in the highlight + return PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR; } } - return defaultHighlightColor; + return PluginConstants.SEARCH_HIGHLIGHT_COLOR; } private boolean checkRemoveHighlights() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java index ee8deba1ec..0981bab88b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java @@ -15,19 +15,21 @@ */ package ghidra.app.plugin.core.searchtext; -import java.awt.*; +import java.awt.Component; +import java.awt.KeyboardFocusManager; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.*; import docking.action.builder.ActionBuilder; import docking.tool.ToolConstants; import docking.widgets.fieldpanel.support.Highlight; import docking.widgets.table.threaded.*; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.context.*; @@ -58,7 +60,6 @@ import ghidra.util.*; import ghidra.util.bean.opteditor.OptionsVetoException; import ghidra.util.table.GhidraProgramTableModel; import ghidra.util.task.*; -import resources.ResourceManager; /** * Plugin to search text as it is displayed in the fields of the Code Browser. @@ -88,7 +89,7 @@ import resources.ResourceManager; public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeListener, TaskListener, NavigatableRemovalListener, DockingContextListener { - private static final ImageIcon searchIcon = ResourceManager.loadImage("images/searchm_obj.gif"); + private static final Icon SEARCH_MARKER_ICON = new GIcon("icon.base.search.marker"); private static final String DESCRIPTION = "Search program text for string"; private final static Highlight[] NO_HIGHLIGHTS = new Highlight[0]; @@ -99,8 +100,6 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList private int searchLimit; private SearchTask currentTask; private String lastSearchedText; - private Color highlightColor; - private Color currentAddrHighlightColor; private boolean doHighlight; private Navigatable navigatable; @@ -182,7 +181,6 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList if (searchDialog != null && searchDialog.isVisible()) { TaskMonitor taskMonitor = searchDialog.getTaskMonitorComponent(); - // TODO this can probably be handled by canceling the task below (or vice versa) taskMonitor.cancel(); searchDialog.dispose(); @@ -332,7 +330,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList if (navigatable.supportsMarkers()) { return query.showTableWithMarkers( "Search Text - \"" + searchString + "\" [" + matchType + "]", "Search", model, - PluginConstants.SEARCH_HIGHLIGHT_COLOR, searchIcon, "Search", navigatable); + PluginConstants.SEARCH_HIGHLIGHT_COLOR, SEARCH_MARKER_ICON, "Search", navigatable); } return query.showTable("Search Text - \"" + searchString + "\" [" + matchType + "]", "Search", model, "Search", navigatable); @@ -425,12 +423,6 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList } searchLimit = newSearchLimit; } - else if (optionName.equals(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME)) { - currentAddrHighlightColor = (Color) newValue; - } - else if (optionName.equals(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME)) { - highlightColor = (Color) newValue; - } else if (optionName.equals(PluginConstants.SEARCH_HIGHLIGHT_NAME)) { doHighlight = ((Boolean) newValue).booleanValue(); } @@ -443,22 +435,17 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_NAME, true, loc, "Determines whether to highlight the matched string for a search in the listing."); - opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_COLOR, loc, - "Color to use when highlighting the matched string for a search in the listing."); - opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_COLOR, loc, - "Color to use for highlighting when the match string occurs at the current address."); + opt.registerThemeColorBinding(PluginConstants.SEARCH_HIGHLIGHT_COLOR_OPTION_NAME, + PluginConstants.SEARCH_HIGHLIGHT_COLOR.getId(), null, + "The search result highlight color"); + opt.registerThemeColorBinding(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_OPTION_NAME, + PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR.getId(), null, + "The search result highlight color for the currently selected match"); searchLimit = opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, PluginConstants.DEFAULT_SEARCH_LIMIT); doHighlight = opt.getBoolean(PluginConstants.SEARCH_HIGHLIGHT_NAME, true); - highlightColor = opt.getColor(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_COLOR); - currentAddrHighlightColor = - opt.getColor(PluginConstants.SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME, - PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR); opt.setOptionsHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Search_Text")); @@ -662,12 +649,14 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList int start = matcher.start(); int end = matcher.end() - 1; if (start <= cursorTextOffset && end >= cursorTextOffset) { - list.add(new Highlight(start, end, currentAddrHighlightColor)); + list.add(new Highlight(start, end, + PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR)); } else if (loc == null) { // only add in matches around current match if loc is null // meaning that this is a one at a time search and not a table // of results. - list.add(new Highlight(start, end, highlightColor)); + list.add(new Highlight(start, end, + PluginConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR)); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/GhidraColorMap.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/GhidraColorMap.java deleted file mode 100644 index 3b3cf9c6d9..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/GhidraColorMap.java +++ /dev/null @@ -1,107 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 ghidra.app.plugin.core.spaceview; - -import java.awt.Color; -import java.awt.image.IndexColorModel; - -public class GhidraColorMap { - - /* - tier 1 - - undefined (GRAY) - zero (BLACK) - low (DARK ORANGE) - whitespace (PALE BLUE) - digit (LIGHT BLUE) - upper (LIGHT BLUE) - lower (MED BLUE) - symbol (DARK BLUE) - high (DARK RED) - full (-1, 255) (WHITE) - - tier 2 - - float? (GREEN) - double? (GREEN) - int? (ORANGE) - long? (ORANGE) - instruction? (PINK) - address? (YELLOW) - - tier 3 - - SEAFOAM - defined data (simple types) - defined data (structs) - defined data (unions) - - MAGENTA - code (memory) - code (flow) - code (special) - code (normal) - - PURPLE - fun code (memory) - fun code (flow) - fun code (special) - fun code (normal) - - RED - error bookmarks - - tier 4 - - selected (BRIGHT GREEN) - highlighted (BRIGHT YELLOW) - selected and highlighted (BRIGHT YELLOW GREEN) - - immutables needed: - - segmenting - hilbert ordering - maximuming - from array - cache - iterator - - also: - - bijection from address to index in array space - bijection from pixelspace to indexspace - */ - - public IndexColorModel getColorModel() { - Color[] colors = - new Color[] { new Color(190, 255, 0), Color.red, new Color(128, 128, 128), Color.cyan, - Color.magenta, }; - - byte[] red = new byte[colors.length]; - byte[] grn = new byte[colors.length]; - byte[] blu = new byte[colors.length]; - for (int ii = 0; ii < colors.length; ++ii) { - red[ii] = (byte) colors[ii].getRed(); - grn[ii] = (byte) colors[ii].getGreen(); - blu[ii] = (byte) colors[ii].getBlue(); - } - IndexColorModel colorModel = new IndexColorModel(8, colors.length, red, grn, blu); - - return colorModel; - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/SpacecurveRasterPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/SpacecurveRasterPanel.java deleted file mode 100644 index 566e82fae9..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/SpacecurveRasterPanel.java +++ /dev/null @@ -1,99 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 ghidra.app.plugin.core.spaceview; - -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.image.*; -import java.util.Hashtable; - -import javax.swing.JFrame; -import javax.swing.JPanel; - -public class SpacecurveRasterPanel extends JPanel { - protected static final Hashtable EMPTY_HASHTABLE = new Hashtable(); - - byte[] raster; - private int width; - private int height; - private IndexColorModel colorModel; - - public SpacecurveRasterPanel(IndexColorModel colorModel) { - this.colorModel = colorModel; - } - - public void setRaster(byte[] raster, int width, int height) { - if (raster.length != width * height) { - throw new IllegalArgumentException("raster.length != width * height"); - } - this.raster = raster; - this.width = width; - this.height = height; - repaint(); - } - - public void setColorModel(IndexColorModel colorModel) { - this.colorModel = colorModel; - repaint(); - } - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - Graphics2D g2 = (Graphics2D) g; - - if (raster != null) { - DataBufferByte dbb = new DataBufferByte(raster, height * width, 0); - ComponentSampleModel sm = getComponentSampleModel(); - WritableRaster wr = Raster.createWritableRaster(sm, dbb, null); - BufferedImage img = new BufferedImage(colorModel, wr, true, EMPTY_HASHTABLE); - - g2.drawImage(img, 0, 0, null); - } - } - - protected ComponentSampleModel getComponentSampleModel() { - return new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 1, width, - new int[] { 0 }); - } - - public static void main(String[] args) { - byte[] red = new byte[256]; - byte[] grn = new byte[256]; - byte[] blu = new byte[256]; - for (int ii = 0; ii < 256; ++ii) { - int jj = (255 - ii); - red[ii] = (byte) jj; - grn[ii] = (byte) (jj * jj / 255); - blu[ii] = (byte) (Math.sqrt(jj) / Math.sqrt(255.0) * 255.0); - } - IndexColorModel colorModel = new IndexColorModel(8, 256, red, grn, blu); - final int width = 256; - final int height = 256; - byte[] raster = new byte[width * height]; - for (int ii = 0; ii < raster.length; ++ii) { - raster[ii] = (byte) ((ii * 1) % 256); - } - SpacecurveRasterPanel panel = new SpacecurveRasterPanel(colorModel); - panel.setRaster(raster, width, height); - JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.getContentPane().add(panel); - frame.setSize(width, height); - frame.setVisible(true); - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringTableProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringTableProvider.java index 53fbdeb850..16fd3eee44 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringTableProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/string/StringTableProvider.java @@ -30,6 +30,7 @@ import docking.widgets.label.GLabel; import docking.widgets.table.*; import docking.widgets.table.threaded.ThreadedTableModel; import docking.widgets.textfield.IntegerTextField; +import generic.theme.GIcon; import ghidra.app.services.GoToService; import ghidra.app.util.HelpTopics; import ghidra.docking.settings.SettingsImpl; @@ -48,26 +49,26 @@ import ghidra.util.layout.VerticalLayout; import ghidra.util.table.*; import ghidra.util.table.actions.MakeProgramSelectionAction; import ghidra.util.task.TaskLauncher; +import resources.Icons; import resources.ResourceManager; /** * Component provider for the Search -> For Strings... result dialog. */ public class StringTableProvider extends ComponentProviderAdapter implements DomainObjectListener { - private static final ImageIcon ICON = ResourceManager.loadImage("images/kmessedwords.png"); - private static final Icon PARITALLY_DEFINED_ICON = - ResourceManager.loadImage("images/dialog-warning.png"); - private static final Icon SHOW_UNDEFINED_ICON = - ResourceManager.loadImage("images/magnifier.png"); - private static final Icon SHOW_DEFINED_ICON = ResourceManager.loadImage("images/font.png"); - private static final Icon SHOW_WORDS_ICON = ResourceManager.loadImage("images/view-filter.png"); - private static final Icon CONFLICTS_ICON = - ResourceManager.loadImage("images/dialog-warning_red.png"); - private static final Icon REFRESH_ICON = ResourceManager.loadImage("images/reload.png"); - private static final Icon REFRESH_NOT_NEEDED_ICON = - ResourceManager.getDisabledIcon(REFRESH_ICON); - private static final Icon EXPAND_ICON = ResourceManager.loadImage("images/expand.gif"); - private static final Icon COLLAPSE_ICON = ResourceManager.loadImage("images/collapse.gif"); + + //@formatter:off + private static final Icon ICON = new GIcon("icon.plugin.stringtable.provider"); + private static final Icon PARITALLY_DEFINED_ICON = new GIcon("icon.plugin.stringtable.defined.partial"); + private static final Icon SHOW_UNDEFINED_ICON = new GIcon("icon.plugin.stringtable.undefined"); + private static final Icon SHOW_DEFINED_ICON = new GIcon("icon.plugin.stringtable.defined"); + private static final Icon SHOW_WORDS_ICON = new GIcon("icon.plugin.stringtable.words"); + private static final Icon CONFLICTS_ICON = new GIcon("icon.plugin.stringtable.conflicts"); + private static final Icon REFRESH_ICON = Icons.REFRESH_ICON; + private static final Icon REFRESH_NOT_NEEDED_ICON = ResourceManager.getDisabledIcon(REFRESH_ICON); + private static final Icon EXPAND_ICON = new GIcon("icon.toggle.expand"); + private static final Icon COLLAPSE_ICON = new GIcon("icon.toggle.collapse"); + //@formatter:off private StringTablePlugin plugin; private JPanel mainPanel; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java index 0b2a0245b0..9435c25150 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java @@ -28,6 +28,7 @@ import javax.swing.table.TableColumn; import docking.ActionContext; import docking.widgets.table.GTableTextCellEditor; import docking.widgets.table.threaded.ThreadedTableModelListener; +import generic.theme.GIcon; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.program.model.address.Address; @@ -40,14 +41,13 @@ import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; import ghidra.util.table.*; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Provider for the defined strings table. */ public class ViewStringsProvider extends ComponentProviderAdapter { - public static final ImageIcon ICON = ResourceManager.loadImage("images/dataW.gif"); + public static final Icon ICON = new GIcon("icon.plugin.viewstrings.provider"); private GhidraThreadedTablePanel threadedTablePanel; private GhidraTableFilterPanel filterPanel; @@ -155,8 +155,9 @@ public class ViewStringsProvider extends ComponentProviderAdapter { // ignore } }); - TableColumn stringRepCol = table.getColumnModel().getColumn( - ViewStringsTableModel.COLUMNS.STRING_REP_COL.ordinal()); + TableColumn stringRepCol = table.getColumnModel() + .getColumn( + ViewStringsTableModel.COLUMNS.STRING_REP_COL.ordinal()); stringRepCol.setCellEditor(new StringRepCellEditor()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/InfiniteProgressPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/InfiniteProgressPanel.java deleted file mode 100644 index d0eb99a5fb..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/InfiniteProgressPanel.java +++ /dev/null @@ -1,455 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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 ghidra.app.plugin.core.symboltree; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsEnvironment; -import java.awt.RenderingHints; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; - -public class InfiniteProgressPanel extends JComponent implements MouseListener { - - private static final String DEFAULT_MESSAGE_TEXT = ""; - private static final int DEFAULT_NUMBER_OF_BARS = 14; - private static final float DEFAULT_SHIELD = .60F; - private static final int DEFAULT_FRAMES_PER_SECOND = 7; - private static final int DEFAULT_FADEIN_DELAY = 300; - - protected String text = DEFAULT_MESSAGE_TEXT; - protected int fadeDelay = DEFAULT_FADEIN_DELAY; - protected float shield = DEFAULT_SHIELD; - protected int barsCount = DEFAULT_NUMBER_OF_BARS; - protected int fps = DEFAULT_FRAMES_PER_SECOND; - protected RenderingHints hints; - protected Area[] ticker; - - // state values - protected Thread animation; - protected boolean paintAnimation = false; - protected int alphaLevel = 0; - - public InfiniteProgressPanel() { - this( DEFAULT_MESSAGE_TEXT ); - } - - public InfiniteProgressPanel( String text ) { - this( text, DEFAULT_NUMBER_OF_BARS ); - } - - public InfiniteProgressPanel( String text, int barsCount ) { - this( text, barsCount, DEFAULT_SHIELD ); - } - - public InfiniteProgressPanel( String text, int barsCount, float shield ) { - this( text, barsCount, shield, DEFAULT_FRAMES_PER_SECOND ); - } - - public InfiniteProgressPanel( String text, int barsCount, float shield, int fps ) { - this( text, barsCount, shield, fps, DEFAULT_FADEIN_DELAY ); - } - - public InfiniteProgressPanel( String text, int barsCount, float shield, int fps, int rampDelay ) { - setText( text ); - this.fadeDelay = rampDelay >= 0 ? rampDelay : 0; - this.shield = shield >= 0.0f ? shield : 0.0f; - this.fps = fps > 0 ? fps : 15; - this.barsCount = barsCount > 0 ? barsCount : 14; - - this.hints = new RenderingHints( RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY ); - this.hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); - this.hints.put( RenderingHints.KEY_FRACTIONALMETRICS, - RenderingHints.VALUE_FRACTIONALMETRICS_ON ); - } - - public void setText( String newText ) { - text = newText; - if ( text == null ) { - text = ""; - } - repaint(); - } - - public String getText() { - return text; - } - - public void start() { - if ( animation != null ) { - animation.interrupt(); - } - - removeMouseListener( this ); // be sure not to add the listener twice - addMouseListener( this ); - setVisible( true ); - - ticker = buildTicker( barsCount ); - double fixIncrement = 2.0 * Math.PI / (barsCount); - animation = new Thread( new Animator( fixIncrement, fadeDelay ) ); - animation.start(); - } - - public void stop() { - if ( animation != null ) { - animation.interrupt(); - animation = null; - double fixIncrement = 2.0 * Math.PI / (barsCount); - animation = new Thread( new FadeOutAnimator( fixIncrement, fadeDelay) ); - animation.start(); - } - } - - public void interrupt() { - if ( animation != null ) { - animation.interrupt(); - animation = null; - removeMouseListener(this); - setVisible(false); - } - } - - private Area[] buildTicker( int barCount ) { - Area[] newTicker = new Area[barCount]; - Point2D.Double center = new Point2D.Double( (double) getWidth() / 2, - (double) getHeight() / 2 ); - double fixedAngle = 2.0 * Math.PI / (barCount); - for ( double i = 0.0; i < barCount; i++ ) { - Area primitive = buildPrimitive(); - AffineTransform toCenter = AffineTransform.getTranslateInstance(center.getX(), - center.getY() ); - AffineTransform toBorder = AffineTransform.getTranslateInstance(45.0, -6.0 ); - AffineTransform toCircle = AffineTransform.getRotateInstance(-i * fixedAngle, - center.getX(), center.getY() ); - - AffineTransform toWheel = new AffineTransform(); - toWheel.concatenate(toCenter); - toWheel.concatenate(toBorder); - - primitive.transform(toWheel); - primitive.transform(toCircle); - - newTicker[(int) i] = primitive; - } - - return newTicker; - } - - private Area buildPrimitive() { - Rectangle2D.Double body = new Rectangle2D.Double( 6, 0, 30, 12 ); // location and size - Ellipse2D.Double head = new Ellipse2D.Double( 0, 0, 12, 12 ); - Ellipse2D.Double tail = new Ellipse2D.Double( 30, 0, 12, 12 ); - - Area tick = new Area(body); - tick.add( new Area( head ) ); - tick.add( new Area( tail ) ); - - return tick; - } - - @Override - public void paintComponent( Graphics g ) { - if ( !paintAnimation ) { - return; - } - - int width = getWidth(); - int height = getHeight(); - double maxY = 0.0; - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHints(hints); - - g2.setColor( new Color( 255, 255, 255, (int) (alphaLevel * shield) ) ); - g2.fillRect(0, 0, width, height); - -double textPosition = 0.0; -for ( Area element : ticker ) { - Rectangle2D bounds = element.getBounds2D(); - if ( bounds.getMaxY() > textPosition ) { - textPosition = bounds.getMaxY(); - } -} - - int channel = 0; - int blue = 255; - Color textColor = Color.BLACK; - for ( int i = 0; i < ticker.length; i++ ) { - - - channel = 264 - 128 / (i + 1); - blue = channel+126 > 255 ? 255 : channel+126; - Color color = new Color( channel, channel, blue, (int) (alphaLevel * shield) ); - - if ( i == 0 ) { - textColor = color; - } - - g2.setColor( color ); - g2.fill( ticker[i] ); - - Rectangle2D bounds = ticker[i].getBounds2D(); - if ( bounds.getMaxY() > maxY ) { - maxY = bounds.getMaxY(); - } - } -paintText( g2, textColor, textPosition ); - } - -private void paintText( Graphics2D graphics, Color color, double textPosition ) { - if ( text == null || text.trim().length() == 0 ) { - return; - } - - FontRenderContext context = graphics.getFontRenderContext(); - TextLayout layout = new TextLayout( text, getFont(), context ); - Rectangle2D bounds = layout.getBounds(); - graphics.setColor( Color.BLACK ); - layout.draw( graphics, (float) (getWidth() - bounds.getWidth()) / 2, - (float) (textPosition + layout.getLeading() + 2 * layout.getAscent() ) ); -} - - // fade out - private class FadeOutAnimator implements Runnable { - - private final int fadeDelayTime; - private AffineTransform transformToCircle; - private long startRampupTime; - - private FadeOutAnimator( double transformTheta, int fadeDelayTime ) { - this.fadeDelayTime = fadeDelayTime; - - Point2D.Double center = new Point2D.Double( (double) getWidth() / 2, - (double) getHeight() / 2 ); - transformToCircle = AffineTransform.getRotateInstance(transformTheta, - center.getX(), center.getY() ); - } - - public void run() { - startRampupTime = System.currentTimeMillis(); - if ( fadeDelayTime == 0 ) { - alphaLevel = 0; - } - - while ( !Thread.interrupted() && (alphaLevel > 0) ) { - transformTicker(); - - repaint(); - - updateBackgroundAlpha(); - - if ( !pauseForEffect() ) { - break; - } - } - - paintAnimation = false; - repaint(); - - setVisible(false); - removeMouseListener( InfiniteProgressPanel.this ); - } - - // true indicates a successful pause - protected boolean pauseForEffect() { - try { - Thread.sleep( (1000/fps) ); - } catch ( InterruptedException ie ) { - return false; // we've stopped the thread - } - Thread.yield(); - return true; - } - - protected void transformTicker() { - for ( Area element : ticker ) { - element.transform( transformToCircle ); - } - } - - protected void updateBackgroundAlpha() { - if ( alphaLevel <= 0 ) { - return; - } - - int elapsedTime = (int) (System.currentTimeMillis() - startRampupTime); - int increment = (255 * elapsedTime) / fadeDelayTime; - alphaLevel = 255 - increment; - if ( alphaLevel <= 0 ) { - alphaLevel = 0; - } - } - } - - private class Animator implements Runnable { - - private boolean inRampUpPeriod = false; - private final int rampDelayTime; - private AffineTransform transformToCircle; - private long startRampupTime; - - protected Animator( double transformTheta, int rampDelayTime ) { - this.rampDelayTime = rampDelayTime; - - Point2D.Double center = new Point2D.Double( (double) getWidth() / 2, - (double) getHeight() / 2 ); - transformToCircle = AffineTransform.getRotateInstance(transformTheta, - center.getX(), center.getY() ); - } - - public void run() { - startRampupTime = System.currentTimeMillis(); - if ( rampDelayTime == 0 ) { - alphaLevel = 255; - } - - paintAnimation = true; - inRampUpPeriod = true; - - while ( !Thread.interrupted() ) { - transformTicker(); - - repaint(); - - updateBackgroundAlpha(); - - if ( !pauseForEffect() ) { - break; - } - } - } - - // true indicates a successful pause - protected boolean pauseForEffect() { - try { - Thread.sleep( (1000/fps) ); - } catch ( InterruptedException ie ) { - return false; // we've stopped the thread - } - Thread.yield(); - return true; - } - - protected void transformTicker() { - if ( inRampUpPeriod ) { - return; - } - - for ( Area element : ticker ) { - element.transform( transformToCircle ); - } - } - - protected void updateBackgroundAlpha() { - if ( alphaLevel >= 255 ) { - inRampUpPeriod = false; - return; - } - - int elapsedTime = (int) (System.currentTimeMillis() - startRampupTime); - int increment = (255 * elapsedTime) / rampDelayTime; - alphaLevel = increment; - if ( alphaLevel >= 255 ) { - alphaLevel = 255; - inRampUpPeriod = false; - } - } - } - - public void mouseClicked(MouseEvent e) { - Toolkit.getDefaultToolkit().beep(); - } - - public void mouseEntered(MouseEvent e) { - } - - public void mouseExited(MouseEvent e) { - } - - public void mousePressed(MouseEvent e) { - } - - public void mouseReleased(MouseEvent e) { - } - - - - public static void main( String[] args ) { - - - final JFrame frame = new JFrame( "Ticker Test" ); - frame.setSize( 400, 600 ); - final Component originalGlassPane = frame.getGlassPane(); - final InfiniteProgressPanel progressPanel = new InfiniteProgressPanel("Processing request..."); - progressPanel.fps = 7; - progressPanel.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked( MouseEvent e ) { - //progressPanel.interrupt(); - progressPanel.stop(); - frame.setGlassPane(originalGlassPane); - } - } ); - - - JPanel mainPanel = new JPanel( new BorderLayout() ); - - JScrollPane scrollPane = new JScrollPane(); - final JTextArea textArea = new JTextArea( 50, 40 ); - textArea.setText("some text here..." ); - scrollPane.getViewport().add( textArea ); - mainPanel.add( scrollPane, BorderLayout.CENTER ); - - JButton button = new JButton( "Start" ); - button.addActionListener(new ActionListener() { - - public void actionPerformed( ActionEvent event ) { - frame.setGlassPane(progressPanel); - progressPanel.start(); - } - } ); - mainPanel.add( button, BorderLayout.SOUTH ); - - frame.setSize( 400, 400 ); - frame.setLocation( GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint() ); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - frame.getContentPane().add( mainPanel ); - frame.setVisible( true ); - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java index 89d512ea1f..fa4aad8e29 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java @@ -24,11 +24,11 @@ import javax.swing.tree.TreePath; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; import docking.widgets.tree.support.GTreeRenderer; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.nodes.SymbolNode; import ghidra.app.util.SymbolInspector; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; -import resources.ResourceManager; public class SymbolGTree extends GTree { @@ -65,9 +65,9 @@ public class SymbolGTree extends GTree { private class SymbolTreeCellRenderer extends GTreeRenderer { public final Icon OPEN_FOLDER_GROUP_ICON = - ResourceManager.loadImage("images/openFolderGroup.png"); + new GIcon("icon.plugin.symboltree.node.group.folder.open"); public final Icon CLOSED_FOLDER_GROUP_ICON = - ResourceManager.loadImage("images/closedFolderGroup.png"); + new GIcon("icon.plugin.symboltree.node.group.folder.closed"); public SymbolTreeCellRenderer() { setMinIconWidth(28); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java index b252bd652b..1c91b419d9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java @@ -33,6 +33,7 @@ import docking.widgets.tree.*; import docking.widgets.tree.support.GTreeNodeTransferable; import docking.widgets.tree.support.GTreeSelectionEvent.EventOrigin; import docking.widgets.tree.tasks.GTreeBulkTask; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.actions.*; import ghidra.app.plugin.core.symboltree.nodes.*; import ghidra.framework.model.*; @@ -46,12 +47,11 @@ import ghidra.program.util.*; import ghidra.util.*; import ghidra.util.exception.*; import ghidra.util.task.*; -import resources.ResourceManager; public class SymbolTreeProvider extends ComponentProviderAdapter { - private static final ImageIcon ICON = ResourceManager.loadImage("images/sitemap_color.png"); - private final static String NAME = "Symbol Tree"; + private static final Icon ICON = new GIcon("icon.plugin.symboltree.provider"); + private static final String NAME = "Symbol Tree"; private ClipboardOwner clipboardOwner; private Clipboard localClipboard;// temporary clipboard used for the "cut" operation diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CutAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CutAction.java index 255c5dbbde..1079a51a5e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CutAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CutAction.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.symboltree.actions; -import static docking.KeyBindingPrecedence.ActionMapLevel; +import static docking.KeyBindingPrecedence.*; import java.awt.datatransfer.*; import java.awt.event.InputEvent; @@ -35,10 +35,10 @@ import docking.widgets.tree.support.GTreeNodeTransferable; import docking.widgets.tree.support.GTreeTransferHandler; import ghidra.app.plugin.core.symboltree.*; import ghidra.app.plugin.core.symboltree.nodes.SymbolTreeNode; -import resources.ResourceManager; +import resources.Icons; public class CutAction extends SymbolTreeContextAction { - private final static Icon CUT_ICON = ResourceManager.loadImage("images/edit-cut22.png"); + private final static Icon CUT_ICON = Icons.CUT_ICON; private final SymbolTreeProvider provider; private ClipboardOwner clipboardOwner; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/DeleteAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/DeleteAction.java index 15a8cb19ec..fcc0231546 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/DeleteAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/DeleteAction.java @@ -27,11 +27,11 @@ import ghidra.app.plugin.core.symboltree.SymbolTreePlugin; import ghidra.app.plugin.core.symboltree.nodes.SymbolNode; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; -import resources.ResourceManager; +import resources.Icons; public class DeleteAction extends SymbolTreeContextAction { - private final static Icon DELETE_ICON = ResourceManager.loadImage("images/edit-delete.png"); + private final static Icon DELETE_ICON = Icons.DELETE_ICON; private final SymbolTreePlugin plugin; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/GoToExternalLocationAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/GoToExternalLocationAction.java index 8925584137..fff2d49e7f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/GoToExternalLocationAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/GoToExternalLocationAction.java @@ -16,12 +16,12 @@ package ghidra.app.plugin.core.symboltree.actions; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.context.ProgramSymbolActionContext; import ghidra.app.context.ProgramSymbolContextAction; import ghidra.app.plugin.core.symboltree.SymbolTreePlugin; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.*; -import resources.ResourceManager; public class GoToExternalLocationAction extends ProgramSymbolContextAction { @@ -32,7 +32,7 @@ public class GoToExternalLocationAction extends ProgramSymbolContextAction { this.plugin = plugin; setPopupMenuData(new MenuData(new String[] { "Go to External Location" }, - ResourceManager.loadImage("images/searchm_obj.gif"), "0External")); + new GIcon("icon.plugin.symboltree.goto"), "0External")); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/PasteAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/PasteAction.java index 1eb4d98f36..90b663ea9f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/PasteAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/PasteAction.java @@ -32,11 +32,11 @@ import docking.widgets.tree.GTreeNode; import docking.widgets.tree.support.GTreeDragNDropHandler; import ghidra.app.plugin.core.symboltree.*; import ghidra.app.plugin.core.symboltree.nodes.SymbolTreeNode; -import resources.ResourceManager; +import resources.Icons; public class PasteAction extends SymbolTreeContextAction { - private final static Icon PASTE_ICON = ResourceManager.loadImage("images/page_paste.png"); + private final static Icon PASTE_ICON = Icons.PASTE_ICON; public PasteAction(SymbolTreePlugin plugin, SymbolTreeProvider provider) { super("Paste Symbols", plugin.getName()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/SetExternalProgramAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/SetExternalProgramAction.java index 53500473f1..2b50d93c0d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/SetExternalProgramAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/SetExternalProgramAction.java @@ -15,6 +15,13 @@ */ package ghidra.app.plugin.core.symboltree.actions; +import javax.swing.Icon; +import javax.swing.SwingUtilities; +import javax.swing.tree.TreePath; + +import docking.action.MenuData; +import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.cmd.refs.SetExternalNameCmd; import ghidra.app.plugin.core.symboltree.*; import ghidra.app.plugin.core.symboltree.nodes.LibrarySymbolNode; @@ -26,19 +33,8 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.ExternalManager; import ghidra.util.HelpLocation; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.ImageIcon; -import javax.swing.SwingUtilities; -import javax.swing.tree.TreePath; - -import docking.action.MenuData; -import docking.action.ToolBarData; -import resources.ResourceManager; - public class SetExternalProgramAction extends SymbolTreeContextAction { - private static ImageIcon EDIT_ICON = ResourceManager.loadImage("images/editbytes.gif"); + private static Icon EDIT_ICON = new GIcon("icon.plugin.symboltree.set.external"); private final SymbolTreePlugin plugin; private SymbolTreeProvider provider; @@ -89,34 +85,27 @@ public class SetExternalProgramAction extends SymbolTreeContextAction { dialog.setSearchText(externalName); - dialog.addOkActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e1) { - DomainFile domainFile = dialog.getDomainFile(); - if (domainFile == null) { - return; - } - String pathName = domainFile.toString(); - dialog.close(); - if (!pathName.equals(externalLibraryPath)) { - Command cmd = new SetExternalNameCmd(externalName, domainFile.getPathname()); - plugin.getTool().execute(cmd, plugin.getProgram()); - } + dialog.addOkActionListener(e1 -> { + DomainFile domainFile = dialog.getDomainFile(); + if (domainFile == null) { + return; + } + String pathName = domainFile.toString(); + dialog.close(); + if (!pathName.equals(externalLibraryPath)) { + Command cmd = new SetExternalNameCmd(externalName, domainFile.getPathname()); + plugin.getTool().execute(cmd, plugin.getProgram()); } }); dialog.setHelpLocation(new HelpLocation("SymbolTreePlugin", "ChooseExternalProgram")); if (externalLibraryPath != null) { - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - Project project = AppInfo.getActiveProject(); - ProjectData pd = project.getProjectData(); - DomainFile domainFile = pd.getFile(externalLibraryPath); - if (domainFile != null) { - dialog.selectDomainFile(domainFile); - } + SwingUtilities.invokeLater(() -> { + Project project = AppInfo.getActiveProject(); + ProjectData pd = project.getProjectData(); + DomainFile domainFile = pd.getFile(externalLibraryPath); + if (domainFile != null) { + dialog.selectDomainFile(domainFile); } }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassCategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassCategoryNode.java index 5bcfd2e031..214290a980 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassCategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassCategoryNode.java @@ -21,21 +21,20 @@ import java.util.*; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.listing.GhidraClass; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; -import resources.ResourceManager; public class ClassCategoryNode extends SymbolCategoryNode { public static final Icon OPEN_FOLDER_CLASSES_ICON = - ResourceManager.loadImage("images/openFolderClasses.png"); + new GIcon("icon.plugin.symboltree.node.category.classes.open"); public static final Icon CLOSED_FOLDER_CLASSES_ICON = - ResourceManager.loadImage("images/closedFolderClasses.png"); + new GIcon("icon.plugin.symboltree.node.category.classes.closed"); ClassCategoryNode(Program program) { super(SymbolCategory.CLASS_CATEGORY, program); @@ -74,7 +73,7 @@ public class ClassCategoryNode extends SymbolCategoryNode { Namespace parentNamespace = symbol.getParentNamespace(); Symbol namespaceSymbol = parentNamespace.getSymbol(); SymbolNode key = SymbolNode.createNode(namespaceSymbol, program); - GTreeNode parentNode = findSymbolTreeNode(key, false, TaskMonitorAdapter.DUMMY_MONITOR); + GTreeNode parentNode = findSymbolTreeNode(key, false, TaskMonitor.DUMMY); if (parentNode == null) { return null; } @@ -84,7 +83,7 @@ public class ClassCategoryNode extends SymbolCategoryNode { @Override protected List getSymbols(SymbolType type, TaskMonitor monitor) throws CancelledException { - List list = new ArrayList(); + List list = new ArrayList<>(); monitor.initialize(symbolTable.getNumSymbols()); SymbolType symbolType = symbolCategory.getSymbolType(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassSymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassSymbolNode.java index 1e1e166f82..db0315ddc2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassSymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ClassSymbolNode.java @@ -18,8 +18,8 @@ package ghidra.app.plugin.core.symboltree.nodes; import java.awt.datatransfer.DataFlavor; import javax.swing.Icon; -import javax.swing.ImageIcon; +import generic.theme.GIcon; import ghidra.app.util.SelectionTransferData; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Namespace; @@ -32,9 +32,9 @@ public class ClassSymbolNode extends SymbolNode { static final DataFlavor GLOBAL_DATA_FLAVOR = new SymbolTreeDataFlavor("Symbol Tree Data Flavor - Global Classes"); - private static Icon CLASS_ICON = ResourceManager.loadImage("images/class.png"); - private static Icon DISABLED_CLASS_ICONDISABLED_CLASS_ICON = - ResourceManager.getDisabledIcon((ImageIcon) CLASS_ICON); + private static final Icon CLASS_ICON = new GIcon("icon.plugin.symboltree.node.class"); + private static final Icon DISABLED_CLASS_ICONDISABLED_CLASS_ICON = + ResourceManager.getDisabledIcon(CLASS_ICON); ClassSymbolNode(Program program, Symbol symbol) { super(program, symbol); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/CodeSymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/CodeSymbolNode.java index f337aea651..e2d722f2b8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/CodeSymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/CodeSymbolNode.java @@ -18,8 +18,8 @@ package ghidra.app.plugin.core.symboltree.nodes; import java.awt.datatransfer.DataFlavor; import javax.swing.Icon; -import javax.swing.ImageIcon; +import generic.theme.GIcon; import ghidra.app.util.ToolTipUtils; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.ExternalLocation; @@ -34,13 +34,13 @@ public class CodeSymbolNode extends SymbolNode { static final DataFlavor EXTERNAL_DATA_FLAVOR = new SymbolTreeDataFlavor("Symbol Tree Data Flavor - External Data"); - private static final Icon CODE_ICON = ResourceManager.loadImage("images/label.png"); - private static final Icon PINNED_ICON = ResourceManager.loadImage("images/pin.png"); - private static final Icon EXTERNAL_ICON = ResourceManager.loadImage("images/ExternalData.gif"); - private static final Icon DISABLED_CODE_ICON = - ResourceManager.getDisabledIcon((ImageIcon) CODE_ICON); - private static final Icon DISABLED_EXTERNAL_ICON = - ResourceManager.getDisabledIcon((ImageIcon) EXTERNAL_ICON); + //@formatter:off + private static final Icon CODE_ICON = new GIcon("icon.plugin.symboltree.node.code"); + private static final Icon PINNED_ICON = new GIcon("icon.plugin.symboltree.node.code.pinned"); + private static final Icon EXTERNAL_ICON = new GIcon("icon.plugin.symboltree.node.code.external"); + private static final Icon DISABLED_CODE_ICON = ResourceManager.getDisabledIcon(CODE_ICON); + private static final Icon DISABLED_EXTERNAL_ICON = ResourceManager.getDisabledIcon(EXTERNAL_ICON); + //@formatter:on private String tooltip; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ExportsCategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ExportsCategoryNode.java index 44940769a3..656d64d0cf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ExportsCategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ExportsCategoryNode.java @@ -20,16 +20,18 @@ import java.util.*; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.address.AddressIterator; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; class ExportsCategoryNode extends SymbolCategoryNode { - private static final Icon OPEN_FOLDER = ResourceManager.loadImage("images/openFolder.png"); - private static final Icon CLOSED_FOLDER = ResourceManager.loadImage("images/closedFolder.png"); + private static final Icon OPEN_FOLDER = + new GIcon("icon.plugin.symboltree.node.category.exports.open"); + private static final Icon CLOSED_FOLDER = + new GIcon("icon.plugin.symboltree.node.category.exports.closed"); ExportsCategoryNode(Program program) { super(SymbolCategory.EXPORTS_CATEGORY, program); @@ -37,7 +39,7 @@ class ExportsCategoryNode extends SymbolCategoryNode { @Override public List generateChildren(TaskMonitor monitor) { - List list = new ArrayList(); + List list = new ArrayList<>(); List functionSymbolList = getExportSymbols(); for (Symbol symbol : functionSymbolList) { @@ -50,7 +52,7 @@ class ExportsCategoryNode extends SymbolCategoryNode { } private List getExportSymbols() { - List symbols = new ArrayList(); + List symbols = new ArrayList<>(); AddressIterator iterator = symbolTable.getExternalEntryPointIterator(); while (iterator.hasNext()) { Symbol symbol = symbolTable.getPrimarySymbol(iterator.next()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionCategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionCategoryNode.java index 8692b83324..336dba25c6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionCategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionCategoryNode.java @@ -22,19 +22,19 @@ import java.util.List; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.*; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; class FunctionCategoryNode extends SymbolCategoryNode { public static final Icon OPEN_FOLDER_FUNCTIONS_ICON = - ResourceManager.loadImage("images/openFolderFunctions.png"); + new GIcon("icon.plugin.symboltree.node.category.function.open"); public static final Icon CLOSED_FOLDER_FUNCTIONS_ICON = - ResourceManager.loadImage("images/closedFolderFunctions.png"); + new GIcon("icon.plugin.symboltree.node.category.function.closed"); FunctionCategoryNode(Program program) { super(SymbolCategory.FUNCTION_CATEGORY, program); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionSymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionSymbolNode.java index 6383dc296c..3e6d463cc8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionSymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/FunctionSymbolNode.java @@ -19,9 +19,9 @@ import java.awt.datatransfer.DataFlavor; import java.util.Comparator; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.util.ToolTipUtils; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Symbol; @@ -30,23 +30,19 @@ import ghidra.util.task.TaskMonitor; import resources.ResourceManager; public class FunctionSymbolNode extends SymbolNode { - static final DataFlavor LOCAL_DATA_FLAVOR = - new SymbolTreeDataFlavor("Symbol Tree Data Flavor - Local Functions"); - static final DataFlavor GLOBAL_DATA_FLAVOR = - new SymbolTreeDataFlavor("Symbol Tree Data Flavor - Global Functions"); - static final DataFlavor EXTERNAL_DATA_FLAVOR = - new SymbolTreeDataFlavor("Symbol Tree Data Flavor - External Functions"); - public static final Icon FUNCTION_ICON = ResourceManager.loadImage("images/FunctionScope.gif"); - public static final Icon THUNK_ICON = ResourceManager.loadImage("images/ThunkFunction.gif"); - public static final Icon EXTERNAL_ICON = - ResourceManager.loadImage("images/ExternalFunction.gif"); - public static final Icon DISABLED_FUNCTION_ICON = - ResourceManager.getDisabledIcon((ImageIcon) FUNCTION_ICON); - public static final Icon DISABLED_THUNK_ICON = - ResourceManager.getDisabledIcon((ImageIcon) THUNK_ICON); - public static final Icon DISABLED_EXTERNAL_ICON = - ResourceManager.getDisabledIcon((ImageIcon) EXTERNAL_ICON); + //@formatter:off + static final DataFlavor LOCAL_DATA_FLAVOR = new SymbolTreeDataFlavor("Symbol Tree Data Flavor - Local Functions"); + static final DataFlavor GLOBAL_DATA_FLAVOR = new SymbolTreeDataFlavor("Symbol Tree Data Flavor - Global Functions"); + static final DataFlavor EXTERNAL_DATA_FLAVOR = new SymbolTreeDataFlavor("Symbol Tree Data Flavor - External Functions"); + + public static final Icon FUNCTION_ICON = new GIcon("icon.plugin.symboltree.node.function"); + public static final Icon THUNK_ICON = new GIcon("icon.plugin.symboltree.node.function.thunk"); + public static final Icon EXTERNAL_ICON = new GIcon("icon.plugin.symboltree.node.function.external"); + public static final Icon DISABLED_FUNCTION_ICON = ResourceManager.getDisabledIcon(FUNCTION_ICON); + public static final Icon DISABLED_THUNK_ICON = ResourceManager.getDisabledIcon(THUNK_ICON); + public static final Icon DISABLED_EXTERNAL_ICON = ResourceManager.getDisabledIcon(EXTERNAL_ICON); + //@formatter:on private static Comparator CHILD_COMPARATOR = new FunctionVariableComparator(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ImportsCategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ImportsCategoryNode.java index 3573ba2e85..88571e92f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ImportsCategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ImportsCategoryNode.java @@ -17,17 +17,17 @@ package ghidra.app.plugin.core.symboltree.nodes; import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; -import resources.ResourceManager; public class ImportsCategoryNode extends SymbolCategoryNode { private static Icon CLOSED_FOLDER_EXTERNALS_ICON = - ResourceManager.loadImage("images/closedFolderExternals.png"); + new GIcon("icon.plugin.symboltree.node.category.imports.closed"); private static Icon OPEN_FOLDER_EXTERNALS_ICON = - ResourceManager.loadImage("images/openFolderExternals.png"); + new GIcon("icon.plugin.symboltree.node.category.imports.open"); public ImportsCategoryNode(Program program) { super(SymbolCategory.IMPORTS_CATEGORY, program); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LabelCategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LabelCategoryNode.java index ad07089d75..f268b5c9b7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LabelCategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LabelCategoryNode.java @@ -22,20 +22,20 @@ import java.util.List; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.SymbolType; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class LabelCategoryNode extends SymbolCategoryNode { public static final Icon OPEN_FOLDER_LABELS_ICON = - ResourceManager.loadImage("images/openFolderLabels.png"); + new GIcon("icon.plugin.symboltree.node.category.label.open"); public static final Icon CLOSED_FOLDER_LABELS_ICON = - ResourceManager.loadImage("images/closedFolderLabels.png"); + new GIcon("icon.plugin.symboltree.node.category.label.closed"); public LabelCategoryNode(Program program) { super(SymbolCategory.LABEL_CATEGORY, program); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LibrarySymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LibrarySymbolNode.java index 2f189dc660..bfb656ec45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LibrarySymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LibrarySymbolNode.java @@ -21,16 +21,16 @@ import java.util.Comparator; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.program.model.listing.Library; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.*; -import resources.ResourceManager; public class LibrarySymbolNode extends SymbolNode { private static final String ORDINAL_PREFIX = "Ordinal_"; - private static Icon LIBRARY_ICON = ResourceManager.loadImage("images/package.png"); + private static final Icon LIBRARY_ICON = new GIcon("icon.plugin.symboltree.node.library"); private static Comparator CHILD_COMPARATOR = (o1, o2) -> { SymbolNode symbolNode1 = (SymbolNode) o1; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LocalVariableSymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LocalVariableSymbolNode.java index ea605ef8d1..41ba219b28 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LocalVariableSymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/LocalVariableSymbolNode.java @@ -17,14 +17,14 @@ package ghidra.app.plugin.core.symboltree.nodes; import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; -import resources.ResourceManager; public class LocalVariableSymbolNode extends SymbolNode { public static final Icon LOCAL_VARIABLE_ICON = - ResourceManager.loadImage("images/LocalVariable.gif"); + new GIcon("icon.plugin.symboltree.node.local.variable"); LocalVariableSymbolNode(Program program, Symbol symbol) { super(program, symbol); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceCategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceCategoryNode.java index 6df89802cd..3a6259efd5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceCategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceCategoryNode.java @@ -19,18 +19,18 @@ import java.awt.datatransfer.DataFlavor; import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Symbol; -import resources.ResourceManager; public class NamespaceCategoryNode extends SymbolCategoryNode { public static final Icon OPEN_FOLDER_NAMESPACES_ICON = - ResourceManager.loadImage("images/openFolderNamespaces.png"); + new GIcon("icon.plugin.symboltree.node.category.namespace.open"); public static final Icon CLOSED_FOLDER_NAMESPACES_ICON = - ResourceManager.loadImage("images/closedFolderNamespaces.png"); + new GIcon("icon.plugin.symboltree.node.category.namespace.closed"); NamespaceCategoryNode(Program program) { super(SymbolCategory.NAMESPACE_CATEGORY, program); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceSymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceSymbolNode.java index 427f5d7630..ff17bc325e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceSymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/NamespaceSymbolNode.java @@ -18,8 +18,8 @@ package ghidra.app.plugin.core.symboltree.nodes; import java.awt.datatransfer.DataFlavor; import javax.swing.Icon; -import javax.swing.ImageIcon; +import generic.theme.GIcon; import ghidra.app.util.SelectionTransferData; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Namespace; @@ -32,9 +32,9 @@ public class NamespaceSymbolNode extends SymbolNode { static final DataFlavor GLOBAL_DATA_FLAVOR = new SymbolTreeDataFlavor("Symbol Tree Data Flavor - Global Namespaces"); - public static final Icon NAMESPACE_ICON = ResourceManager.loadImage("images/Namespace.gif"); + public static final Icon NAMESPACE_ICON = new GIcon("icon.plugin.symboltree.node.namespace"); public static final Icon DISABLED_NAMESPACE_ICON = - ResourceManager.getDisabledIcon((ImageIcon) NAMESPACE_ICON); + ResourceManager.getDisabledIcon(NAMESPACE_ICON); NamespaceSymbolNode(Program program, Symbol symbol) { super(program, symbol); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/OrganizationNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/OrganizationNode.java index d70c1b2c4f..c5a9cfb6ae 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/OrganizationNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/OrganizationNode.java @@ -23,13 +23,13 @@ import javax.swing.Icon; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; import docking.widgets.tree.tasks.GTreeCollapseAllTask; +import generic.theme.GIcon; import ghidra.program.model.symbol.Namespace; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** - * These nodes are used to organize large lists of nodes into a hierachical structure based on + * These nodes are used to organize large lists of nodes into a hierarchical structure based on * the node names. See {@link #organize(List, int, TaskMonitor)} for details on * how this class works. */ @@ -39,9 +39,9 @@ public class OrganizationNode extends SymbolTreeNode { static final Comparator COMPARATOR = new OrganizationNodeComparator(); private static Icon OPEN_FOLDER_GROUP_ICON = - ResourceManager.loadImage("images/openFolderGroup.png"); + new GIcon("icon.plugin.symboltree.node.organization.open"); private static Icon CLOSED_FOLDER_GROUP_ICON = - ResourceManager.loadImage("images/closedFolderGroup.png"); + new GIcon("icon.plugin.symboltree.node.organization.closed"); private String baseName; private int totalCount; @@ -370,7 +370,7 @@ public class OrganizationNode extends SymbolTreeNode { for (GTreeNode node : nodeList) { monitor.checkCanceled(); String prefix = getPrefix(node, uniquePrefixSize); - List list = map.computeIfAbsent(prefix, k -> new ArrayList()); + List list = map.computeIfAbsent(prefix, k -> new ArrayList<>()); list.add(node); } if (map.size() == 1) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ParameterSymbolNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ParameterSymbolNode.java index 56ec805771..43799aa56a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ParameterSymbolNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/ParameterSymbolNode.java @@ -17,13 +17,13 @@ package ghidra.app.plugin.core.symboltree.nodes; import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; -import resources.ResourceManager; public class ParameterSymbolNode extends SymbolNode { - public static final Icon PARAMETER_ICON = ResourceManager.loadImage("images/Parameter.gif"); + public static final Icon PARAMETER_ICON = new GIcon("icon.plugin.symboltree.node.parameter"); ParameterSymbolNode(Program program, Symbol symbol) { super(program, symbol); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/SymbolTreeRootNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/SymbolTreeRootNode.java index 778b0621ac..245d5520b5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/SymbolTreeRootNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/nodes/SymbolTreeRootNode.java @@ -23,15 +23,15 @@ import java.util.*; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.app.plugin.core.symboltree.SymbolCategory; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.SymbolType; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class SymbolTreeRootNode extends SymbolCategoryNode { - private static Icon GLOBAL_ICON = ResourceManager.loadImage("images/bullet_green.png"); + private static Icon GLOBAL_ICON = new GIcon("icon.plugin.symboltree.node.root"); private final String name; public SymbolTreeRootNode() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java index cb83b9219c..647576b7e8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/FilterDialog.java @@ -33,7 +33,7 @@ import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.PluginTool; import ghidra.util.*; import ghidra.util.layout.*; -import resources.ResourceManager; +import resources.Icons; public class FilterDialog extends DialogComponentProvider { private NewSymbolFilter filter; @@ -162,7 +162,7 @@ public class FilterDialog extends DialogComponentProvider { advancedPanel = new JPanel(new BorderLayout()); JPanel infoPanel = new JPanel(new HorizontalLayout(20)); - Icon icon = ResourceManager.loadImage("images/information.png"); + Icon icon = Icons.INFO_ICON; infoPanel.add(new GIconLabel(icon)); infoPanel.add(new GHtmlLabel( diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferenceProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferenceProvider.java index 4a7e8a8f71..0258e1a0d1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferenceProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferenceProvider.java @@ -17,11 +17,12 @@ package ghidra.app.plugin.core.symtable; import java.awt.event.MouseEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import docking.ActionContext; import docking.WindowPosition; +import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.app.util.SymbolInspector; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -30,11 +31,10 @@ import ghidra.program.model.symbol.Symbol; import ghidra.util.HelpLocation; import ghidra.util.Swing; import ghidra.util.table.GhidraTable; -import resources.ResourceManager; class ReferenceProvider extends ComponentProviderAdapter { - private static final ImageIcon ICON = ResourceManager.loadImage("images/table_go.png"); + private static final Icon ICON = new GIcon("icon.plugin.symboltable.referencetable.provider"); private SymbolTablePlugin plugin; private SymbolReferenceModel referenceKeyModel; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolProvider.java index 17fc15e28a..32f100fd4e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolProvider.java @@ -19,12 +19,13 @@ import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import docking.ActionContext; import docking.DockingUtils; import docking.action.KeyBindingData; +import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.app.context.ProgramSymbolActionContext; import ghidra.app.util.SymbolInspector; @@ -34,11 +35,10 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.Symbol; import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTable; -import resources.ResourceManager; class SymbolProvider extends ComponentProviderAdapter { - private static final ImageIcon ICON = ResourceManager.loadImage("images/table.png"); + private static final Icon ICON = new GIcon("icon.plugin.symboltable.provider"); private SymbolTablePlugin plugin; private SymbolRenderer renderer; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolRenderer.java index d0ac3f78a8..0c05518968 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolRenderer.java @@ -19,6 +19,7 @@ import java.awt.Color; import java.awt.Component; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.SymbolInspector; import ghidra.program.model.address.Address; import ghidra.program.model.lang.Register; @@ -78,7 +79,7 @@ class SymbolRenderer extends GhidraTableCellRenderer { setBold(); Color color = (inspector != null) && (value instanceof Symbol) ? inspector.getColor((Symbol) value) - : Color.BLACK; + : Colors.FOREGROUND; if (!isSelected) { setForeground(color); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java index 42d076b1b7..c61214ee47 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java @@ -18,10 +18,11 @@ package ghidra.app.plugin.core.symtable; import java.awt.Cursor; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.events.ProgramActivatedPluginEvent; import ghidra.app.events.ProgramLocationPluginEvent; @@ -48,7 +49,6 @@ import ghidra.util.task.TaskMonitor; import ghidra.util.worker.Job; import ghidra.util.worker.Worker; import resources.Icons; -import resources.ResourceManager; /** * Plugin to display the symbol table for a program. @@ -231,8 +231,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { case ChangeManager.DOCR_CODE_ADDED: case ChangeManager.DOCR_CODE_REMOVED: if (rec.getNewValue() instanceof Data) { - domainObjectWorker.schedule( - new CodeAddedRemoveJob(currentProgram, rec.getStart())); + domainObjectWorker + .schedule(new CodeAddedRemoveJob(currentProgram, rec.getStart())); } break; @@ -241,16 +241,15 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { // dynamic label symbols. Reference events must be used to check for existence // of a dynamic label symbol. Symbol symbol = (Symbol) rec.getNewValue(); - domainObjectWorker.schedule( - new SymbolAddedJob(currentProgram, symbol)); + domainObjectWorker.schedule(new SymbolAddedJob(currentProgram, symbol)); break; case ChangeManager.DOCR_SYMBOL_REMOVED: Address removeAddr = rec.getStart(); Long symbolID = (Long) rec.getNewValue(); - domainObjectWorker.schedule( - new SymbolRemovedJob(currentProgram, removeAddr, symbolID)); + domainObjectWorker + .schedule(new SymbolRemovedJob(currentProgram, removeAddr, symbolID)); break; case ChangeManager.DOCR_SYMBOL_RENAMED: @@ -294,8 +293,8 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED: Address address = rec.getStart(); - domainObjectWorker.schedule( - new ExternalEntryChangedJob(currentProgram, address)); + domainObjectWorker + .schedule(new ExternalEntryChangedJob(currentProgram, address)); break; } } @@ -344,7 +343,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { refProvider.setCurrentSymbol(symProvider.getCurrentSymbol()); } }; - ImageIcon icon = ResourceManager.loadImage("images/table_go.png"); + Icon icon = new GIcon("icon.plugin.symboltable.referencetable.provider"); openRefsAction.setPopupMenuData( new MenuData(new String[] { "Symbol References" }, icon, popupGroup)); openRefsAction.setToolBarData(new ToolBarData(icon)); @@ -370,7 +369,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { } }; - icon = ResourceManager.loadImage("images/edit-delete.png"); + icon = Icons.DELETE_ICON; String deleteGroup = "3"; // put in a group after the others deleteAction.setPopupMenuData(new MenuData(new String[] { "Delete" }, icon, deleteGroup)); deleteAction.setToolBarData(new ToolBarData(icon)); @@ -445,7 +444,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { referencesToAction.setDescription("References To"); referencesToAction.setSelected(true); referencesToAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/references_to.gif"), null)); + new ToolBarData(new GIcon("icon.plugin.symboltable.references.to"), null)); tool.addLocalAction(refProvider, referencesToAction); @@ -467,8 +466,9 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { }; instructionsFromAction.setDescription("Instructions From"); instructionsFromAction.setSelected(false); - instructionsFromAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/I.gif"), null)); + instructionsFromAction + .setToolBarData( + new ToolBarData(new GIcon("icon.plugin.symboltable.instructions.from"), null)); tool.addLocalAction(refProvider, instructionsFromAction); @@ -490,8 +490,9 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { }; dataFromAction.setDescription("Data From"); dataFromAction.setSelected(false); - dataFromAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/D.gif"), null)); + dataFromAction + .setToolBarData( + new ToolBarData(new GIcon("icon.plugin.symboltable.data.from"), null)); tool.addLocalAction(refProvider, dataFromAction); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java index efd59a9889..495df3b130 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java @@ -32,6 +32,7 @@ import docking.action.MenuData; import docking.widgets.table.AbstractSortedTableModel; import docking.widgets.table.GTable; import docking.widgets.table.threaded.GThreadedTablePanel; +import generic.theme.GIcon; import ghidra.app.nav.Navigatable; import ghidra.app.nav.NavigatableRemovalListener; import ghidra.app.services.*; @@ -45,7 +46,6 @@ import ghidra.util.HelpLocation; import ghidra.util.table.*; import ghidra.util.table.actions.DeleteTableRowAction; import ghidra.util.table.actions.MakeProgramSelectionAction; -import resources.ResourceManager; public class TableComponentProvider extends ComponentProviderAdapter implements TableModelListener, NavigatableRemovalListener { @@ -78,7 +78,7 @@ public class TableComponentProvider extends ComponentProviderAdapter TableComponentProvider(TableServicePlugin plugin, String title, String name, GhidraProgramTableModel model, String programName, GoToService gotoService, - MarkerService markerService, Color markerColor, ImageIcon markerIcon, + MarkerService markerService, Color markerColor, Icon markerIcon, String windowSubMenu, Navigatable navigatable) { super(plugin.getTool(), name, plugin.getName()); @@ -89,7 +89,7 @@ public class TableComponentProvider extends ComponentProviderAdapter this.programName = programName; this.markerService = markerService; this.windowSubMenu = windowSubMenu; - setIcon(ResourceManager.loadImage("images/magnifier.png")); + setIcon(new GIcon("icon.plugin.table.service")); setTransient(); setTitle(title); setHelpLocation(helpLoc); @@ -186,7 +186,7 @@ public class TableComponentProvider extends ComponentProviderAdapter externalGotoAction.setDescription("Go to an external location"); externalGotoAction.setEnabled(false); - Icon icon = ResourceManager.loadImage("images/searchm_obj.gif"); + Icon icon = new GIcon("icon.plugin.table.service.marker"); externalGotoAction.setPopupMenuData( new MenuData(new String[] { "GoTo External Location" }, icon, null)); externalGotoAction.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Navigation")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableServicePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableServicePlugin.java index 04fb38fa79..a3d0d9580e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableServicePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableServicePlugin.java @@ -18,7 +18,7 @@ package ghidra.app.plugin.core.table; import java.awt.Color; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import ghidra.app.CorePluginPackage; import ghidra.app.events.ProgramClosedPluginEvent; @@ -153,7 +153,7 @@ public class TableServicePlugin extends ProgramPlugin @Override public TableComponentProvider showTableWithMarkers(String title, String tableTypeName, - GhidraProgramTableModel model, Color markerColor, ImageIcon markerIcon, + GhidraProgramTableModel model, Color markerColor, Icon markerIcon, String windowSubMenu, Navigatable navigatable) { GoToService gotoService = tool.getService(GoToService.class); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java index 799af68a53..fc5a3a0721 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/totd/TipOfTheDayDialog.java @@ -15,8 +15,8 @@ */ package ghidra.app.plugin.core.totd; -import java.awt.*; -import java.awt.event.*; +import java.awt.BorderLayout; +import java.awt.Component; import java.util.List; import javax.swing.*; @@ -26,9 +26,14 @@ import docking.DialogComponentProvider; import docking.DockingWindowManager; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GLabel; -import resources.ResourceManager; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.Gui; class TipOfTheDayDialog extends DialogComponentProvider { + private static final String FONT_ID = "font.plugin.tips"; + private static final String FONT_LABEL_ID = "font.plugin.tips.label"; private static final int _24_HOURS = 86400000; private TipOfTheDayPlugin plugin; private JCheckBox showTipsCheckbox; @@ -48,11 +53,11 @@ class TipOfTheDayDialog extends DialogComponentProvider { tips.add("Could not find any tips!"); } - ImageIcon tipIcon = ResourceManager.loadImage("images/help-hint.png"); + Icon tipIcon = new GIcon("icon.plugin.totd.provider"); tipArea = new JTextArea(4, 30); tipArea.setEditable(false); - tipArea.setFont(new Font("dialog", Font.PLAIN, 12)); + tipArea.setFont(Gui.getFont(FONT_ID)); tipArea.setWrapStyleWord(true); tipArea.setLineWrap(true); tipArea.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); @@ -65,41 +70,28 @@ class TipOfTheDayDialog extends DialogComponentProvider { showTipsCheckbox = new GCheckBox("Show Tips on Startup?"); showTipsCheckbox.setSelected(true); // TODO (FixMe) Moved this before its listener to prevent project save for now. - showTipsCheckbox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - showTipsChanged(); - } - }); + showTipsCheckbox.addItemListener(e -> showTipsChanged()); nextTipButton = new JButton("Next Tip"); - nextTipButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - incrementTipIndex(); - loadNextTip(); - } + nextTipButton.addActionListener(e -> { + incrementTipIndex(); + loadNextTip(); }); addButton(nextTipButton); closeButton = new JButton("Close"); - closeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - close(); - } - }); + closeButton.addActionListener(e -> close()); addButton(closeButton); JPanel panel = new JPanel(new BorderLayout()); Border panelBorder = BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10), - BorderFactory.createLineBorder(Color.BLACK)); + BorderFactory.createLineBorder(Java.BORDER)); panel.setBorder(panelBorder); - panel.setBackground(Color.WHITE); + panel.setBackground(Colors.BACKGROUND); JLabel label = new GLabel("Did you know...", tipIcon, SwingConstants.LEFT); - label.setFont(new Font("dialog", Font.BOLD, 12)); + Gui.registerFont(label, FONT_LABEL_ID); panel.add(label, BorderLayout.NORTH); panel.add(tipScroll, BorderLayout.CENTER); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerPlugin.java index 21faf46bf0..c29cdc1094 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerPlugin.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.debug; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; @@ -73,7 +73,7 @@ public class DbViewerPlugin extends Plugin { }; refreshAction.setEnabled(false); - ImageIcon icon = Icons.REFRESH_ICON; + Icon icon = Icons.REFRESH_ICON; refreshAction.setToolBarData(new ToolBarData(icon)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerProvider.java index d39a63b7d8..7b837bd9f8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DbViewerProvider.java @@ -19,15 +19,13 @@ import javax.swing.JComponent; import db.DBHandle; import docking.WindowPosition; +import generic.theme.GIcon; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.Plugin; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class DbViewerProvider extends ComponentProviderAdapter { - private static final String ICON_IMAGE = "images/zoom.png"; - private DBHandle dbh; private String dbName; private DbViewerComponent comp; @@ -35,7 +33,7 @@ public class DbViewerProvider extends ComponentProviderAdapter { public DbViewerProvider(Plugin plugin) { super(plugin.getTool(), "Database Viewer", plugin.getName()); - setIcon(ResourceManager.loadImage(ICON_IMAGE)); + setIcon(new GIcon("icon.plugin.debug.dbviewer.provider")); setDefaultWindowPosition(WindowPosition.BOTTOM); setHelpLocation(new HelpLocation(plugin.getName(), "DbViewer")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainEventComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainEventComponentProvider.java index 4c07160b56..e51804fe0b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainEventComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainEventComponentProvider.java @@ -25,13 +25,14 @@ import docking.ActionContext; import docking.WindowPosition; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; -import resources.ResourceManager; +import resources.Icons; public class DomainEventComponentProvider extends ComponentProviderAdapter { final static int LIMIT = 200; - private final static ImageIcon ICON = ResourceManager.loadImage("images/monitor.png"); + private final static Icon ICON = new GIcon("icon.plugin.debug.domaineventviewer.provider"); private JTextArea textArea; private JScrollPane scrollPane; @@ -84,7 +85,7 @@ public class DomainEventComponentProvider extends ComponentProviderAdapter { clearAction.markHelpUnnecessary(); clearAction.setEnabled(true); - ImageIcon icon = ResourceManager.loadImage("images/erase16.png"); + Icon icon = Icons.CLEAR_ICON; clearAction.setToolBarData(new ToolBarData(icon)); addLocalAction(clearAction); } @@ -109,8 +110,7 @@ public class DomainEventComponentProvider extends ComponentProviderAdapter { } textArea.setText(""); int length = 0; - for (int i = 0; i < eventList.size(); i++) { - String str = eventList.get(i); + for (String str : eventList) { textArea.append(str); length += str.length(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayComponentProvider.java index ccaafbccb2..51d4531b8f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/DomainFolderChangesDisplayComponentProvider.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +15,19 @@ */ package ghidra.app.plugin.debug; -import ghidra.framework.plugintool.ComponentProviderAdapter; -import ghidra.framework.plugintool.PluginTool; -import ghidra.util.Msg; - import java.awt.Point; import java.util.Date; import javax.swing.*; -import resources.ResourceManager; import docking.ActionContext; import docking.WindowPosition; import docking.action.DockingAction; import docking.action.ToolBarData; +import ghidra.framework.plugintool.ComponentProviderAdapter; +import ghidra.framework.plugintool.PluginTool; +import ghidra.util.Msg; +import resources.Icons; public class DomainFolderChangesDisplayComponentProvider extends ComponentProviderAdapter { private JTextArea textArea; @@ -72,7 +70,7 @@ public class DomainFolderChangesDisplayComponentProvider extends ComponentProvid } }; clearAction.setEnabled(true); - ImageIcon icon = ResourceManager.loadImage("images/erase16.png"); + Icon icon = Icons.CLEAR_ICON; clearAction.setToolBarData(new ToolBarData(icon)); addLocalAction(clearAction); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/EventDisplayComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/EventDisplayComponentProvider.java index c04a547481..3b33ff1f4e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/EventDisplayComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/EventDisplayComponentProvider.java @@ -27,7 +27,7 @@ import docking.action.ToolBarData; import ghidra.app.events.ProgramLocationPluginEvent; import ghidra.framework.plugintool.*; import ghidra.program.util.ProgramLocation; -import resources.ResourceManager; +import resources.Icons; public class EventDisplayComponentProvider extends ComponentProviderAdapter { private JTextArea textArea; @@ -82,7 +82,7 @@ public class EventDisplayComponentProvider extends ComponentProviderAdapter { clearAction.markHelpUnnecessary(); clearAction.setEnabled(true); - ImageIcon icon = ResourceManager.loadImage("images/erase16.png"); + Icon icon = Icons.CLEAR_ICON; clearAction.setToolBarData(new ToolBarData(icon)); addLocalAction(clearAction); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerPlugin.java index 9efce398e4..1c9d8fb6ed 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerPlugin.java @@ -15,6 +15,11 @@ */ package ghidra.app.plugin.debug.propertymanager; +import javax.swing.Icon; +import javax.swing.Timer; + +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.ProgramPlugin; @@ -29,16 +34,6 @@ import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.Program; import ghidra.program.util.*; -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.ImageIcon; -import javax.swing.Timer; - -import resources.ResourceManager; - - /** * PropertyManagerPlugin */ @@ -56,15 +51,15 @@ import resources.ResourceManager; //@formatter:on public class PropertyManagerPlugin extends ProgramPlugin implements DomainObjectListener { - private static final ImageIcon propIcon = ResourceManager.loadImage("images/searchm_pink.gif"); + private static final Icon MARKER_ICON = new GIcon("icon.plugin.debug.propertymanager.marker"); final static String DISPLAY_ACTION_NAME = "Display Property Viewer"; final static String PROPERTY_MARKER_NAME = "Property Locations"; private PropertyManagerProvider propertyViewProvider; - private MarkerService markerService; - private MarkerSet searchMarks; - private Timer updateTimer; + private MarkerService markerService; + private MarkerSet searchMarks; + private Timer updateTimer; public PropertyManagerPlugin(PluginTool tool) { super(tool); @@ -72,30 +67,21 @@ public class PropertyManagerPlugin extends ProgramPlugin implements DomainObject propertyViewProvider = new PropertyManagerProvider(this); } - /** - * @see ghidra.framework.plugintool.Plugin#init() - */ @Override - protected void init() { + protected void init() { markerService = tool.getService(MarkerService.class); - - updateTimer = new Timer(500, new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (propertyViewProvider != null && propertyViewProvider.isVisible()) { - propertyViewProvider.refresh(); - } + updateTimer = new Timer(500, e -> { + if (propertyViewProvider != null && propertyViewProvider.isVisible()) { + propertyViewProvider.refresh(); } }); updateTimer.setRepeats(false); } - /* - * (non-Javadoc) - * @see ghidra.framework.model.DomainObjectListener#domainObjectChanged(ghidra.framework.model.DomainObjectChangedEvent) - */ - public void domainObjectChanged(DomainObjectChangedEvent ev) { + @Override + public void domainObjectChanged(DomainObjectChangedEvent ev) { if (propertyViewProvider == null || !propertyViewProvider.isVisible()) { return; } @@ -110,8 +96,7 @@ public class PropertyManagerPlugin extends ProgramPlugin implements DomainObject if (eventType == DomainObject.DO_OBJECT_RESTORED || eventType == ChangeManager.DOCR_MEMORY_BLOCK_MOVED || eventType == ChangeManager.DOCR_MEMORY_BLOCK_REMOVED || - eventType == ChangeManager.DOCR_CODE_UNIT_PROPERTY_ALL_REMOVED) - { + eventType == ChangeManager.DOCR_CODE_UNIT_PROPERTY_ALL_REMOVED) { affectedByChange = true; break; } @@ -124,7 +109,7 @@ public class PropertyManagerPlugin extends ProgramPlugin implements DomainObject break; } - CodeUnitPropertyChangeRecord pcr = (CodeUnitPropertyChangeRecord)record; + CodeUnitPropertyChangeRecord pcr = (CodeUnitPropertyChangeRecord) record; Address addr = pcr.getAddress(); if (addr != null) { if (currentSelection.contains(addr)) { @@ -145,16 +130,16 @@ public class PropertyManagerPlugin extends ProgramPlugin implements DomainObject if (affectedByChange) { updateTimer.restart(); } - } + } @Override - protected void programActivated(Program program) { + protected void programActivated(Program program) { program.addListener(this); propertyViewProvider.programActivated(program); } @Override - protected void programDeactivated(Program program) { + protected void programDeactivated(Program program) { disposeSearchMarks(program); if (program != null) { program.removeListener(this); @@ -162,57 +147,48 @@ public class PropertyManagerPlugin extends ProgramPlugin implements DomainObject propertyViewProvider.programDeactivated(); } - @Override - protected void selectionChanged(ProgramSelection sel) { - if (propertyViewProvider != null && propertyViewProvider.isVisible()) { - updateTimer.restart(); - } - } + @Override + protected void selectionChanged(ProgramSelection sel) { + if (propertyViewProvider != null && propertyViewProvider.isVisible()) { + updateTimer.restart(); + } + } - /** - * Initialize search marker manager - */ MarkerSet getSearchMarks() { if (searchMarks == null && currentProgram != null) { searchMarks = markerService.createPointMarker(PROPERTY_MARKER_NAME, - "Locations where properties are set", currentProgram, - MarkerService.PROPERTY_PRIORITY, true, true, false, Color.pink, propIcon); + "Locations where properties are set", currentProgram, + MarkerService.PROPERTY_PRIORITY, true, true, false, Palette.PINK, MARKER_ICON); } return searchMarks; } - /** - * Dispose search marker manager - */ void disposeSearchMarks() { - disposeSearchMarks( currentProgram ); + disposeSearchMarks(currentProgram); } - private void disposeSearchMarks( Program program ) { - if (searchMarks != null && program != null) { - markerService.removeMarker(searchMarks, program); - searchMarks = null; - } + private void disposeSearchMarks(Program program) { + if (searchMarks != null && program != null) { + markerService.removeMarker(searchMarks, program); + searchMarks = null; + } } void clearSearchMarks() { - if ( searchMarks != null ) { - searchMarks.clearAll(); - } + if (searchMarks != null) { + searchMarks.clearAll(); + } } - /** - * @see ghidra.framework.plugintool.Plugin#dispose() - */ @Override - public void dispose() { + public void dispose() { super.dispose(); - disposeSearchMarks(); + disposeSearchMarks(); - if (currentProgram != null) { - currentProgram.removeListener(this); - } + if (currentProgram != null) { + currentProgram.removeListener(this); + } if (propertyViewProvider != null) { propertyViewProvider.dispose(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerProvider.java index 8ace64dde9..221e5195da 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/debug/propertymanager/PropertyManagerProvider.java @@ -25,6 +25,7 @@ import javax.swing.event.TableModelListener; import docking.ActionContext; import docking.action.DockingAction; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.services.MarkerSet; import ghidra.framework.cmd.Command; import ghidra.framework.plugintool.ComponentProviderAdapter; @@ -32,15 +33,13 @@ import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*; import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTable; -import resources.ResourceManager; /** * PropertyManagerDialog */ public class PropertyManagerProvider extends ComponentProviderAdapter { - protected static final ImageIcon ICON = - ResourceManager.loadImage("images/document-properties.png"); + protected static final Icon ICON = new GIcon("icon.plugin.debug.propertymanager.provider"); protected static final String DELETE_PROPERTIES_ACTION_NAME = "Delete Properties"; @@ -140,7 +139,6 @@ public class PropertyManagerProvider extends ComponentProviderAdapter { ListSelectionModel tlsm = table.getSelectionModel(); selectionListener = e -> { - ListSelectionModel lsm = (ListSelectionModel) e.getSource(); refreshMarkers(table.getSelectedRow()); }; tlsm.addListSelectionListener(selectionListener); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java deleted file mode 100644 index b71ec19dda..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/LookAndFeelPlugin.java +++ /dev/null @@ -1,167 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.plugin.gui; - -import static ghidra.docking.util.DockingWindowsLookAndFeelUtils.*; - -import java.util.List; - -import docking.options.editor.StringWithChoicesEditor; -import docking.tool.ToolConstants; -import docking.widgets.OptionDialog; -import ghidra.app.CorePluginPackage; -import ghidra.app.plugin.PluginCategoryNames; -import ghidra.docking.util.DockingWindowsLookAndFeelUtils; -import ghidra.framework.main.ApplicationLevelOnlyPlugin; -import ghidra.framework.main.FrontEndTool; -import ghidra.framework.options.*; -import ghidra.framework.plugintool.*; -import ghidra.framework.plugintool.util.PluginStatus; -import ghidra.framework.preferences.Preferences; -import ghidra.util.*; - -//@formatter:off -@PluginInfo( - status = PluginStatus.RELEASED, - packageName = CorePluginPackage.NAME, - category = PluginCategoryNames.SUPPORT, - shortDescription = "Sets the GUI look and feel", - description = "Adds a Tool Option to allow the user to adjust the GUI look and feel settings. " + - "Ghidra may have to be restarted to see the effect. This plugin is available " + - "only in the Ghidra Project Window." -) -//@formatter:on -public class LookAndFeelPlugin extends Plugin implements ApplicationLevelOnlyPlugin, OptionsChangeListener { - - private String selectedLookAndFeel; - private boolean useInvertedColors; - public final static String LOOK_AND_FEEL_NAME = "Swing Look And Feel"; - private final static String USE_INVERTED_COLORS_NAME = "Use Inverted Colors"; - private final static String OPTIONS_TITLE = ToolConstants.TOOL_OPTIONS; - - private static boolean issuedLafNotification; - private static boolean issuedPreferredDarkThemeLafNotification; - - public LookAndFeelPlugin(PluginTool tool) { - super(tool); - - SystemUtilities.assertTrue(tool instanceof FrontEndTool, - "Plugin added to the wrong type of tool"); - initLookAndFeelOptions(); - } - - private void initLookAndFeelOptions() { - - ToolOptions opt = tool.getOptions(OPTIONS_TITLE); - - selectedLookAndFeel = getInstalledLookAndFeelName(); - List lookAndFeelNames = getLookAndFeelNames(); - opt.registerOption(LOOK_AND_FEEL_NAME, OptionType.STRING_TYPE, selectedLookAndFeel, - new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Look_And_Feel"), - "Set the look and feel for Ghidra. After you change the " + - "look and feel, you will have to restart Ghidra to see the effect.", - new StringWithChoicesEditor(lookAndFeelNames)); - selectedLookAndFeel = opt.getString(LOOK_AND_FEEL_NAME, selectedLookAndFeel); - - useInvertedColors = getUseInvertedColorsPreference(); - opt.registerOption(USE_INVERTED_COLORS_NAME, OptionType.BOOLEAN_TYPE, useInvertedColors, - new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Use_Inverted_Colors"), - "Indicates to invert all drawn colors. This provides the ability to create an " + - "effective 'Dark Theme' appearance. (Note: you may have to change your " + - "Look and Feel to achieve the best rendering.)\n\n" + - "PROTOTYPE - This feature is an example prototype " + - "and contains many known rendering issues that cause some widgets to be " + - "unreadable."); - useInvertedColors = opt.getBoolean(USE_INVERTED_COLORS_NAME, useInvertedColors); - - opt.addOptionsChangeListener(this); - } - - @Override - public void optionsChanged(ToolOptions options, String optionName, Object oldValue, - Object newValue) { - - if (optionName.equals(LOOK_AND_FEEL_NAME)) { - String newLookAndFeel = (String) newValue; - if (!newLookAndFeel.equals(selectedLookAndFeel)) { - issueLaFNotification(); - } - - saveLookAndFeel((String) newValue); - } - - if (optionName.equals(USE_INVERTED_COLORS_NAME)) { - boolean newUseInvertedColors = (Boolean) newValue; - if (newUseInvertedColors != useInvertedColors) { - - issueLaFNotification(); - } - - useInvertedColors = newUseInvertedColors; - Preferences.setProperty(USE_INVERTED_COLORS_KEY, Boolean.toString(useInvertedColors)); - Preferences.store(); - - if (useInvertedColors) { - issuePreferredDarkThemeLaFNotification(); - } - } - } - - private void saveLookAndFeel(String lookAndFeelName) { - selectedLookAndFeel = lookAndFeelName; - Preferences.setProperty(LAST_LOOK_AND_FEEL_KEY, selectedLookAndFeel); - Preferences.store(); - } - - private void issuePreferredDarkThemeLaFNotification() { - if (issuedPreferredDarkThemeLafNotification) { - return; - } - - issuedPreferredDarkThemeLafNotification = true; - - if (DockingWindowsLookAndFeelUtils.METAL_LOOK_AND_FEEL.equals(selectedLookAndFeel)) { - return; - } - - int choice = OptionDialog.showYesNoDialog(null, "Change Look and Feel?", "The '" + - USE_INVERTED_COLORS_NAME + "' setting works best with the " + - "'Metal' Look and Feel.\nWould you like to switch to that Look and Feel upon restart?"); - if (choice == OptionDialog.YES_OPTION) { - SystemUtilities.runSwingLater(() -> { - - saveLookAndFeel(DockingWindowsLookAndFeelUtils.METAL_LOOK_AND_FEEL); - }); - } - } - - private void issueLaFNotification() { - if (issuedLafNotification) { - return; - } - - issuedLafNotification = true; - Msg.showInfo(getClass(), null, "Look And Feel Updated", - "The new Look and Feel will take effect \nafter you exit and restart Ghidra."); - } - - @Override - public void dispose() { - ToolOptions opt = tool.getOptions(OPTIONS_TITLE); - opt.removeOptionsChangeListener(this); - super.dispose(); - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/WindowLocationPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/WindowLocationPlugin.java index 840de692f1..15ffcae96f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/WindowLocationPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/gui/WindowLocationPlugin.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,6 +26,7 @@ import javax.swing.*; import docking.ComponentProvider; import docking.Tool; +import generic.theme.GColor; import generic.util.WindowUtilities; import generic.util.image.ImageUtils; import ghidra.app.DeveloperPluginPackage; @@ -46,6 +47,18 @@ import ghidra.util.Swing; //@formatter:on public class WindowLocationPlugin extends Plugin { + private static final Color BG_COLOR = new GColor("color.bg.plugin.windowlocation"); + private static final Color BG_COLOR_BOUNDS_VIRTUAL = + new GColor("color.bg.plugin.windowlocation.bounds.virtual"); + private static final Color BG_COLOR_BOUNDS_VISIBLE = + new GColor("color.bg.plugin.windowlocation.bounds.visible"); + private static final Color BG_COLOR_SCREENS = + new GColor("color.bg.plugin.windowlocation.screens"); + private static final Color BG_COLOR_WINDOW_SELECTED = + new GColor("color.bg.plugin.windowlocation.window.selected"); + private static final Color FG_COLOR_WINDOW_TEXT = + new GColor("color.fg.plugin.windowlocation.window.text"); + static final String NAME = "Window Locations"; private WindowLocationProvider provider; @@ -75,12 +88,7 @@ public class WindowLocationPlugin extends Plugin { windowPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); Toolkit toolkit = Toolkit.getDefaultToolkit(); - AWTEventListener listener = new AWTEventListener() { - @Override - public void eventDispatched(AWTEvent event) { - windowPanel.repaint(); - } - }; + AWTEventListener listener = event -> windowPanel.repaint(); toolkit.addAWTEventListener(listener, AWTEvent.MOUSE_MOTION_EVENT_MASK); toolkit.addAWTEventListener(listener, AWTEvent.MOUSE_EVENT_MASK); } @@ -124,7 +132,7 @@ public class WindowLocationPlugin extends Plugin { Dimension size = getSize(); double panelWidth = size.getWidth(); double panelHeight = size.getHeight(); - setBackground(Color.BLACK); + setBackground(BG_COLOR); g.fillRect(0, 0, (int) panelWidth, (int) panelHeight); Graphics2D g2d = (Graphics2D) g; @@ -135,9 +143,9 @@ public class WindowLocationPlugin extends Plugin { clone.concatenate(newxform); g2d.setTransform(clone); - paintVirtualBounds(g2d, Color.RED); - paintVisibleBounds(g2d, Color.GREEN); - paintScreens(g2d, Color.ORANGE); + paintVirtualBounds(g2d, BG_COLOR_BOUNDS_VIRTUAL); + paintVisibleBounds(g2d, BG_COLOR_BOUNDS_VISIBLE); + paintScreens(g2d, BG_COLOR_SCREENS); paintWindows(g2d, newxform); } finally { @@ -183,7 +191,7 @@ public class WindowLocationPlugin extends Plugin { Font f = g2d.getFont(); Font biggerFont = f.deriveFont(40f); g2d.setFont(biggerFont); - g2d.setColor(Color.GRAY); + g2d.setColor(FG_COLOR_WINDOW_TEXT); Window[] windows = Window.getWindows(); @@ -380,8 +388,7 @@ public class WindowLocationPlugin extends Plugin { Color bg = g2d.getColor(); try { - Color withAlpha = new Color(0, 255, 0, 200); - g2d.setColor(withAlpha); + g2d.setColor(BG_COLOR_WINDOW_SELECTED); g2d.fill(b); } finally { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java index 91a46d506b..0f458bc7af 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScript.java @@ -26,6 +26,7 @@ import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooserMode; import generic.jar.ResourceFile; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.analysis.AnalysisWorker; import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.colorizer.ColorizingService; @@ -421,8 +422,8 @@ public abstract class GhidraScript extends FlatProgramAPI { null, "Keep Changes?", message, - "No (discard changes)", - "Yes (keep changes)", + "No (discard changes)", + "Yes (keep changes)", OptionDialog.QUESTION_MESSAGE); //@formatter:on @@ -3684,7 +3685,7 @@ public abstract class GhidraScript extends FlatProgramAPI { state.getTool(), currentProgram, addresses); TableComponentProvider

tableProvider = table.showTableWithMarkers(title + " " + model.getName(), "GhidraScript", model, - Color.GREEN, null, "Script Results", null); + Palette.GREEN, null, "Script Results", null); tableProvider.installRemoveItemsAction(); }; Swing.runLater(runnable); @@ -3701,7 +3702,7 @@ public abstract class GhidraScript extends FlatProgramAPI { AddressSetTableModel model = new AddressSetTableModel(title, state.getTool(), currentProgram, addresses, null); TableComponentProvider
tableProvider = table.showTableWithMarkers(title, - "GhidraScript", model, Color.GREEN, null, "Script Results", null); + "GhidraScript", model, Palette.GREEN, null, "Script Results", null); tableProvider.installRemoveItemsAction(); }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/ScriptInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/ScriptInfo.java index 49bca25d09..324a51bfb0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/script/ScriptInfo.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/ScriptInfo.java @@ -23,8 +23,7 @@ import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.ImageIcon; -import javax.swing.KeyStroke; +import javax.swing.*; import org.apache.commons.lang3.StringUtils; @@ -465,7 +464,7 @@ public class ScriptInfo { * @param scaled true if the icon should be scaled to 16x16. * @return the script tool bar icon */ - public ImageIcon getToolBarImage(boolean scaled) { + public Icon getToolBarImage(boolean scaled) { parseHeader(); if (toolbar == null) { return null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/tablechooser/TableChooserDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/tablechooser/TableChooserDialog.java index e8068526ab..f5e808fe7f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/tablechooser/TableChooserDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/tablechooser/TableChooserDialog.java @@ -29,6 +29,8 @@ import docking.DialogComponentProvider; import docking.action.DockingAction; import docking.widgets.table.*; import docking.widgets.table.threaded.ThreadedTableModel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.nav.Navigatable; import ghidra.app.nav.NavigatableRemovalListener; import ghidra.app.services.GoToService; @@ -418,7 +420,7 @@ public class TableChooserDialog extends DialogComponentProvider private class WrappingCellRenderer extends GhidraTableCellRenderer { - private Color pendingColor = new Color(192, 192, 192, 75); + private Color pendingColor = Palette.LIGHT_GRAY; private TableCellRenderer delegate; @Override @@ -443,7 +445,7 @@ public class TableChooserDialog extends DialogComponentProvider if (sharedPending.contains(ro)) { renderer.setBackground(pendingColor); renderer.setForeground(data.getTable().getSelectionForeground()); - renderer.setForeground(Color.BLACK); + renderer.setForeground(Colors.FOREGROUND); } return renderer; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddressSetEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddressSetEditorPanel.java index 52b0d42825..3679818faf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddressSetEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/AddressSetEditorPanel.java @@ -16,8 +16,6 @@ package ghidra.app.util; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.HashSet; import java.util.List; @@ -25,13 +23,14 @@ import javax.swing.*; import javax.swing.event.*; import docking.widgets.label.GDLabel; +import generic.theme.GIcon; import ghidra.program.model.address.*; import ghidra.util.layout.MiddleLayout; -import resources.ResourceManager; +import resources.Icons; public class AddressSetEditorPanel extends JPanel { - private static Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static Icon SUBTRACT_ICON = ResourceManager.loadImage("images/list-remove.png"); + private static Icon ADD_ICON = Icons.ADD_ICON; + private static Icon SUBTRACT_ICON = new GIcon("icon.subtract"); private AddressInput minAddressField; private AddressInput maxAddressField; @@ -68,12 +67,7 @@ public class AddressSetEditorPanel extends JPanel { minAddressPanel.add(minLabel, BorderLayout.WEST); minAddressField = new AddressInput(); minAddressField.setAddressFactory(addressFactory); - ChangeListener listener = new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - validateAddRemoveButton(); - } - }; + ChangeListener listener = e -> validateAddRemoveButton(); minAddressField.addChangeListener(listener); minAddressPanel.add(minAddressField, BorderLayout.CENTER); @@ -88,20 +82,10 @@ public class AddressSetEditorPanel extends JPanel { maxAddressPanel.add(maxAddressField, BorderLayout.CENTER); maxAddressPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); addRangeButton = new JButton(ADD_ICON); - addRangeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - addRange(); - } - }); + addRangeButton.addActionListener(e -> addRange()); addRangeButton.setToolTipText("Add the range to the set of included addresses"); subtractRangeButton = new JButton(SUBTRACT_ICON); - subtractRangeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - subtractRange(); - } - }); + subtractRangeButton.addActionListener(e -> subtractRange()); subtractRangeButton.setToolTipText("Remove the range from the set of included addresses"); JPanel addressPanel = new JPanel(); @@ -133,12 +117,7 @@ public class AddressSetEditorPanel extends JPanel { bottomButtons.setLayout(new MiddleLayout()); removeRangeButton = new JButton("Remove Selected Range(s)"); - removeRangeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - removeRange(); - } - }); + removeRangeButton.addActionListener(e -> removeRange()); bottomButtons.add(removeRangeButton); return bottomButtons; @@ -149,12 +128,7 @@ public class AddressSetEditorPanel extends JPanel { listModel = new AddressSetListModel(addressSet.toList()); list = new JList<>(listModel); list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - list.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - validateRemoveButton(); - } - }); + list.getSelectionModel().addListSelectionListener(e -> validateRemoveButton()); JScrollPane scrollPane = new JScrollPane(list); panel.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(10, 10, 10, 10), "Included Address Ranges:")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/BlockPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/BlockPanel.java deleted file mode 100644 index 964e5660e9..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/BlockPanel.java +++ /dev/null @@ -1,144 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util; - -import java.awt.*; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; - -import javax.swing.*; - -import docking.widgets.label.GDLabel; -import ghidra.app.util.viewer.util.AddressPixelMap; -import ghidra.program.model.mem.MemoryBlock; - -public class BlockPanel extends JPanel implements ComponentListener { - private static final long serialVersionUID = 1L; - private static final int SPACING = 5; - private static final Font FONT = new Font("SansSerif", Font.PLAIN, 10); - private AddressPixelMap map; - private FontMetrics metrics; - - public BlockPanel() { - super(); - setBackground(Color.WHITE); - addComponentListener(this); - metrics = getFontMetrics(FONT); - setPreferredSize( - new Dimension(100, SPACING + metrics.getMaxAscent() + metrics.getMaxDescent())); - } - - @Override - public void paintComponent(Graphics g) { - - g.setColor(Color.BLACK); - g.setFont(FONT); - int height = getHeight(); - - MemoryBlock[] blocks = map.getBlocks(); - if (blocks == null) { - return; - } - - for (int i = 0; i < blocks.length; i++) { - Rectangle rect = map.getBlockPosition(blocks[i]); - g.drawLine(rect.x, 0, rect.x, height - 1); - } - g.drawLine(getWidth() - 1, 0, getWidth() - 1, height - 1); - - g.drawLine(0, height - 1, getWidth() - 1, height - 1); - } - - @Override - protected void paintChildren(Graphics g) { - // - // clear the background; paint our labels; paint our divider lines - // - Color oldColor = g.getColor(); - g.setColor(getBackground()); - Rectangle clip = g.getClipBounds(); - g.fillRect(clip.x, clip.y, clip.width, clip.height); - g.setColor(oldColor); - super.paintChildren(g); - paintComponent(g); - } - - public void setMemoryBlockMap(AddressPixelMap map) { - this.map = map; - repaint(); - } - - /** Creates labels for the block names */ - private void buildLabels() { - removeAll(); - setLayout(null); - - Container parent = getParent(); - - MemoryBlock[] blocks = map.getBlocks(); - if (blocks == null) { - return; - } - - for (MemoryBlock block : blocks) { - JLabel label = new GDLabel(block.getName()); - label.setFont(FONT); - label.setHorizontalAlignment(SwingConstants.CENTER); - label.setToolTipText(block.getName()); - - Rectangle rect = map.getBlockPosition(block); - int height = getHeight(); - int width = metrics.stringWidth(block.getName()); - if (rect.width < width) { - label.setText("..."); - } - int labelWidth = Math.min(rect.width, width); - labelWidth = Math.max(labelWidth, 3); - int labelHeight = height - 1; - int x = rect.x + (rect.width - 1) / 2 - labelWidth / 2; - int y = 0; - - label.setBounds(x, y, labelWidth, labelHeight); - add(label); - } - invalidate(); - if (parent != null) { - parent.validate(); - } - } - - public void refresh() { - buildLabels(); - repaint(); - } - - @Override - public void componentResized(ComponentEvent e) { - refresh(); - } - - @Override - public void componentHidden(ComponentEvent e) { - } - - @Override - public void componentMoved(ComponentEvent e) { - } - - @Override - public void componentShown(ComponentEvent e) { - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/PluginConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/PluginConstants.java index 98fbd60360..21d3edbe99 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/PluginConstants.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/PluginConstants.java @@ -15,7 +15,7 @@ */ package ghidra.app.util; -import java.awt.Color; +import generic.theme.GColor; /** * Miscellaneous defined constants @@ -75,17 +75,10 @@ public interface PluginConstants { * Name of the Options object for Search. */ public static final String SEARCH_OPTION_NAME = "Search"; - /** - * Option name for highlight color - */ - public static final String SEARCH_HIGHLIGHT_COLOR_NAME = " Highlight Color"; - /** * Option name for highlight color used when something to highlight is at the current * address. */ - public static final String SEARCH_HIGHLIGHT_CURRENT_COLOR_NAME = - "Highlight Color for Current Match"; /** * Option name for whether to highlight search results. */ @@ -94,11 +87,16 @@ public interface PluginConstants { /** * Color for highlighting for searches. */ - public static final Color SEARCH_HIGHLIGHT_COLOR = new Color(255, 255, 200); + public static final String SEARCH_HIGHLIGHT_COLOR_OPTION_NAME = " Highlight Color"; + public static final GColor SEARCH_HIGHLIGHT_COLOR = new GColor("color.bg.search.highlight"); + /** * Default highlight color used when something to highlight is at the current * address. */ - public static final Color SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR = Color.YELLOW; + public static final String SEARCH_HIGHLIGHT_CURRENT_COLOR_OPTION_NAME = + "Highlight Color for Current Match"; + public static final GColor SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR = + new GColor("color.bg.search.current.line.highlight"); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/SymbolInspector.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/SymbolInspector.java index edcdcd601c..233c7d4dff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/SymbolInspector.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/SymbolInspector.java @@ -20,6 +20,7 @@ import java.awt.Component; import java.util.HashMap; import java.util.Map; +import generic.theme.GThemeDefaults.Colors; import ghidra.GhidraOptions; import ghidra.app.util.viewer.options.OptionsGui; import ghidra.app.util.viewer.options.ScreenElement; @@ -431,7 +432,7 @@ public class SymbolInspector implements OptionsChangeListener { private Color getColor(ScreenElement se) { if (se == null) { - return Color.BLACK; + return Colors.BACKGROUND; } String optionName = se.getColorOptionName(); Color color = (Color) cache.get(optionName); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java index 721cbb8624..41b30272d3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/ToolTipUtils.java @@ -23,6 +23,8 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.html.*; import ghidra.app.util.viewer.options.OptionsGui; import ghidra.program.model.address.Address; @@ -42,7 +44,8 @@ import ghidra.util.StringUtilities; */ public class ToolTipUtils { - private static final Color PARAM_NAME_COLOR = new Color(155, 50, 155); + private static final Color FG_FUNCTION_NAME = new GColor("color.fg.function.name"); + private static final Color PARAM_NAME_COLOR = new GColor("color.fg.function.params"); private static final Color PARAM_CUSTOM_STORAGE_COLOR = OptionsGui.PARAMETER_CUSTOM.getDefaultColor(); private static final Color PARAM_DYNAMIC_STORAGE_COLOR = @@ -162,7 +165,7 @@ public class ToolTipUtils { dt = DataType.DEFAULT; } - buf.append(colorString(Color.BLACK, friendlyEncodeHTML(dt.getName()))); + buf.append(colorString(Colors.FOREGROUND, friendlyEncodeHTML(dt.getName()))); buf.append(HTML_SPACE); buf.append(friendlyEncodeHTML(s.getName())); @@ -256,7 +259,7 @@ public class ToolTipUtils { StringBuilder buf = new StringBuilder(); buf.append("
"); // indent buf.append(""); } - private void writeResultCount(PrintWriter w, int count, String color) { + private void writeResultCount(PrintWriter w, int count, Color color) { if (count == 0) { - w.print("-"); + w.print("-"); } else { w.print("" + Integer.toString(count) + ""); @@ -417,25 +419,26 @@ public class PCodeTestCombinedTestResults { // analyzed program has relocation or disassembly errors w.print(" - - +
Tool - Options
OptionOptionDescriptionDescription
 "); - buf.append(colorString(Color.BLACK, friendlyEncodeHTML(type))); + buf.append(colorString(Colors.FOREGROUND, friendlyEncodeHTML(type))); buf.append(""); boolean usesCustomStorage = false; @@ -301,7 +304,7 @@ public class ToolTipUtils { } String functionName = StringUtilities.trimMiddle(function.getName(), LINE_LENGTH); - buffy.append(colorString(Color.BLUE, friendlyEncodeHTML(functionName))); + buffy.append(colorString(FG_FUNCTION_NAME, friendlyEncodeHTML(functionName))); buffy.append(HTML_SPACE).append("("); buildParameterPreview(function, buffy); @@ -399,7 +402,7 @@ public class ToolTipUtils { } StringBuilder pb = new StringBuilder(); - pb.append(colorString(Color.BLACK, friendlyEncodeHTML(type))); + pb.append(colorString(Colors.FOREGROUND, friendlyEncodeHTML(type))); pb.append(HTML_SPACE); pb.append(colorString(PARAM_NAME_COLOR, friendlyEncodeHTML(name))); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/FixedBitSizeValueField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/FixedBitSizeValueField.java index a3ee981ea1..7381c1b29f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/FixedBitSizeValueField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/FixedBitSizeValueField.java @@ -15,12 +15,11 @@ */ package ghidra.app.util.bean; - import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigInteger; import java.util.ArrayList; +import java.util.List; import javax.swing.*; import javax.swing.event.ChangeEvent; @@ -28,14 +27,14 @@ import javax.swing.event.ChangeListener; import javax.swing.text.*; import docking.widgets.SmallBorderButton; -import resources.ResourceManager; +import generic.theme.GIcon; +import generic.theme.Gui; - -/** - * - */ public class FixedBitSizeValueField extends JPanel { - private static final ImageIcon DROP_DOWN_MENU_ICON = ResourceManager.loadImage("images/menu16.gif"); + + private static final Icon DROP_DOWN_MENU_ICON = + new GIcon("icon.base.util.fixed.bit.size.field"); + protected JTextField valueField; protected JButton menuButton; private PlainDocument doc; @@ -49,32 +48,27 @@ public class FixedBitSizeValueField extends JPanel { private BigInteger maxValue; private BigInteger minValue; protected JPopupMenu popupMenu; - protected java.util.List menuItems = new ArrayList<>(); - protected java.util.List listeners = new ArrayList<>(); + protected List menuItems = new ArrayList<>(); + protected List listeners = new ArrayList<>(); public FixedBitSizeValueField(int bitSize, boolean includeFormatButton, boolean leftJustify) { setLayout(new BorderLayout()); valueField = new JTextField(); if (includeFormatButton) { JPanel buttonPanel = new JPanel(new BorderLayout()); - menuButton = new SmallBorderButton(" hex",DROP_DOWN_MENU_ICON); + menuButton = new SmallBorderButton(" hex", DROP_DOWN_MENU_ICON); menuButton.setHorizontalTextPosition(SwingConstants.LEADING); - buttonPanel.setBorder(BorderFactory.createEmptyBorder(0,2,0,3)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 3)); buttonPanel.add(menuButton, BorderLayout.EAST); add(buttonPanel, BorderLayout.EAST); menuButton.setFocusable(false); - menuButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - showPopup(); - } - }); + menuButton.addActionListener(e -> showPopup()); } add(valueField, BorderLayout.CENTER); - Font f2 = new Font("monospaced", Font.PLAIN, 14); + Font f2 = Gui.getFont(Font.MONOSPACED); valueField.setFont(f2); - valueField.setMargin(new Insets(0,2,0,2)); + valueField.setMargin(new Insets(0, 2, 0, 2)); createPopup(); @@ -92,8 +86,8 @@ public class FixedBitSizeValueField extends JPanel { public void setBitSize(int bitSize) { BigInteger b = BigInteger.valueOf(2); - maxSignedValue = b.pow(bitSize-1).subtract(BigInteger.ONE); - minSignedValue = b.pow(bitSize-1).negate(); + maxSignedValue = b.pow(bitSize - 1).subtract(BigInteger.ONE); + minSignedValue = b.pow(bitSize - 1).negate(); maxUnsignedValue = b.pow(bitSize).subtract(BigInteger.ONE); maxValue = signed ? maxSignedValue : maxUnsignedValue; @@ -104,6 +98,7 @@ public class FixedBitSizeValueField extends JPanel { public void addChangeListener(ChangeListener listener) { listeners.add(listener); } + public void removeChangeListener(ChangeListener listener) { listeners.remove(listener); } @@ -128,18 +123,16 @@ public class FixedBitSizeValueField extends JPanel { } return true; } + public void setMinMax(BigInteger min, BigInteger max) { minValue = min; maxValue = max; } protected void createPopup() { - ActionListener actionListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JCheckBoxMenuItem item = (JCheckBoxMenuItem)e.getSource(); - menuActivated(item); - } + ActionListener actionListener = e -> { + JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getSource(); + menuActivated(item); }; popupMenu = new JPopupMenu(); @@ -154,16 +147,18 @@ public class FixedBitSizeValueField extends JPanel { menuItem.addActionListener(actionListener); } } + private void showPopup() { Dimension d = getSize(); - popupMenu.show(this, d.width, d.height ); + popupMenu.show(this, d.width, d.height); } + protected void updatePopup() { - for (JCheckBoxMenuItem menuItem : menuItems) { + for (JCheckBoxMenuItem menuItem : menuItems) { menuItem.setSelected(false); } int selectedMenuItem = -1; - switch(radix) { + switch (radix) { case 2: selectedMenuItem = signed ? -1 : 5; break; @@ -181,10 +176,11 @@ public class FixedBitSizeValueField extends JPanel { menuItems.get(selectedMenuItem).setSelected(true); } } + protected void menuActivated(JCheckBoxMenuItem item) { int index = menuItems.indexOf(item); - switch(index) { + switch (index) { case 0: setFormat(16, false); break; @@ -205,6 +201,7 @@ public class FixedBitSizeValueField extends JPanel { break; } } + public void setFormat(int radix, boolean signed) { BigInteger curValue = getValue(valueField.getText()); @@ -243,7 +240,7 @@ public class FixedBitSizeValueField extends JPanel { return; } String buttonText = ""; - switch(radix) { + switch (radix) { case 16: buttonText = " hex"; break; @@ -264,6 +261,7 @@ public class FixedBitSizeValueField extends JPanel { public boolean setValue(BigInteger value) { return setValue(value, false); } + public boolean setValue(BigInteger value, boolean pad) { setText(""); if (value == null) { @@ -282,6 +280,7 @@ public class FixedBitSizeValueField extends JPanel { setText(valueString); return true; } + private String pad(String valueString) { if (signed) { return valueString; @@ -290,7 +289,7 @@ public class FixedBitSizeValueField extends JPanel { if (maxValueString.length() > valueString.length()) { StringBuffer buf = new StringBuffer(); int n = maxValueString.length() - valueString.length(); - for(int i=0;i 0) { if (eqRowObject.getEntryName().contains(EquateManager.ERROR_TAG)) { - c.setForeground(isSelected ? Color.WHITE : Color.RED); + c.setForeground(isSelected ? this.SELECTED_CELL_COLOR : this.BAD_EQUATE_COLOR); } else { Equate e = eqRowObject.getEquate(); if (e != null && !e.isEnumBased()) { - c.setForeground(isSelected ? Color.WHITE : Color.BLUE.brighter()); + c.setForeground(isSelected ? this.SELECTED_CELL_COLOR : this.EQUATE_COLOR); } } } else { - c.setForeground(isSelected ? Color.WHITE : Color.GRAY.darker()); + c.setForeground(isSelected ? this.SELECTED_CELL_COLOR : this.SUGGESTION_COLOR); } return c; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java index 9722950225..e175231fbc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/C/CParserUtils.java @@ -19,6 +19,8 @@ import java.io.*; import java.util.Arrays; import java.util.Iterator; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.framework.plugintool.ServiceProvider; @@ -652,16 +654,16 @@ public class CParserUtils { StringBuffer successFailureBuffer = new StringBuffer(); successFailureBuffer.append("
"); if (errorIndex == 0) { - successFailureBuffer.append(""); + successFailureBuffer.append(""); successFailureBuffer.append(HTMLUtilities.friendlyEncodeHTML(functionString)); successFailureBuffer.append(""); } else { - successFailureBuffer.append(""); + successFailureBuffer.append(""); successFailureBuffer.append( HTMLUtilities.friendlyEncodeHTML(functionString.substring(0, errorIndex))); successFailureBuffer.append(""); - successFailureBuffer.append(""); + successFailureBuffer.append(""); successFailureBuffer.append( HTMLUtilities.friendlyEncodeHTML(functionString.substring(errorIndex))); successFailureBuffer.append(""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java index e17d76ca5c..a07c0c5824 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/ProgramTextWriter.java @@ -18,6 +18,7 @@ package ghidra.app.util.exporter; import java.io.*; import java.util.ArrayList; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.util.DisplayableEol; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.address.Address; @@ -372,7 +373,7 @@ class ProgramTextWriter { buffy = new StringBuilder(); if (options.isHTML()) { - writer.print(""); + writer.print(""); } processAddress(bytesRemovedRangeStart, null); buffy.append(" -> "); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/CompositeDataTypeHTMLRepresentation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/CompositeDataTypeHTMLRepresentation.java index 745b7fded1..fe7c7aafd8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/CompositeDataTypeHTMLRepresentation.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/CompositeDataTypeHTMLRepresentation.java @@ -20,6 +20,8 @@ import static ghidra.util.HTMLUtilities.*; import java.awt.Color; import java.util.*; +import generic.theme.GThemeDefaults.Colors.Messages; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.ToolTipUtils; import ghidra.app.util.html.diff.*; import ghidra.program.model.data.*; @@ -162,7 +164,7 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat Iterator warnings = warningLines.iterator(); for (; warnings.hasNext();) { String warning = warnings.next(); - String warningLine = wrapStringInColor(warning, Color.RED); + String warningLine = wrapStringInColor(warning, Messages.ERROR); //@formatter:off append(fullHtml, truncatedHtml, lineCount++, warningLine, BR); @@ -226,7 +228,7 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat if (!(line instanceof DataTypeLine)) { append(fullHtml, truncatedHtml, lineCount++, TR_OPEN, - "
", TAB, TAB, + "", TAB, TAB, line.getText(), "", TD_CLOSE, TR_CLOSE); continue; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java index 2122efd995..4ea978ec97 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/TypeDefDataTypeHTMLRepresentation.java @@ -15,11 +15,11 @@ */ package ghidra.app.util.html; -import java.awt.Color; import java.util.*; import org.apache.commons.lang3.StringUtils; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.util.ToolTipUtils; import ghidra.app.util.html.diff.DataTypeDiff; import ghidra.app.util.html.diff.DataTypeDiffBuilder; @@ -144,7 +144,7 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio protected List buildHeaderText(boolean trim) { DataType baseDataType = typeDef.getDataType(); - + List lines = new ArrayList<>(); lines.add(new TextLine(getDataTypeNameHTML(typeDef, trim))); @@ -181,7 +181,7 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio addDataTypeLengthAndAlignment(typeDef, new StringBuilder()).toString(); lines.add(new TextLine(INDENT_OPEN + lengthAndAlignmentStr + INDENT_CLOSE)); } - + baseDataType = getBasePointerArrayDataType(baseDataType); boolean firstBaseTypedef = true; while (baseDataType instanceof TypeDef) { @@ -220,7 +220,7 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio Iterator warnings = warningLines.iterator(); for (; warnings.hasNext();) { String warning = warnings.next(); - String warningLine = wrapStringInColor(warning, Color.RED); + String warningLine = wrapStringInColor(warning, Messages.ERROR); buffy.append(warningLine).append(BR); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/ValidatableLine.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/ValidatableLine.java index 2c0c2031aa..ece4a86660 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/ValidatableLine.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/html/ValidatableLine.java @@ -17,6 +17,8 @@ package ghidra.app.util.html; import java.awt.Color; +import generic.theme.GThemeDefaults.Colors.Messages; + /** * A loose concept that represents a line of text, potentially with multiple parts, that can * be validated against other instances and can change the color of the text. @@ -26,7 +28,7 @@ import java.awt.Color; */ public interface ValidatableLine { - public static final Color INVALID_COLOR = Color.RED; + public static final Color INVALID_COLOR = Messages.ERROR; public void updateColor(ValidatableLine otherLine, Color invalidColor); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/query/TableService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/query/TableService.java index bb604c7576..0d5fef34cf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/query/TableService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/query/TableService.java @@ -15,6 +15,10 @@ */ package ghidra.app.util.query; +import java.awt.Color; + +import javax.swing.Icon; + import ghidra.app.nav.Navigatable; import ghidra.app.plugin.core.table.TableComponentProvider; import ghidra.app.plugin.core.table.TableServicePlugin; @@ -24,10 +28,6 @@ import ghidra.framework.plugintool.ServiceInfo; import ghidra.program.model.listing.Program; import ghidra.util.table.GhidraProgramTableModel; -import java.awt.Color; - -import javax.swing.ImageIcon; - /** * Service to show a component that has a JTable given a table model * that builds up its data dynamically (a ThreadedTableModel). @@ -65,7 +65,7 @@ public interface TableService { */ public TableComponentProvider showTableWithMarkers(String componentProviderTitle, String tableTypeName, GhidraProgramTableModel model, Color markerColor, - ImageIcon markerIcon, String windowSubMenu, Navigatable navigatable); + Icon markerIcon, String windowSubMenu, Navigatable navigatable); public TableChooserDialog createTableChooserDialog(TableChooserExecutor executor, Program program, String name, Navigatable navigatable); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AbstractVariableFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AbstractVariableFieldFactory.java index 71bd42d72e..93b36675f9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AbstractVariableFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AbstractVariableFieldFactory.java @@ -24,7 +24,6 @@ import ghidra.app.util.viewer.options.ScreenElement; import ghidra.framework.options.Options; import ghidra.program.model.listing.Parameter; import ghidra.program.model.listing.Variable; -import ghidra.util.SystemUtilities; public abstract class AbstractVariableFieldFactory extends FieldFactory { @@ -110,7 +109,7 @@ public abstract class AbstractVariableFieldFactory extends FieldFactory { Object newValue) { if (optionName.equals(FONT_OPTION_NAME)) { - baseFont = SystemUtilities.adjustForFontSizeOverride((Font) newValue); + baseFont = (Font) newValue; setMetrics(baseFont, parameterFieldOptions[CUSTOM_PARAM_INDEX]); setMetrics(baseFont, parameterFieldOptions[DYNAMIC_PARAM_INDEX]); } @@ -133,7 +132,7 @@ public abstract class AbstractVariableFieldFactory extends FieldFactory { private void setMetrics(Font newFont, ParameterFieldOptions paramFieldOptions) { paramFieldOptions.defaultMetrics = Toolkit.getDefaultToolkit().getFontMetrics(newFont); for (int i = 0; i < paramFieldOptions.fontMetrics.length; i++) { - Font font = new Font(newFont.getFamily(), i, newFont.getSize()); + Font font = newFont.deriveFont(i); // i is looping over the 4 font styles PLAIN, BOLD, ITALIC, and BOLDITALIC paramFieldOptions.fontMetrics[i] = Toolkit.getDefaultToolkit().getFontMetrics(font); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressAnnotatedStringHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressAnnotatedStringHandler.java index 94bb1e3110..38623b1fd7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressAnnotatedStringHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressAnnotatedStringHandler.java @@ -15,6 +15,9 @@ */ package ghidra.app.util.viewer.field; +import docking.widgets.fieldpanel.field.AttributedString; +import generic.theme.GThemeDefaults.Colors.Messages; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.nav.Navigatable; import ghidra.app.services.GoToService; import ghidra.framework.plugintool.ServiceProvider; @@ -22,18 +25,14 @@ import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.util.Msg; -import java.awt.Color; - -import docking.widgets.fieldpanel.field.AttributedString; - /** * An annotated string handler that allows handles annotations that begin with * {@link #SUPPORTED_ANNOTATIONS}. This class expects one string following the annotation * text that is an address string and will display that string as its display text. */ public class AddressAnnotatedStringHandler implements AnnotatedStringHandler { - private static final String INVALID_SYMBOL_TEXT = "@address annotation must have an address" - + "string"; + private static final String INVALID_SYMBOL_TEXT = + "@address annotation must have an address" + "string"; private static final String[] SUPPORTED_ANNOTATIONS = { "address", "addr" }; @Override @@ -51,7 +50,7 @@ public class AddressAnnotatedStringHandler implements AnnotatedStringHandler { Address address = program.getAddressFactory().getAddress(text[1]); if (address == null) { - return new AttributedString("No address: " + text[1], Color.RED, + return new AttributedString("No address: " + text[1], Messages.ERROR, prototypeString.getFontMetrics(0), false, null); } @@ -69,15 +68,17 @@ public class AddressAnnotatedStringHandler implements AnnotatedStringHandler { prototypeString.getFontMetrics(0), true, prototypeString.getColor(0)); } - private AttributedString createUndecoratedString(AttributedString prototypeString, String[] text) { + private AttributedString createUndecoratedString(AttributedString prototypeString, + String[] text) { StringBuilder buffer = new StringBuilder(); for (String string : text) { buffer.append(string).append(" "); } - return new AttributedString(buffer.toString(), Color.LIGHT_GRAY, + return new AttributedString(buffer.toString(), Palette.LIGHT_GRAY, prototypeString.getFontMetrics(0)); } + @Override public String[] getSupportedAnnotations() { return SUPPORTED_ANNOTATIONS; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java index e6d2a4defb..abca961115 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AddressFieldFactory.java @@ -21,6 +21,7 @@ import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -39,7 +40,7 @@ import ghidra.util.exception.AssertException; */ public class AddressFieldFactory extends FieldFactory { public static final String FIELD_NAME = "Address"; - public static final Color DEFAULT_COLOR = Color.BLACK; + public static final Color DEFAULT_COLOR = Colors.FOREGROUND; private final static String GROUP_TITLE = "Address Field"; public final static String DISPLAY_BLOCK_NAME = GROUP_TITLE + Options.DELIMITER + "Display Block Name"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java index 8463984fd7..fb28a24596 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -35,7 +36,7 @@ import ghidra.program.util.ProgramLocation; */ public class AssignedVariableFieldFactory extends FieldFactory { public static final String FIELD_NAME = "Var Assign"; - public static final Color DEFAULT_COLOR = new Color(128, 0, 128); + public static final Color DEFAULT_COLOR = Palette.PURPLE; /** * Default constructor. @@ -59,15 +60,9 @@ public class AssignedVariableFieldFactory extends FieldFactory { @Override public void fieldOptionsChanged(Options options, String optionName, Object oldValue, Object newValue) { - + // stub } -// private static String getOffsetString(int offset) { -// String offString = -// (offset >= 0 ? Integer.toHexString(offset) : "-" + Integer.toHexString(-offset)); -// return offString; -// } - /** * Returns the FactoryField for the given object at index index. * @param varWidth the amount of variable width spacing for any fields diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java index 6caf5b9ea2..0bcab118fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java @@ -27,6 +27,7 @@ import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.RowColLocation; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -46,8 +47,8 @@ import ghidra.util.HelpLocation; public class BytesFieldFactory extends FieldFactory { private static final int CHARS_IN_BYTE = 2; public static final String FIELD_NAME = "Bytes"; - public static final Color DEFAULT_COLOR = Color.BLUE; - public static final Color ALIGNMENT_BYTES_COLOR = Color.gray; + public static final Color DEFAULT_COLOR = Palette.BLUE; + public static final Color ALIGNMENT_BYTES_COLOR = Palette.GRAY; public final static String GROUP_TITLE = "Bytes Field"; public final static String MAX_DISPLAY_LINES_MSG = GROUP_TITLE + Options.DELIMITER + "Maximum Lines To Display"; @@ -79,7 +80,7 @@ public class BytesFieldFactory extends FieldFactory { /** * Constructor * @param model the model that the field belongs to. - * @param hsProvider the HightLightStringProvider. + * @param hlProvider the HightLightStringProvider. * @param displayOptions the Options for display properties. * @param fieldOptions the Options for field specific properties. */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentUtils.java index 2a06ac439d..56d3b81b3a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/CommentUtils.java @@ -26,6 +26,8 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import docking.widgets.fieldpanel.field.*; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.Gui; import ghidra.program.model.listing.Program; import ghidra.util.StringUtilities; import ghidra.util.WordLocation; @@ -93,10 +95,10 @@ public class CommentUtils { } private static AttributedString createPrototype() { - Font dummyFont = new Font("monospaced", Font.PLAIN, 12); + Font dummyFont = Gui.getFont("font.monospaced"); @SuppressWarnings("deprecation") FontMetrics fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(dummyFont); - return new AttributedString("", Color.BLACK, fontMetrics); + return new AttributedString("", Colors.FOREGROUND, fontMetrics); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java index 5df7cf0162..65113d6208 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java @@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.*; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -62,7 +63,7 @@ public class EolCommentFieldFactory extends FieldFactory { GROUP_TITLE + Options.DELIMITER + "Show Function Reference Automatic Comments"; public final static String ENABLE_PREPEND_REF_ADDRESS_MSG = GROUP_TITLE + Options.DELIMITER + "Prepend the Address to Each Referenced Comment"; - public static final Color DEFAULT_COLOR = Color.BLUE; + public static final Color DEFAULT_COLOR = Palette.BLUE; private boolean isWordWrap; private int maxDisplayLines; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldFactory.java index e43eb264db..003ff793f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldFactory.java @@ -19,6 +19,9 @@ import java.awt.*; import java.math.BigInteger; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; +import generic.theme.Gui; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -39,14 +42,14 @@ import ghidra.util.classfinder.ExtensionPoint; */ public abstract class FieldFactory implements ExtensionPoint { public static final String FONT_OPTION_NAME = "BASE FONT"; - public static final Font DEFAULT_FIELD_FONT = new Font("monospaced", Font.PLAIN, 12); + public static final String BASE_LISTING_FONT_ID = "font.listing.base"; protected FieldFormatModel model; protected String name; protected int startX; protected int width; protected Color color; - protected Color underlineColor = Color.BLUE; + protected Color underlineColor = Palette.BLUE; private FontMetrics defaultMetrics; private FontMetrics[] fontMetrics = new FontMetrics[4]; protected Font baseFont; @@ -84,12 +87,11 @@ public abstract class FieldFactory implements ExtensionPoint { } protected void initDisplayOptions() { - baseFont = SystemUtilities.adjustForFontSizeOverride( - displayOptions.getFont(FONT_OPTION_NAME, DEFAULT_FIELD_FONT)); + baseFont = Gui.getFont(BASE_LISTING_FONT_ID); // For most fields (defined in optionsGui) these will be set. But "ad hoc" fields won't, // so register something. A second registration won't change the original - displayOptions.registerOption(colorOptionName, Color.BLACK, null, + displayOptions.registerThemeColorBinding(colorOptionName, Colors.FOREGROUND.getId(), null, "Sets the " + colorOptionName); displayOptions.registerOption(styleOptionName, -1, null, "Sets the " + style); @@ -197,7 +199,7 @@ public abstract class FieldFactory implements ExtensionPoint { * @return the color. */ public Color getDefaultColor() { - return Color.BLACK; + return Colors.FOREGROUND; } /** @@ -349,7 +351,7 @@ public abstract class FieldFactory implements ExtensionPoint { private void setMetrics(Font newFont) { defaultMetrics = Toolkit.getDefaultToolkit().getFontMetrics(newFont); for (int i = 0; i < fontMetrics.length; i++) { - Font font = new Font(newFont.getFamily(), i, newFont.getSize()); + Font font = newFont.deriveFont(i); // i is looping over the 4 font styles PLAIN, BOLD, ITALIC, and BOLDITALIC fontMetrics[i] = Toolkit.getDefaultToolkit().getFontMetrics(font); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionPurgeFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionPurgeFieldFactory.java index ec0df618c1..18c8e77051 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionPurgeFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionPurgeFieldFactory.java @@ -15,11 +15,11 @@ */ package ghidra.app.util.viewer.field; -import java.awt.Color; import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -47,8 +47,8 @@ public class FunctionPurgeFieldFactory extends FieldFactory { @Override public FieldFactory newInstance(FieldFormatModel newModel, HighlightProvider newHlProvider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new FunctionPurgeFieldFactory(newModel, newHlProvider, displayOptions, fieldOptions); + ToolOptions toolOptions, ToolOptions fieldOptions) { + return new FunctionPurgeFieldFactory(newModel, newHlProvider, toolOptions, fieldOptions); } /** @@ -79,7 +79,7 @@ public class FunctionPurgeFieldFactory extends FieldFactory { stringDepth = Integer.toHexString(depth); } } - AttributedString as = new AttributedString(stringDepth, Color.BLUE, getMetrics()); + AttributedString as = new AttributedString(stringDepth, Palette.BLUE, getMetrics()); FieldElement text = new TextFieldElement(as, 0, 0); return ListingTextField.createSingleLineTextField(this, proxy, text, startX + varWidth, width, hlProvider); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java index 22ba668786..68673018de 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureFieldFactory.java @@ -23,6 +23,8 @@ import java.util.List; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.RowColLocation; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; @@ -99,18 +101,22 @@ public class FunctionSignatureFieldFactory extends FieldFactory { public void displayOptionsChanged(Options options, String optionName, Object oldValue, Object newValue) { super.displayOptionsChanged(options, optionName, oldValue, newValue); - funRetColor = options.getColor(OptionsGui.FUN_RET_TYPE.getColorOptionName(), Color.BLACK); - funNameColor = options.getColor(OptionsGui.FUN_NAME.getColorOptionName(), Color.BLACK); + funRetColor = + options.getColor(OptionsGui.FUN_RET_TYPE.getColorOptionName(), Colors.FOREGROUND); + funNameColor = + options.getColor(OptionsGui.FUN_NAME.getColorOptionName(), Colors.FOREGROUND); unresolvedThunkRefColor = displayOptions.getColor(OptionsGui.BAD_REF_ADDR.getColorOptionName(), OptionsGui.BAD_REF_ADDR.getDefaultColor()); resolvedThunkRefColor = displayOptions.getColor(OptionsGui.EXT_REF_RESOLVED.getColorOptionName(), OptionsGui.EXT_REF_RESOLVED.getDefaultColor()); - funParamsColor = options.getColor(OptionsGui.FUN_PARAMS.getColorOptionName(), Color.BLACK); + funParamsColor = + options.getColor(OptionsGui.FUN_PARAMS.getColorOptionName(), Colors.FOREGROUND); autoParamColor = - options.getColor(OptionsGui.FUN_AUTO_PARAMS.getColorOptionName(), Color.GRAY); - literalColor = options.getColor(OptionsGui.SEPARATOR.getColorOptionName(), Color.BLACK); + options.getColor(OptionsGui.FUN_AUTO_PARAMS.getColorOptionName(), Palette.GRAY); + literalColor = + options.getColor(OptionsGui.SEPARATOR.getColorOptionName(), Colors.FOREGROUND); } @Override @@ -413,8 +419,8 @@ public class FunctionSignatureFieldFactory extends FieldFactory { @Override public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new FunctionSignatureFieldFactory(formatModel, provider, displayOptions, + ToolOptions toolOptions, ToolOptions fieldOptions) { + return new FunctionSignatureFieldFactory(formatModel, provider, toolOptions, fieldOptions); } @@ -445,6 +451,7 @@ public class FunctionSignatureFieldFactory extends FieldFactory { * @param as the attributed string used to display this element. * @param row the row of the function signature where this field element starts. * @param column the column where this field element starts within the row. + * @param functionSigIndex the function signature index */ FunctionSignatureFieldElement(AttributedString as, int row, int column, int functionSigIndex) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureSourceFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureSourceFieldFactory.java index 218755d3b4..333b65eb3a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureSourceFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionSignatureSourceFieldFactory.java @@ -21,6 +21,7 @@ import java.math.BigInteger; import docking.widgets.fieldpanel.field.AttributedString; import docking.widgets.fieldpanel.field.TextFieldElement; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -70,7 +71,8 @@ public class FunctionSignatureSourceFieldFactory extends FieldFactory { public void displayOptionsChanged(Options options, String optionName, Object oldValue, Object newValue) { super.displayOptionsChanged(options, optionName, oldValue, newValue); - literalColor = options.getColor(OptionsGui.SEPARATOR.getColorOptionName(), Color.BLACK); + literalColor = + options.getColor(OptionsGui.SEPARATOR.getColorOptionName(), Colors.FOREGROUND); } @Override @@ -125,8 +127,8 @@ public class FunctionSignatureSourceFieldFactory extends FieldFactory { @Override public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new FunctionSignatureSourceFieldFactory(formatModel, provider, displayOptions, + ToolOptions toolOptions, ToolOptions fieldOptions) { + return new FunctionSignatureSourceFieldFactory(formatModel, provider, toolOptions, fieldOptions); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionTagFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionTagFieldFactory.java index 697384b4e4..90e7f64912 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionTagFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionTagFieldFactory.java @@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -44,7 +45,7 @@ import ghidra.program.util.ProgramLocation; public class FunctionTagFieldFactory extends FieldFactory { public static final String FIELD_NAME = "Function Tags"; - public static final Color DEFAULT_COLOR = new Color(130, 0, 75); + public static final Color DEFAULT_COLOR = Palette.MAROON; private Color literalColor; @@ -59,10 +60,9 @@ public class FunctionTagFieldFactory extends FieldFactory { * Constructor * * @param model the model that the field belongs to. - * @param hsProvider the HightLightStringProvider. + * @param hlProvider the HightLightStringProvider. * @param displayOptions the Options for display properties. * @param fieldOptions the Options for field specific properties. - * @param serviceProvider the provider for services. */ private FunctionTagFieldFactory(FieldFormatModel model, HighlightProvider hlProvider, Options displayOptions, Options fieldOptions) { @@ -73,10 +73,6 @@ public class FunctionTagFieldFactory extends FieldFactory { OptionsGui.SEPARATOR.getDefaultColor()); } - /****************************************************************************** - * PUBLIC METHODS - ******************************************************************************/ - @Override public ListingField getField(ProxyObj proxy, int varWidth) { @@ -139,8 +135,8 @@ public class FunctionTagFieldFactory extends FieldFactory { @Override public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new FunctionTagFieldFactory(formatModel, provider, displayOptions, fieldOptions); + ToolOptions toolOptions, ToolOptions fieldOptions) { + return new FunctionTagFieldFactory(formatModel, provider, toolOptions, fieldOptions); } @Override @@ -155,15 +151,12 @@ public class FunctionTagFieldFactory extends FieldFactory { super.displayOptionsChanged(options, optionName, oldValue, newValue); } - /****************************************************************************** - * PROTECTED METHODS - ******************************************************************************/ - /** * Creates a tags list field to be show at the beginning of each function that shows the tags * assigned to that function. * * @param function the function to retrieve the tags from + * @return the elements */ protected List createFunctionTagElements(FunctionDB function) { @@ -186,10 +179,6 @@ public class FunctionTagFieldFactory extends FieldFactory { return textElements; } - /****************************************************************************** - * PRIVATE METHODS - ******************************************************************************/ - /** * Returns all function tags associated with the given function. * diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ImageFactoryField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ImageFactoryField.java index cea5fb2df7..4aa0f249f6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ImageFactoryField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ImageFactoryField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +15,15 @@ */ package ghidra.app.util.viewer.field; -import ghidra.app.util.viewer.format.FieldFormatModel; -import ghidra.app.util.viewer.proxy.EmptyProxy; -import ghidra.app.util.viewer.proxy.ProxyObj; - import java.awt.FontMetrics; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.widgets.fieldpanel.field.SimpleImageField; import docking.widgets.fieldpanel.support.FieldLocation; +import ghidra.app.util.viewer.format.FieldFormatModel; +import ghidra.app.util.viewer.proxy.EmptyProxy; +import ghidra.app.util.viewer.proxy.ProxyObj; /** * Class for displaying images in fields. @@ -33,77 +31,69 @@ import docking.widgets.fieldpanel.support.FieldLocation; public class ImageFactoryField extends SimpleImageField implements ListingField { private FieldFactory factory; - private ProxyObj proxy; + private ProxyObj proxy; - /** - * Constructor - * @param factory the FieldFactory that generated this field. - * @param icon the ImageIcon to display. - * @param proxy the object that this field represents. - * @param metrics the FontMetrics used to render. - * @param x the starting x position for this field. - * @param width the width of this field. - */ - public ImageFactoryField(FieldFactory factory, - ImageIcon icon, - ProxyObj proxy, - FontMetrics metrics, - int x, - int width) { - this(factory, icon, proxy, metrics, x, width, false); - } + /** + * Constructor + * @param factory the FieldFactory that generated this field. + * @param icon the ImageIcon to display. + * @param proxy the object that this field represents. + * @param metrics the FontMetrics used to render. + * @param x the starting x position for this field. + * @param width the width of this field. + */ + public ImageFactoryField(FieldFactory factory, + Icon icon, + ProxyObj proxy, + FontMetrics metrics, + int x, + int width) { + this(factory, icon, proxy, metrics, x, width, false); + } - /** - * Constructor - * @param factory the FieldFactory that generated this field. - * @param icon the ImageIcon to display. - * @param proxy the object that this field represents. - * @param metrics the FontMetrics used to render. - * @param x the starting x position for this field. - * @param width the width of this field. - * @param center centers the image if true. - */ - public ImageFactoryField(FieldFactory factory, - ImageIcon icon, - ProxyObj proxy, - FontMetrics metrics, - int x, - int width, - boolean center) { + /** + * Constructor + * @param factory the FieldFactory that generated this field. + * @param icon the ImageIcon to display. + * @param proxy the object that this field represents. + * @param metrics the FontMetrics used to render. + * @param x the starting x position for this field. + * @param width the width of this field. + * @param center centers the image if true. + */ + public ImageFactoryField(FieldFactory factory, + Icon icon, + ProxyObj proxy, + FontMetrics metrics, + int x, + int width, + boolean center) { super(icon, metrics, x, 0, width, center); this.factory = factory; this.proxy = proxy; - } + } - /** - * Returns the FieldFactory that generated this Field. - */ + @Override public FieldFactory getFieldFactory() { - return factory; - } + return factory; + } - /** - * Returns the model that contains the FieldFactory that generated this Field. - */ + @Override public FieldFormatModel getFieldModel() { - return factory.getFieldModel(); - } + return factory.getFieldModel(); + } - /** - * Returns the object that this field is associated with. - */ - public ProxyObj getProxy() { + @Override + public ProxyObj getProxy() { if (proxy == null) { return EmptyProxy.EMPTY_PROXY; } - return proxy; - } + return proxy; + } - /** - * @see ListingField#getClickedObject(FieldLocation) - */ - public Object getClickedObject( FieldLocation fieldLocation ) { - return this; - } + @Override + public Object getClickedObject(FieldLocation fieldLocation) { + return this; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/IndentField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/IndentField.java index 080c574dfa..6446826ed4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/IndentField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/IndentField.java @@ -22,6 +22,7 @@ import javax.swing.JComponent; import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; import docking.widgets.fieldpanel.support.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.EmptyProxy; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -177,7 +178,7 @@ public class IndentField implements ListingField { public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) { - g.setColor(Color.LIGHT_GRAY); + g.setColor(Palette.LIGHT_GRAY); // draw the vertical lines to the left of the data (these are shown when there are vertical // bars drawn for inset data) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java index 55767826d2..a520453ae1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java @@ -20,6 +20,8 @@ import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -36,9 +38,9 @@ import ghidra.util.StringUtilities; public class InstructionMaskValueFieldFactory extends FieldFactory { public static final String FIELD_NAME = "Instr Mask/Value"; - public static final Color MASK_COLOR = new Color(0, 0, 128); - public static final Color VALUE_COLOR = new Color(0, 128, 0); - public static final Color LABEL_COLOR = new Color(0, 0, 0); + public static final Color MASK_COLOR = Palette.getColor("navy"); + public static final Color VALUE_COLOR = Palette.GREEN; + public static final Color LABEL_COLOR = Colors.FOREGROUND; /** * Default constructor. @@ -141,9 +143,6 @@ public class InstructionMaskValueFieldFactory extends FieldFactory { return buf.toString(); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField) - */ @Override public ProgramLocation getProgramLocation(int row, int col, ListingField bf) { Object obj = bf.getProxy().getObject(); @@ -156,9 +155,6 @@ public class InstructionMaskValueFieldFactory extends FieldFactory { col); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getFieldLocation(ghidra.app.util.viewer.field.ListingField, BigInteger, int, ghidra.program.util.ProgramLocation) - */ @Override public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum, ProgramLocation programLoc) { @@ -171,9 +167,6 @@ public class InstructionMaskValueFieldFactory extends FieldFactory { return null; } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#acceptsType(int, java.lang.Class) - */ @Override public boolean acceptsType(int category, Class proxyObjectClass) { return category == FieldFormatModel.INSTRUCTION_OR_DATA; @@ -181,16 +174,13 @@ public class InstructionMaskValueFieldFactory extends FieldFactory { @Override public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider hsProvider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new InstructionMaskValueFieldFactory(formatModel, hsProvider, displayOptions, + ToolOptions toolOptions, ToolOptions fieldOptions) { + return new InstructionMaskValueFieldFactory(formatModel, hsProvider, toolOptions, fieldOptions); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getDefaultColor() - */ @Override public Color getDefaultColor() { - return Color.black; + return Colors.FOREGROUND; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InvalidAnnotatedStringHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InvalidAnnotatedStringHandler.java index 68bf9ebe7e..0f745e99d3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InvalidAnnotatedStringHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InvalidAnnotatedStringHandler.java @@ -15,14 +15,12 @@ */ package ghidra.app.util.viewer.field; +import docking.widgets.fieldpanel.field.AttributedString; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.nav.Navigatable; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.listing.Program; -import java.awt.Color; - -import docking.widgets.fieldpanel.field.AttributedString; - /** * An annotated string handler that is used to display an error message string when there is a * problem creating an annotated string. @@ -42,7 +40,7 @@ public class InvalidAnnotatedStringHandler implements AnnotatedStringHandler { @Override public AttributedString createAnnotatedString(AttributedString prototypeString, String[] text, Program program) throws AnnotationException { - return new AttributedString(errorText, Color.RED, prototypeString.getFontMetrics(0)); + return new AttributedString(errorText, Messages.ERROR, prototypeString.getFontMetrics(0)); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java index 548a05ad9b..e225df955b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java @@ -24,6 +24,7 @@ import javax.swing.event.ChangeListener; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GIcon; import ghidra.app.util.*; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -36,9 +37,7 @@ import ghidra.program.util.*; import ghidra.util.HelpLocation; import ghidra.util.exception.AssertException; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.EmptyIcon; -import resources.icons.TranslateIcon; /** * Generates label Fields. @@ -58,8 +57,8 @@ public class LabelFieldFactory extends FieldFactory { // These icons would normally be static, but can't be because the class searcher loads this // class and it triggers swing access which is not allowed in headless. private Icon EMPTY_ICON = new EmptyIcon(12, 16); - private Icon ANCHOR_ICON = new MultiIcon(EMPTY_ICON, - new TranslateIcon(ResourceManager.loadImage("images/pin.png"), 0, 4)); + private Icon ANCHOR_ICON = + new MultiIcon(EMPTY_ICON, new GIcon("icon.base.util.viewer.fieldfactory.label")); private PropertyEditor namespaceOptionsEditor = new NamespacePropertyEditor(); @@ -75,7 +74,6 @@ public class LabelFieldFactory extends FieldFactory { public LabelFieldFactory() { super(FIELD_NAME); - initIcons(); } /** @@ -103,14 +101,6 @@ public class LabelFieldFactory extends FieldFactory { // Create code unit format and associated options - listen for changes codeUnitFormat = new LabelCodeUnitFormat(fieldOptions); codeUnitFormat.addChangeListener(codeUnitFormatListener); - initIcons(); - } - - private void initIcons() { - EMPTY_ICON = new EmptyIcon(12, 16); - ANCHOR_ICON = new MultiIcon(EMPTY_ICON, - new TranslateIcon(ResourceManager.loadImage("images/pin.png"), 0, 4)); - } private void setupNamespaceOptions(Options fieldOptions) { @@ -198,8 +188,8 @@ public class LabelFieldFactory extends FieldFactory { int nextPos = 0; if (hasOffcuts) { - for (int i = 0; i < offcuts.size(); i++) { - AttributedString as = getAttributedOffsetText(obj, cu, currAddr, offcuts.get(i)); + for (Address offcut : offcuts) { + AttributedString as = getAttributedOffsetText(obj, cu, currAddr, offcut); if (as == null) { as = new AttributedString(EMPTY_ICON, SymbolUtilities.getDynamicOffcutName(currAddr), diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java index 7b17a08eff..235eb487fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java @@ -23,6 +23,7 @@ import java.util.List; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.RowColLocation; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -41,7 +42,7 @@ import ghidra.program.util.ProgramLocation; public class MemoryBlockStartFieldFactory extends FieldFactory { private static final String FIELD_NAME = "Memory Block Start"; - private static final Color BLOCK_COLOR = new Color(75, 0, 130); + private static final Color BLOCK_COLOR = Palette.getColor("indigo"); /** * Constructor @@ -54,7 +55,7 @@ public class MemoryBlockStartFieldFactory extends FieldFactory { /** * Constructor * @param model the model that the field belongs to. - * @param hsProvider the HightLightStringProvider. + * @param hlProvider the HightLightStringProvider. * @param displayOptions the Options for display properties. * @param fieldOptions the Options for field specific properties. */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MnemonicFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MnemonicFieldFactory.java index b09be00c41..a7850ca733 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MnemonicFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MnemonicFieldFactory.java @@ -22,6 +22,8 @@ import javax.swing.event.ChangeListener; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors.Messages; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; @@ -43,9 +45,9 @@ import ghidra.util.HelpLocation; */ public class MnemonicFieldFactory extends FieldFactory { public static final String FIELD_NAME = "Mnemonic"; - public static final Color OVERRIDE_COLOR = new Color(180, 0, 108); -// TODO: Should BAD_PROTOTYPE_COLOR be an option? - private final static Color BAD_PROTOTYPE_COLOR = new Color(196, 0, 0); + public static final Color OVERRIDE_COLOR = Palette.PURPLE; + + private final static Color BAD_PROTOTYPE_COLOR = Messages.ERROR; private final static String SHOW_UNDERLINE_FOR_REFERENCES = GhidraOptions.MNEMONIC_GROUP_TITLE + Options.DELIMITER + "Underline Fields With References"; @@ -140,7 +142,7 @@ public class MnemonicFieldFactory extends FieldFactory { else { Data data = (Data) cu; if (data.isDefined() && data.getDataType().isNotYetDefined()) { - c = Color.RED; + c = Messages.ERROR; } } AttributedString as = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OpenCloseField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OpenCloseField.java index bdbd1069a4..29557cd47e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OpenCloseField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OpenCloseField.java @@ -17,24 +17,26 @@ package ghidra.app.util.viewer.field; import java.awt.*; -import javax.swing.ImageIcon; import javax.swing.JComponent; import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; import docking.widgets.fieldpanel.support.*; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.EmptyProxy; import ghidra.app.util.viewer.proxy.ProxyObj; import ghidra.program.model.listing.Data; -import resources.ResourceManager; /** * FactoryField class for displaying the open/close field. */ public class OpenCloseField implements ListingField { - private static final ImageIcon openImage = ResourceManager.loadImage("images/small_minus.png"); - private static final ImageIcon closedImage = ResourceManager.loadImage("images/small_plus.png"); + private static final GIcon OPEN_ICON = + new GIcon("icon.base.util.viewer.fieldfactory.openclose.open"); + private static final GIcon CLOSED_ICON = + new GIcon("icon.base.util.viewer.fieldfactory.openclose.closed"); private FieldFactory factory; private int startX; @@ -42,7 +44,7 @@ public class OpenCloseField implements ListingField { private int fieldWidth; private int heightAbove; private int heightBelow; - private ProxyObj proxy; + private ProxyObj proxy; private boolean isOpen; private int indentLevel; @@ -61,7 +63,7 @@ public class OpenCloseField implements ListingField { * @param width the width of this field. * @param isLast true if the data object is the last subcomponent at its level. */ - public OpenCloseField(FieldFactory factory, ProxyObj proxy, int indentLevel, + public OpenCloseField(FieldFactory factory, ProxyObj proxy, int indentLevel, FontMetrics metrics, int x, int width, boolean isLast) { this.factory = factory; this.proxy = proxy; @@ -86,7 +88,7 @@ public class OpenCloseField implements ListingField { } @Override - public ProxyObj getProxy() { + public ProxyObj getProxy() { if (proxy == null) { return EmptyProxy.EMPTY_PROXY; } @@ -105,7 +107,7 @@ public class OpenCloseField implements ListingField { /** * Sets the yPos relative to the overall layout. - * @param yPos the starting Ypos of the layout row. + * @param yPos the starting Y position of the layout row. * @param heightAbove the heightAbove the alignment line in the layout row. * @param heightBelow the heightBelow the alignment line in the layout row. */ @@ -137,6 +139,7 @@ public class OpenCloseField implements ListingField { /** * Returns the vertical position of this field. + * @return the position */ public int getStartY() { return startY; @@ -167,16 +170,16 @@ public class OpenCloseField implements ListingField { // if (!context.isPrinting()) { if (isOpen) { - g.drawImage(openImage.getImage(), toggleHandleStartX, toggleHandleStartY, - context.getBackground(), null); + g.drawImage(OPEN_ICON.getImageIcon().getImage(), toggleHandleStartX, + toggleHandleStartY, context.getBackground(), null); } else { - g.drawImage(closedImage.getImage(), toggleHandleStartX, toggleHandleStartY, - context.getBackground(), null); + g.drawImage(CLOSED_ICON.getImageIcon().getImage(), toggleHandleStartX, + toggleHandleStartY, context.getBackground(), null); } } - g.setColor(Color.LIGHT_GRAY); + g.setColor(Palette.LIGHT_GRAY); // draw the vertical lines to the left of the toggle handle (these are shown when // there are vertical bars drawn for inset data) @@ -340,6 +343,6 @@ public class OpenCloseField implements ListingField { //================================================================================================== static int getOpenCloseHandleSize() { - return openImage.getIconWidth(); + return OPEN_ICON.getIconWidth(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ParallelInstructionFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ParallelInstructionFieldFactory.java index 4d5c19e7fb..1a7d7b69e3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ParallelInstructionFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ParallelInstructionFieldFactory.java @@ -20,6 +20,8 @@ import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -38,7 +40,7 @@ import ghidra.program.util.ProgramLocation; public class ParallelInstructionFieldFactory extends FieldFactory { public static final String FIELD_NAME = "Parallel ||"; - public static final Color DEFAULT_COLOR = new Color(0, 0, 128); + public static final Color DEFAULT_COLOR = Palette.BLUE; /** * Default constructor. @@ -60,19 +62,18 @@ public class ParallelInstructionFieldFactory extends FieldFactory { } @Override - public void fieldOptionsChanged(Options options, String name, Object oldValue, + public void fieldOptionsChanged(Options options, String optionName, Object oldValue, Object newValue) { // don't care } /** * Returns the FactoryField for the given object at index index. - * @param varWidth the amount of variable width spacing for any fields - * before this one. * @param proxy the object whose properties should be displayed. + * @param varWidth the amount of variable width spacing for any fields before this one. */ @Override - public ListingField getField(ProxyObj proxy, int varWidth) { + public ListingField getField(ProxyObj proxy, int varWidth) { Object obj = proxy.getObject(); if (!enabled || !(obj instanceof Instruction)) { @@ -98,9 +99,6 @@ public class ParallelInstructionFieldFactory extends FieldFactory { width, hlProvider); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField) - */ @Override public ProgramLocation getProgramLocation(int row, int col, ListingField bf) { Object obj = bf.getProxy().getObject(); @@ -112,9 +110,6 @@ public class ParallelInstructionFieldFactory extends FieldFactory { return new ParallelInstructionLocation(instr.getProgram(), instr.getMinAddress(), col); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getFieldLocation(ghidra.app.util.viewer.field.ListingField, BigInteger, int, ghidra.program.util.ProgramLocation) - */ @Override public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum, ProgramLocation programLoc) { @@ -126,25 +121,20 @@ public class ParallelInstructionFieldFactory extends FieldFactory { return null; } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#acceptsType(int, java.lang.Class) - */ @Override public boolean acceptsType(int category, Class proxyObjectClass) { return category == FieldFormatModel.INSTRUCTION_OR_DATA; } @Override - public FieldFactory newInstance(FieldFormatModel model, HighlightProvider hsProvider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new ParallelInstructionFieldFactory(model, hsProvider, displayOptions, fieldOptions); + public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider hsProvider, + ToolOptions toolOptinos, ToolOptions fieldOptions) { + return new ParallelInstructionFieldFactory(formatModel, hsProvider, toolOptinos, + fieldOptions); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getDefaultColor() - */ @Override public Color getDefaultColor() { - return Color.black; + return Colors.FOREGROUND; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PlateFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PlateFieldFactory.java index ce4194a24c..0c0c4c3a06 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PlateFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PlateFieldFactory.java @@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.util.HelpTopics; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; @@ -47,7 +48,7 @@ public class PlateFieldFactory extends FieldFactory { private static final String EMPTY_STRING = ""; public static final String FIELD_NAME = "Plate Comment"; - public static final Color DEFAULT_COLOR = Color.BLUE; + public static final Color DEFAULT_COLOR = Palette.BLUE; private final static String FIELD_GROUP_TITLE = "Plate Comments Field"; public final static String ENABLE_WORD_WRAP_MSG = FIELD_GROUP_TITLE + Options.DELIMITER + "Enable Word Wrapping"; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java index e95bd974a8..2d3a5de21e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java @@ -15,11 +15,11 @@ */ package ghidra.app.util.viewer.field; -import java.awt.Color; import java.math.BigInteger; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.proxy.ProxyObj; @@ -67,38 +67,42 @@ public class SpaceFieldFactory extends FieldFactory { if (!enabled || !(obj instanceof CodeUnit)) { return null; } + CodeUnit cu = (CodeUnit) obj; - - if (cu.hasProperty(CodeUnit.SPACE_PROPERTY)) { - - try { - int n = cu.getIntProperty(CodeUnit.SPACE_PROPERTY); - if (n == 0) { - cu.removeProperty(CodeUnit.SPACE_PROPERTY); - return null; - } - else if (n < 0) { - n = -n; - } - FieldElement[] fes = new FieldElement[n]; - AttributedString as = new AttributedString("", Color.BLACK, getMetrics()); - for (int i = 0; i < n; i++) { - fes[i] = new TextFieldElement(as, 0, 0); - } - - return ListingTextField.createMultilineTextField(this, proxy, fes, - startX + varWidth, width, n + 1, hlProvider); + Integer n = getSpaces(cu); + if (n != null) { + if (n == 0) { + cu.removeProperty(CodeUnit.SPACE_PROPERTY); + return null; } - catch (NoValueException e) { + else if (n < 0) { + n = -n; } + FieldElement[] fes = new FieldElement[n]; + AttributedString as = new AttributedString("", Colors.FOREGROUND, getMetrics()); + for (int i = 0; i < n; i++) { + fes[i] = new TextFieldElement(as, 0, 0); + } + + return ListingTextField.createMultilineTextField(this, proxy, fes, + startX + varWidth, width, n + 1, hlProvider); } return null; } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField) - */ + private Integer getSpaces(CodeUnit cu) { + if (cu.hasProperty(CodeUnit.SPACE_PROPERTY)) { + try { + return cu.getIntProperty(CodeUnit.SPACE_PROPERTY); + } + catch (NoValueException e) { + // can't happen + } + } + return null; + } + @Override public ProgramLocation getProgramLocation(int row, int col, ListingField bf) { Object obj = bf.getProxy().getObject(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SymbolAnnotatedStringHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SymbolAnnotatedStringHandler.java index b3c2626908..f843f4f27c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SymbolAnnotatedStringHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SymbolAnnotatedStringHandler.java @@ -15,11 +15,12 @@ */ package ghidra.app.util.viewer.field; -import java.awt.Color; import java.util.*; import java.util.regex.Pattern; import docking.widgets.fieldpanel.field.AttributedString; +import generic.theme.GThemeDefaults.Colors.Messages; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.nav.Navigatable; import ghidra.app.services.GoToService; import ghidra.app.util.NamespaceUtils; @@ -90,7 +91,7 @@ public class SymbolAnnotatedStringHandler implements AnnotatedStringHandler { prototypeString.getFontMetrics(0), true, prototypeString.getColor(0)); } - return new AttributedString("No symbol: " + text[1], Color.RED, + return new AttributedString("No symbol: " + text[1], Messages.ERROR, prototypeString.getFontMetrics(0), false, null); } @@ -101,7 +102,7 @@ public class SymbolAnnotatedStringHandler implements AnnotatedStringHandler { buffer.append(string).append(" "); } - return new AttributedString(buffer.toString(), Color.LIGHT_GRAY, + return new AttributedString(buffer.toString(), Palette.LIGHT_GRAY, prototypeString.getFontMetrics(0)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/URLAnnotatedStringHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/URLAnnotatedStringHandler.java index fc08f64810..6895494fd3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/URLAnnotatedStringHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/URLAnnotatedStringHandler.java @@ -15,6 +15,11 @@ */ package ghidra.app.util.viewer.field; +import java.net.MalformedURLException; +import java.net.URL; + +import docking.widgets.fieldpanel.field.AttributedString; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.nav.Navigatable; import ghidra.app.services.ProgramManager; import ghidra.framework.plugintool.ServiceProvider; @@ -23,12 +28,6 @@ import ghidra.program.model.listing.Program; import ghidra.util.BrowserLoader; import ghidra.util.Msg; -import java.awt.Color; -import java.net.MalformedURLException; -import java.net.URL; - -import docking.widgets.fieldpanel.field.AttributedString; - /** * An annotated string handler that allows handles annotations that begin with * {@link #SUPPORTED_ANNOTATIONS}. This class expects one or two strings following the annotation. @@ -37,8 +36,8 @@ import docking.widgets.fieldpanel.field.AttributedString; * displayed. */ public class URLAnnotatedStringHandler implements AnnotatedStringHandler { - private static final String INVALID_SYMBOL_TEXT = "@url annotation must have a URL string " - + "optionally followed by a display string"; + private static final String INVALID_SYMBOL_TEXT = + "@url annotation must have a URL string " + "optionally followed by a display string"; private static final String[] SUPPORTED_ANNOTATIONS = { "url", "hyperlink", "href", "link" }; @Override @@ -54,7 +53,7 @@ public class URLAnnotatedStringHandler implements AnnotatedStringHandler { if (url == null) { return new AttributedString("Invalid URL annotations - not a URL: " + text[1], - Color.RED, prototypeString.getFontMetrics(0), false, Color.RED); + Messages.ERROR, prototypeString.getFontMetrics(0), false, Messages.ERROR); } String displayText = url.toExternalForm(); @@ -88,6 +87,7 @@ public class URLAnnotatedStringHandler implements AnnotatedStringHandler { return url; } + @Override public boolean handleMouseClick(String[] annotationParts, Navigatable navigatable, ServiceProvider serviceProvider) { String urlString = annotationParts[1]; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableLocFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableLocFieldFactory.java index d670e6e662..8b8a9e73c9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableLocFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableLocFieldFactory.java @@ -23,6 +23,8 @@ import javax.swing.Icon; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.format.FieldFormatModel; import ghidra.app.util.viewer.options.OptionsGui; @@ -34,7 +36,6 @@ import ghidra.program.model.listing.Variable; import ghidra.program.util.ProgramLocation; import ghidra.program.util.VariableLocFieldLocation; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.EmptyIcon; /** @@ -42,12 +43,9 @@ import resources.icons.EmptyIcon; */ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { public static final String FIELD_NAME = "Variable Location"; -// - private static final Icon INVALID_STORAGE_ICON = - ResourceManager.loadImage("images/warning.png"); -// private static final Icon EMPTY_ICON = new EmptyIcon(20, 12); -// private static Icon invalidStorageIcon; + private static final Icon INVALID_STORAGE_ICON = + new GIcon("icon.base.util.viewer.fieldfactory.variable"); /** * Constructor @@ -59,7 +57,7 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { /** * Constructor * @param model the model that the field belongs to. - * @param hsProvider the HightLightStringProvider. + * @param hlProvider the HightLightStringProvider. * @param displayOptions the Options for display properties. * @param fieldOptions the Options for field specific properties. */ @@ -78,9 +76,6 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { return icon; } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getField(ProxyObj, int) - */ @Override public ListingField getField(ProxyObj proxy, int varWidth) { Object obj = proxy.getObject(); @@ -93,7 +88,7 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { boolean hasInvalidStorage = !var.isValid(); String loc = var.getVariableStorage().toString(); AttributedString as = new AttributedString(getStorageIcon(fontMetrics, hasInvalidStorage), - loc, hasInvalidStorage ? Color.RED : getColor(var), fontMetrics, false, null); + loc, hasInvalidStorage ? Messages.ERROR : getColor(var), fontMetrics, false, null); FieldElement field = new TextFieldElement(as, 0, 0); return ListingTextField.createSingleLineTextField(this, proxy, field, startX + varWidth, width, hlProvider); @@ -102,6 +97,7 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { /** * Returns the string representing the offset. * @param offset the offset to get a string for + * @return the offset string */ public String getOffsetString(int offset) { String offString = @@ -109,10 +105,6 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { return offString; } - /** - * - * @see ghidra.app.util.viewer.field.FieldFactory#getProgramLocation(int, int, ghidra.app.util.viewer.field.ListingField) - */ @Override public ProgramLocation getProgramLocation(int row, int col, ListingField bf) { ProxyObj proxy = bf.getProxy(); @@ -126,9 +118,6 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { return null; } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getFieldLocation(ghidra.app.util.viewer.field.ListingField, BigInteger, int, ghidra.program.util.ProgramLocation) - */ @Override public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum, ProgramLocation loc) { @@ -149,9 +138,6 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { return null; } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#acceptsType(int, java.lang.Class) - */ @Override public boolean acceptsType(int category, Class proxyObjectClass) { if (!Variable.class.isAssignableFrom(proxyObjectClass)) { @@ -162,13 +148,10 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory { @Override public FieldFactory newInstance(FieldFormatModel formatModel, HighlightProvider provider, - ToolOptions displayOptions, ToolOptions fieldOptions) { - return new VariableLocFieldFactory(formatModel, provider, displayOptions, fieldOptions); + ToolOptions toolOptions, ToolOptions fieldOptions) { + return new VariableLocFieldFactory(formatModel, provider, toolOptions, fieldOptions); } - /** - * @see ghidra.app.util.viewer.field.FieldFactory#getDefaultColor() - */ @Override public Color getDefaultColor() { return OptionsGui.VARIABLE.getDefaultColor(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableXRefFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableXRefFieldFactory.java index 0bfea408ec..bd98344f0c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableXRefFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableXRefFieldFactory.java @@ -15,13 +15,13 @@ */ package ghidra.app.util.viewer.field; -import java.awt.Color; import java.math.BigInteger; import java.util.*; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.RowColLocation; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.HighlightProvider; import ghidra.app.util.XReferenceUtils; import ghidra.app.util.viewer.format.FieldFormatModel; @@ -101,7 +101,7 @@ public class VariableXRefFieldFactory extends XRefFieldFactory { int totalXrefs = xrefs.size() + offcuts.size(); boolean tooMany = totalXrefs > maxXRefs; - AttributedString delimiter = new AttributedString(delim, Color.BLACK, getMetrics()); + AttributedString delimiter = new AttributedString(delim, Colors.FOREGROUND, getMetrics()); FieldElement[] elements = new FieldElement[tooMany ? maxXRefs : totalXrefs]; int count = 0; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java index add67b32f2..306b6cb585 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/XRefFieldFactory.java @@ -27,6 +27,7 @@ import javax.swing.event.ChangeListener; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.*; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.HighlightProvider; import ghidra.app.util.XReferenceUtils; import ghidra.app.util.viewer.format.FieldFormatModel; @@ -428,7 +429,7 @@ public class XRefFieldFactory extends FieldFactory { HighlightFactory hlFactory) { FontMetrics metrics = getMetrics(); - AttributedString delimiter = new AttributedString(delim, Color.BLACK, metrics); + AttributedString delimiter = new AttributedString(delim, Colors.FOREGROUND, metrics); int row = 0; List elements = new ArrayList<>(); @@ -490,7 +491,7 @@ public class XRefFieldFactory extends FieldFactory { HighlightFactory hlFactory) { FontMetrics metrics = getMetrics(); - AttributedString delimiter = new AttributedString(delim, Color.BLACK, metrics); + AttributedString delimiter = new AttributedString(delim, Colors.FOREGROUND, metrics); int row = startRow; List elements = new ArrayList<>(); for (Reference ref : xrefs) { @@ -542,7 +543,7 @@ public class XRefFieldFactory extends FieldFactory { CodeUnit cu = (CodeUnit) obj; Program program = cu.getProgram(); FontMetrics metrics = getMetrics(); - AttributedString delimiter = new AttributedString(delim, Color.BLACK, metrics); + AttributedString delimiter = new AttributedString(delim, Colors.FOREGROUND, metrics); Set offcutSet = new HashSet<>(offcuts); Predicate isOffcut = r -> offcutSet.contains(r); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/ErrorListingField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/ErrorListingField.java index a56c92a9e6..4d55952a0c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/ErrorListingField.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/ErrorListingField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,33 +15,29 @@ */ package ghidra.app.util.viewer.format; +import docking.widgets.fieldpanel.field.*; +import docking.widgets.fieldpanel.support.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.field.*; import ghidra.app.util.viewer.proxy.ProxyObj; -import java.awt.Color; - -import docking.widgets.fieldpanel.field.*; -import docking.widgets.fieldpanel.support.*; - public class ErrorListingField extends ListingTextField { private Throwable t; - private static HighlightProvider myProvider = new HighlightProvider() { + private static HighlightProvider myProvider = + (text, obj, fieldFactoryClass, cursorTextOffset) -> new Highlight[] { + new Highlight(0, text.length() - 1, new GColor("color.bg.error")) }; - public Highlight[] getHighlights(String text, Object obj, - Class fieldFactoryClass, int cursorTextOffset) { - return new Highlight[] { new Highlight(0, text.length() - 1, new Color(245, 158, 158)) }; - } - }; - - public ErrorListingField(FieldFactory ff, ProxyObj proxy, int varWidth, Throwable t) { + public ErrorListingField(FieldFactory ff, ProxyObj proxy, int varWidth, Throwable t) { super(ff, proxy, createField(ff, proxy, varWidth, t)); this.t = t; } - private static TextField createField(FieldFactory ff, ProxyObj proxy, int varWidth, Throwable t) { + private static TextField createField(FieldFactory ff, ProxyObj proxy, int varWidth, + Throwable t) { HighlightFactory hlFactory = new FieldHighlightFactory(myProvider, ff.getClass(), proxy.getObject()); return new ClippingTextField(ff.getStartX() + varWidth, ff.getWidth(), @@ -53,7 +48,7 @@ public class ErrorListingField extends ListingTextField { String message = t.getMessage() == null ? t.toString() : t.getMessage(); AttributedString as = new AttributedString("*Error*: " + message + ". Double click for Details.", - Color.BLACK, ff.getMetrics()); + Colors.FOREGROUND, ff.getMetrics()); return new TextFieldElement(as, 0, 0); } @@ -61,9 +56,6 @@ public class ErrorListingField extends ListingTextField { return t; } - /** - * @see ListingTextField#getClickedObject(FieldLocation) - */ @Override public Object getClickedObject(FieldLocation fieldLocation) { // overridden to return this object, rather than the lower-level text field diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java index 9fec8465b4..e161262d16 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/format/FieldHeaderComp.java @@ -22,6 +22,8 @@ import javax.swing.*; import javax.swing.border.Border; import docking.widgets.label.GDLabel; +import generic.theme.GColor; +import generic.theme.Gui; import ghidra.app.util.viewer.field.FieldFactory; import ghidra.util.HelpLocation; import ghidra.util.Swing; @@ -32,6 +34,8 @@ import help.HelpService; * Class manage a header for the FieldViewer. */ public class FieldHeaderComp extends JPanel { + private static final String FONT_ID = "font.listing.header"; + private enum CursorState { NOWHERE, NEAR_EDGE, OVER_FIELD } @@ -41,6 +45,11 @@ public class FieldHeaderComp extends JPanel { private static final int DEFAULT_SNAP_SIZE = 10; + private static final Color ACTIVE_FIELD_BG_COLOR = + new GColor("color.bg.listing.header.active.field"); + private static final Color ACTIVE_FIELD_FG_COLOR = + new GColor("color.fg.listing.header.active.field"); + private FieldFormatModel model; private JLabel label; private int rowHeight; @@ -52,8 +61,8 @@ public class FieldHeaderComp extends JPanel { private int anchorX; private int anchorY; private int snapSize = DEFAULT_SNAP_SIZE; - private Color buttonColor; - private Color highlightButtonColor; + private Color defaultButtonBgColor; + private Color defaultButtonFgColor; private boolean editInProgress; private MovingField moving; @@ -78,11 +87,11 @@ public class FieldHeaderComp extends JPanel { label = new GDLabel("Test"); label.setOpaque(true); label.setHorizontalAlignment(SwingConstants.CENTER); - buttonColor = label.getBackground(); + defaultButtonBgColor = label.getBackground(); + defaultButtonFgColor = label.getForeground(); label.setBorder(BorderFactory.createCompoundBorder(border2, border1)); - label.setFont(new Font("Tahoma", Font.PLAIN, 11)); + label.setFont(Gui.getFont(FONT_ID)); Dimension d = label.getPreferredSize(); - highlightButtonColor = new Color(244, 221, 183); rowHeight = d.height; this.setMinimumSize(new Dimension(0, 2 * rowHeight)); renderPane = new CellRendererPane(); @@ -130,6 +139,7 @@ public class FieldHeaderComp extends JPanel { /** * Returns the currently displayed model. + * @return the currently displayed model. */ public FieldFormatModel getModel() { return model; @@ -190,9 +200,6 @@ public class FieldHeaderComp extends JPanel { } } - /** - * Callback for when the mouse button is pressed. - */ private void pressed(int x, int y) { editInProgress = true; headerPanel.setTabLock(true); @@ -211,9 +218,6 @@ public class FieldHeaderComp extends JPanel { } } - /** - * Callback for when the mouse button is released. - */ private void released(int x, int y) { if (!editInProgress) { return; @@ -242,9 +246,6 @@ public class FieldHeaderComp extends JPanel { Swing.runLater(() -> headerPanel.setTabLock(false)); } - /** - * Callback for when the mouse is dragged. - */ private void dragged(int x, int y) { int deltaX = x - anchorX; int deltaY = y - anchorY; @@ -263,9 +264,6 @@ public class FieldHeaderComp extends JPanel { } } - /** - * Callback as the user is resizing a field. - */ private void resize(int deltaX) { int row = curRow; int col = edgeCol; @@ -283,7 +281,8 @@ public class FieldHeaderComp extends JPanel { /** * Returns the row in the model that the point is over. - * @param p the point for which to find its corresponding row. + * @param p the point for which to find its corresponding row + * @return the row */ public int getRow(Point p) { if (p.y < 0) { @@ -297,9 +296,10 @@ public class FieldHeaderComp extends JPanel { } /** - * 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 */ public int getCol(int row, int x) { if (x < 0) { @@ -326,7 +326,7 @@ public class FieldHeaderComp extends JPanel { @Override public void paint(Graphics g) { - g.setColor(buttonColor); + g.setColor(defaultButtonBgColor); int nRows = model.getNumRows(); Dimension dim = getSize(); g.fillRect(0, 0, dim.width, dim.height); @@ -344,10 +344,12 @@ public class FieldHeaderComp extends JPanel { label.setText(name); label.setEnabled(factorys[j].isEnabled()); if (factorys[j] == selectedFactory) { - label.setBackground(highlightButtonColor); + label.setBackground(ACTIVE_FIELD_BG_COLOR); + label.setForeground(ACTIVE_FIELD_FG_COLOR); } else { - label.setBackground(buttonColor); + label.setBackground(defaultButtonBgColor); + label.setForeground(defaultButtonFgColor); } renderPane.paintComponent(g, label, this, startX, startY, width, height, true); @@ -363,9 +365,6 @@ public class FieldHeaderComp extends JPanel { } - /** - * Returns the preferredSize for this header component. - */ @Override public Dimension getPreferredSize() { FormatManager formatManager = model.getFormatManager(); @@ -380,7 +379,8 @@ public class FieldHeaderComp extends JPanel { /** * Returns a FieldHeaderLocation for the given point - * @param p the point to get a location for. + * @param p the point to get a location for + * @return the location */ public FieldHeaderLocation getFieldHeaderLocation(Point p) { int row = getRow(p); @@ -419,9 +419,6 @@ public class FieldHeaderComp extends JPanel { int widthRightField; int widthLeftField; - /** - * Construct a Moving Field for the field at the given row and column. - */ MovingField(int row, int col) { baseRow = row; baseCol = col; @@ -434,17 +431,11 @@ public class FieldHeaderComp extends JPanel { } - /** - * Moves the floating field by the given deltas. - */ void moveFloating(int deltaX, int deltaY) { floatingX += deltaX; floatingY += deltaY; } - /** - * Moves the base field to a new position in the header. - */ void move() { if (((floatingY - y) > rowHeight / 2) && baseRow < 11) { // move down @@ -508,9 +499,6 @@ public class FieldHeaderComp extends JPanel { } - /** - * Returns the start position of the base field. - */ private int getStart() { int start = 0; FieldFactory[] factorys = model.getFactorys(baseRow); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonOptions.java index 7d801e8b4a..b86f766876 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonOptions.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonOptions.java @@ -17,6 +17,7 @@ package ghidra.app.util.viewer.listingpanel; import java.awt.Color; +import generic.theme.GColor; import ghidra.framework.options.ToolOptions; import ghidra.util.HelpLocation; @@ -42,15 +43,16 @@ public class ListingCodeComparisonOptions { private static final String DEFAULT_UNMATCHED_CODE_UNITS_BACKGROUND_COLOR_DESCRIPTION = "The default background color applied to code units that are unmatched within the listing code comparison window by the address correlator."; - public static final Color MEDIUM_SKY_BLUE_COLOR = new Color(0x69, 0xcd, 0xe1); - public static final Color MEDIUM_GRAY_COLOR = new Color(0xb9, 0xb9, 0xb9); - public static final Color SPRING_GREEN_COLOR = new Color(0xaf, 0xff, 0x69); - - private static final Color DEFAULT_BYTE_DIFFS_COLOR = SPRING_GREEN_COLOR; - private static final Color DEFAULT_MNEMONIC_DIFFS_COLOR = SPRING_GREEN_COLOR; - private static final Color DEFAULT_OPERAND_DIFFS_COLOR = SPRING_GREEN_COLOR; - private static final Color DEFAULT_DIFF_CODE_UNITS_COLOR = MEDIUM_GRAY_COLOR; - private static final Color DEFAULT_UNMATCHED_CODE_UNITS_COLOR = MEDIUM_SKY_BLUE_COLOR; + private static final Color DEFAULT_BYTE_DIFFS_COLOR = + new GColor("color.bg.listing.comparison.bytes"); + private static final Color DEFAULT_MNEMONIC_DIFFS_COLOR = + new GColor("color.bg.listing.comparison.mnemonic"); + private static final Color DEFAULT_OPERAND_DIFFS_COLOR = + new GColor("color.bg.listing.comparison.operand"); + private static final Color DEFAULT_DIFF_CODE_UNITS_COLOR = + new GColor("color.bg.listing.comparison.code.units.diff"); + private static final Color DEFAULT_UNMATCHED_CODE_UNITS_COLOR = + new GColor("color.bg.listing.comparison.code.units.unmatched"); private Color byteDiffsColor = DEFAULT_BYTE_DIFFS_COLOR; private Color mnemonicDiffsColor = DEFAULT_MNEMONIC_DIFFS_COLOR; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java index 50bca2ccb1..fd74443260 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java @@ -35,6 +35,8 @@ import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; import docking.widgets.fieldpanel.listener.FieldLocationListener; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.ViewerPosition; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.nav.Navigatable; import ghidra.app.plugin.core.codebrowser.MarkerServiceBackgroundColorModel; @@ -61,8 +63,6 @@ import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; import help.Help; import help.HelpService; -import resources.Icons; -import resources.ResourceManager; /** * Panel that displays two listings for comparison. @@ -72,6 +72,8 @@ public class ListingCodeComparisonPanel extends CodeComparisonPanel implements FormatModelListener, CodeFormatService, ListingDiffChangeListener, OptionsChangeListener { + private static final Color FG_COLOR_TITLE = Palette.DARK_GRAY; + private static final String DUAL_LISTING_HEADER_SHOWING = "DUAL_LISTING_HEADER_SHOWING"; private static final String DUAL_LISTING_SIDE_BY_SIDE = "DUAL_LISTING_SIDE_BY_SIDE"; public static final String NAME = "DualListing"; @@ -85,22 +87,24 @@ public class ListingCodeComparisonPanel private static final String DIFF_NAVIGATE_GROUP = "A2_DiffNavigate"; private static final String HOVER_GROUP = "A5_Hovers"; private static final String PROPERTIES_GROUP = "B1_Properties"; - private static final Icon NEXT_DIFF_ICON = - ResourceManager.loadImage("images/view-sort-ascending.png"); - private static final Icon PREVIOUS_DIFF_ICON = - ResourceManager.loadImage("images/view-sort-descending.png"); - private static final Icon bothIcon = ResourceManager.loadImage("images/text_list_bullets.png"); - private static final Icon unmatchedIcon = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON; - private static final Icon diffsIcon = - ResourceManager.loadImage("images/table_relationship.png"); + + //@formatter:off + private static final Icon NEXT_DIFF_ICON = new GIcon("icon.base.util.listingcompare.diff.next"); + private static final Icon PREVIOUS_DIFF_ICON = new GIcon("icon.base.util.listingcompare.previous.next"); + private static final Icon BOTH_VIEWS_ICON = new GIcon("icon.base.util.listingcompare.area.markers.all"); + private static final Icon UNMATCHED_ICON = new GIcon("icon.base.util.listingcompare.area.markers.unmatched"); + private static final Icon DIFF_ICON = new GIcon("icon.base.util.listingcompare.area.markers.diff"); + private static final Icon CURSOR_LOC_ICON = new GIcon("icon.base.util.listingcompare.cursor"); + //@formatter:on + + private static final Icon HOVER_ON_ICON = new GIcon("icon.base.util.listingcompare.hover.on"); + private static final Icon HOVER_OFF_ICON = new GIcon("icon.base.util.listingcompare.hover.off"); + private static final String ALL_AREA_MARKERS = "All Area Markers"; private static final String UNMATCHED_AREA_MARKERS = "Unmatched Area Markers"; private static final String DIFF_AREA_MARKERS = "Diff Area Markers"; private String nextPreviousAreaType; - private static final Icon HOVER_ON_ICON = ResourceManager.loadImage("images/hoverOn.gif"); - private static final Icon HOVER_OFF_ICON = ResourceManager.loadImage("images/hoverOff.gif"); - private ListingPanel[] listingPanels = new ListingPanel[2]; private ListingDiff listingDiff; private ListingDiffActionManager diffActionManager; @@ -116,8 +120,6 @@ public class ListingCodeComparisonPanel private MarkerSet[] diffMarkers = new MarkerSet[2]; private MarkerSet[] currentCursorMarkers = new MarkerSet[2]; private static final Color CURSOR_LINE_COLOR = GhidraOptions.DEFAULT_CURSOR_LINE_COLOR; - private ImageIcon CURSOR_LOC_ICON = - ResourceManager.loadImage("images/cursor_arrow_flipped.gif"); private Color cursorHighlightColor; private boolean isShowingEntireListing; private boolean isSideBySide = true; @@ -149,7 +151,7 @@ public class ListingCodeComparisonPanel FunctionNameListingHover functionNameHoverService; private String leftTitle; private String rightTitle; - private ListingCodeComparisonOptions comparisonOptions = new ListingCodeComparisonOptions(); + private ListingCodeComparisonOptions comparisonOptions; private Address[] coordinatorLockedAddresses; /** @@ -663,7 +665,7 @@ public class ListingCodeComparisonPanel public NextPreviousAreaMarkerAction(String owner) { super("Dual Listing Next/Previous Area Marker", owner); - ToolBarData toolBarData = new ToolBarData(diffsIcon, DIFF_NAVIGATE_GROUP); + ToolBarData toolBarData = new ToolBarData(DIFF_ICON, DIFF_NAVIGATE_GROUP); setToolBarData(toolBarData); HelpLocation helpLocation = @@ -672,13 +674,13 @@ public class ListingCodeComparisonPanel setDescription("Set Navigate Next/Previous Area Marker options"); ActionState allAreaMarkers = - new ActionState<>(ALL_AREA_MARKERS, bothIcon, ALL_AREA_MARKERS); + new ActionState<>(ALL_AREA_MARKERS, BOTH_VIEWS_ICON, ALL_AREA_MARKERS); allAreaMarkers.setHelpLocation(helpLocation); ActionState unmatchedAreaMarkers = - new ActionState<>(UNMATCHED_AREA_MARKERS, unmatchedIcon, UNMATCHED_AREA_MARKERS); + new ActionState<>(UNMATCHED_AREA_MARKERS, UNMATCHED_ICON, UNMATCHED_AREA_MARKERS); unmatchedAreaMarkers.setHelpLocation(helpLocation); ActionState diffAreaMarkers = - new ActionState<>(DIFF_AREA_MARKERS, diffsIcon, DIFF_AREA_MARKERS); + new ActionState<>(DIFF_AREA_MARKERS, DIFF_ICON, DIFF_AREA_MARKERS); diffAreaMarkers.setHelpLocation(helpLocation); addActionState(allAreaMarkers); @@ -1406,7 +1408,7 @@ public class ListingCodeComparisonPanel String programStr = HTMLUtilities.friendlyEncodeHTML(program.getDomainFile().getPathname()); - String specialProgramStr = HTMLUtilities.colorString(Color.DARK_GRAY, programStr); + String specialProgramStr = HTMLUtilities.colorString(FG_COLOR_TITLE, programStr); buf.append(specialProgramStr); buf.append(padStr); } @@ -1441,7 +1443,7 @@ public class ListingCodeComparisonPanel String programStr = HTMLUtilities.friendlyEncodeHTML(program.getDomainFile().getPathname()); - String specialProgramStr = HTMLUtilities.colorString(Color.DARK_GRAY, programStr); + String specialProgramStr = HTMLUtilities.colorString(FG_COLOR_TITLE, programStr); buf.append(specialProgramStr); buf.append(padStr); } @@ -1461,7 +1463,7 @@ public class ListingCodeComparisonPanel String padStr = HTMLUtilities.spaces(4); buf.append(padStr); String programStr = HTMLUtilities.friendlyEncodeHTML(program.getDomainFile().getPathname()); - String specialProgramStr = HTMLUtilities.colorString(Color.DARK_GRAY, programStr); + String specialProgramStr = HTMLUtilities.colorString(FG_COLOR_TITLE, programStr); buf.append(specialProgramStr); buf.append(padStr); return HTMLUtilities.wrapAsHTML(buf.toString()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingComparisonProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingComparisonProvider.java index eee56d3eaa..1d37b0f2e4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingComparisonProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingComparisonProvider.java @@ -17,11 +17,11 @@ package ghidra.app.util.viewer.listingpanel; import javax.swing.Icon; +import generic.theme.GIcon; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.Program; -import resources.ResourceManager; /** * Provider for displaying a ListingCodeComparisonPanel. @@ -29,7 +29,7 @@ import resources.ResourceManager; public class ListingComparisonProvider extends ComponentProviderAdapter { private static final Icon DUAL_LISTING_ICON = - ResourceManager.loadImage("images/table_relationship.png"); + new GIcon("icon.base.util.listingcompare.provider"); private ListingCodeComparisonPanel dualListingPanel; /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingDiffActionManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingDiffActionManager.java index 408a2b1be0..749dd7f864 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingDiffActionManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingDiffActionManager.java @@ -19,11 +19,11 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.program.util.ListingDiff; import ghidra.util.HTMLUtilities; import ghidra.util.HelpLocation; import resources.MultiIcon; -import resources.ResourceManager; /** * Manages the actions that control a ListingDiff. @@ -31,15 +31,16 @@ import resources.ResourceManager; public class ListingDiffActionManager { private static final String HELP_TOPIC = "FunctionComparison"; - private static final Icon NOT_ICON = ResourceManager.loadImage("images/no_small.png"); - private static final Icon BYTE_DIFFS_ICON = ResourceManager.loadImage("images/binaryData.gif"); + + //@formatter:off + private static final Icon NOT_ICON = new GIcon("icon.base.util.listingdiff.diffs.not"); + private static final Icon BYTE_DIFFS_ICON = new GIcon("icon.base.util.listingdiff.diffs.byte"); private static final Icon NO_BYTE_DIFFS_ICON = new MultiIcon(BYTE_DIFFS_ICON, NOT_ICON); - private static final Icon DIFF_CONSTANTS_ICON = - ResourceManager.loadImage("images/class.png"); + private static final Icon DIFF_CONSTANTS_ICON = new GIcon("icon.base.util.listingdiff.diffs.constants"); private static final Icon IGNORE_CONSTANTS_ICON = new MultiIcon(DIFF_CONSTANTS_ICON, NOT_ICON); - private static final Icon DIFF_REGISTERS_ICON = - ResourceManager.loadImage("images/registerGroup.png"); + private static final Icon DIFF_REGISTERS_ICON = new GIcon("icon.base.util.listingdiff.diffs.registers"); private static final Icon IGNORE_REGISTERS_ICON = new MultiIcon(DIFF_REGISTERS_ICON, NOT_ICON); + //@formatter:on private static final String ACTION_GROUP = "A4_Diff"; private DockingAction toggleIgnoreByteDiffsAction; @@ -89,8 +90,8 @@ public class ListingDiffActionManager { ToggleIgnoreByteDiffsAction() { super("Toggle Ignore Byte Diffs", "DualListing"); - setDescription(HTMLUtilities.toHTML("If selected, difference highlights should\n" - + "ignore Byte differences.")); + setDescription(HTMLUtilities.toHTML( + "If selected, difference highlights should\n" + "ignore Byte differences.")); setEnabled(true); setPopupMenuData(new MenuData(new String[] { "Ignore Bytes As Differences" }, BYTE_DIFFS_ICON, @@ -117,8 +118,8 @@ public class ListingDiffActionManager { ToggleIgnoreConstantsAction() { super("Toggle Ignore Constants", "DualListing"); - setDescription(HTMLUtilities.toHTML("If selected, difference highlights should\n" - + "ignore operand Constants.")); + setDescription(HTMLUtilities.toHTML( + "If selected, difference highlights should\n" + "ignore operand Constants.")); setEnabled(true); setPopupMenuData(new MenuData( new String[] { "Ignore Operand Constants As Differences" }, @@ -146,8 +147,8 @@ public class ListingDiffActionManager { ToggleIgnoreRegisterNamesAction() { super("Toggle Ignore Register Names", "DualListing"); - setDescription(HTMLUtilities.toHTML("If selected, difference highlights should\n" - + "ignore operand Registers.")); + setDescription(HTMLUtilities.toHTML( + "If selected, difference highlights should\n" + "ignore operand Registers.")); setEnabled(true); setPopupMenuData(new MenuData( new String[] { "Ignore Operand Registers As Differences" }, diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java index fe7b5024ae..79937f2812 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java @@ -32,6 +32,7 @@ import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.listener.*; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexedScrollPane; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.plugin.core.codebrowser.LayeredColorModel; import ghidra.app.plugin.core.codebrowser.hover.ListingHoverService; import ghidra.app.services.ButtonPressedListener; @@ -349,7 +350,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc splitPaneDividerLocation = splitPane.getDividerLocation(); } JPanel resizeablePanel = new JPanel(new ScrollpanelResizeablePanelLayout(scroller)); - resizeablePanel.setBackground(Color.WHITE); + resizeablePanel.setBackground(Colors.BACKGROUND); resizeablePanel.add(resizeableMarginProvider.getComponent()); splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, resizeablePanel, scroller); splitPane.setDividerSize(4); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/PropertyBasedBackgroundColorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/PropertyBasedBackgroundColorModel.java index e754a0f45d..e4f96e4945 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/PropertyBasedBackgroundColorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/PropertyBasedBackgroundColorModel.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import docking.widgets.fieldpanel.support.BackgroundColorModel; +import generic.theme.GColor; import ghidra.app.util.viewer.util.AddressIndexMap; import ghidra.framework.model.DomainObjectChangedEvent; import ghidra.framework.model.DomainObjectListener; @@ -28,6 +29,7 @@ import ghidra.program.database.IntRangeMap; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.program.util.ChangeManager; +import ghidra.util.ColorUtils; /** * Default {@link BackgroundColorModel} for the ListingPanel where the color returned @@ -40,7 +42,7 @@ public class PropertyBasedBackgroundColorModel public static final String COLOR_PROPERTY_NAME = "LISTING_COLOR"; private IntRangeMap colorMap; private AddressIndexMap indexMap; - private Color defaultBackgroundColor = Color.WHITE; + private Color defaultBackgroundColor = new GColor("color.bg.listing"); private Map colorCache = new HashMap<>(); private Program program; private boolean enabled = false; @@ -93,7 +95,7 @@ public class PropertyBasedBackgroundColorModel } Color c = colorCache.get(value); if (c == null) { - c = new Color(value, true); + c = ColorUtils.getColor(value); colorCache.put(value, c); } return c; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ListingDisplayOptionsEditor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ListingDisplayOptionsEditor.java index 920fa05650..a2389af420 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ListingDisplayOptionsEditor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ListingDisplayOptionsEditor.java @@ -21,6 +21,7 @@ import java.beans.PropertyChangeListener; import javax.swing.JComponent; +import generic.theme.Gui; import ghidra.GhidraOptions; import ghidra.framework.options.*; @@ -28,7 +29,7 @@ import ghidra.framework.options.*; * Class for editing Listing display properties. */ public class ListingDisplayOptionsEditor implements OptionsEditor { - public static final Font DEFAULT_FONT = new Font("Monospaced", Font.PLAIN, 12); + public static final String DEFAULT_FONT_ID = "font.listing.base"; private OptionsGui optionsGui; private Options options; @@ -53,11 +54,11 @@ public class ListingDisplayOptionsEditor implements OptionsEditor { private void registerOptions() { String prefix = "Sets the "; - options.registerOption(GhidraOptions.OPTION_BASE_FONT, DEFAULT_FONT, null, - prefix + GhidraOptions.OPTION_BASE_FONT); + options.registerThemeFontBinding(GhidraOptions.OPTION_BASE_FONT, + DEFAULT_FONT_ID, null, prefix + GhidraOptions.OPTION_BASE_FONT); for (ScreenElement element : OptionsGui.elements) { String colorOptionName = element.getColorOptionName(); - options.registerOption(colorOptionName, element.getDefaultColor(), null, + options.registerThemeColorBinding(colorOptionName, element.getThemeColorId(), null, prefix + colorOptionName); String styleOptionName = element.getStyleOptionName(); options.registerOption(styleOptionName, -1, null, prefix + styleOptionName); @@ -68,7 +69,7 @@ public class ListingDisplayOptionsEditor implements OptionsEditor { public void apply() { if (optionsGui != null) { - Font font = options.getFont(GhidraOptions.OPTION_BASE_FONT, DEFAULT_FONT); + Font font = Gui.getFont(DEFAULT_FONT_ID); Font newFont = optionsGui.getBaseFont(); if (!newFont.equals(font)) { options.setFont(GhidraOptions.OPTION_BASE_FONT, newFont); @@ -123,7 +124,7 @@ public class ListingDisplayOptionsEditor implements OptionsEditor { @Override public JComponent getEditorComponent(Options editableOptions, EditorStateFactory editorStateFactory) { - Font font = options.getFont(GhidraOptions.OPTION_BASE_FONT, DEFAULT_FONT); + Font font = Gui.getFont(DEFAULT_FONT_ID); for (ScreenElement element : OptionsGui.elements) { Color c = options.getColor(element.getColorOptionName(), element.getDefaultColor()); int style = options.getInt(element.getStyleOptionName(), -1); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java index d6593229d3..e5d808ddb4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java @@ -35,6 +35,10 @@ import docking.widgets.fieldpanel.listener.LayoutModelListener; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexedScrollPane; import docking.widgets.label.GDLabel; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.GhidraOptions; import ghidra.util.SystemUtilities; @@ -43,100 +47,156 @@ import ghidra.util.SystemUtilities; */ public class OptionsGui extends JPanel { private static final long serialVersionUID = 1L; - private static final Color DARK_GREEN = new Color(0, 128, 0); - private static final Color BLUE_GREEN = new Color(0, 128, 64); - private static final Color DARK_BLUE = new Color(0, 0, 128); - private static final Color PALE_BLUE = new Color(128, 128, 255); - private static final Color YELLOW_ORANGE = new Color(155, 150, 50); - private static final Color PURPLE = new Color(155, 50, 155); - private static final Color DEEP_PURPLE = new Color(75, 0, 130); - private static final Color DARK_PURPLE = new Color(102, 0, 102); - private static final Color DARK_CYAN = new Color(0, 102, 102); - private static final Color DARK_ORANGE = new Color(255, 128, 0); - private static final Color DARK_RED = new Color(130, 0, 75); private static final Highlight[] NO_HIGHLIGHTS = new Highlight[0]; private static final HighlightFactory hlFactory = (field, text, cursorTextOffset) -> NO_HIGHLIGHTS; + public static final ScreenElement BACKGROUND = + new ScreenElement("Background", new GColor("color.bg.listing")); public static final ScreenElement COMMENT_AUTO = - new ScreenElement("Comment, Automatic", Color.LIGHT_GRAY); - public static final ScreenElement ADDRESS = new ScreenElement("Address", Color.BLACK); - public static final ScreenElement BACKGROUND = new ScreenElement("Background", Color.WHITE); + new ScreenElement("Comment, Automatic", new GColor("color.fg.listing.comment.auto")); + public static final ScreenElement ADDRESS = + new ScreenElement("Address", new GColor("color.fg.listing.address")); + public static final ScreenElement BAD_REF_ADDR = - new ScreenElement("Bad Reference Address", Color.RED); - public static final ScreenElement BYTES = new ScreenElement("Bytes", Color.BLUE); - public static final ScreenElement CONSTANT = new ScreenElement("Constant", BLUE_GREEN); - public static final ScreenElement LABELS_UNREFD = - new ScreenElement("Labels, Unreferenced", Color.BLACK); - public static final ScreenElement ENTRY_POINT = new ScreenElement("Entry Point", Color.MAGENTA); - public static final ScreenElement COMMENT_EOL = - new ScreenElement("Comment, EOL", "EOL Comment", Color.BLUE); - public static final ScreenElement EXT_REF_RESOLVED = - new ScreenElement("External Reference, Resolved", Color.CYAN.darker().darker()); - public static final ScreenElement FIELD_NAME = new ScreenElement("Field Name", Color.BLACK); + new ScreenElement("Bad Reference Address", new GColor("color.fg.listing.ref.bad")); + + public static final ScreenElement BYTES = + new ScreenElement("Bytes", new GColor("color.fg.listing.bytes")); + + public static final ScreenElement CONSTANT = + new ScreenElement("Constant", new GColor("color.fg.listing.constant")); + + public static final ScreenElement LABELS_UNREFD = new ScreenElement("Labels, Unreferenced", + new GColor("color.fg.listing.label.unreferenced")); + + public static final ScreenElement ENTRY_POINT = + new ScreenElement("Entry Point", new GColor("color.fg.listing.entrypoint")); + + public static final ScreenElement COMMENT_EOL = new ScreenElement("Comment, EOL", "EOL Comment", + new GColor("color.fg.listing.comment.auto")); + + public static final ScreenElement EXT_REF_RESOLVED = new ScreenElement( + "External Reference, Resolved", new GColor("color.fg.listing.ref.ext.resolved")); + + public static final ScreenElement FIELD_NAME = + new ScreenElement("Field Name", new GColor("color.fg.listing.fieldname")); + public static final ScreenElement FUN_CALL_FIXUP = - new ScreenElement("Function Call-Fixup", new Color(255, 0, 204)); - public static final ScreenElement FUN_NAME = new ScreenElement("Function Name", Color.BLUE); + new ScreenElement("Function Call-Fixup", new GColor("color.fg.listing.function.callfixup")); + + public static final ScreenElement FUN_NAME = + new ScreenElement("Function Name", new GColor("color.fg.listing.function.name")); + public static final ScreenElement FUN_PARAMS = - new ScreenElement("Function Parameters", Color.BLACK); - public static final ScreenElement FUN_TAG = new ScreenElement("Function Tag", DARK_RED); - public static final ScreenElement FUN_AUTO_PARAMS = - new ScreenElement("Function Auto-Parameters", Color.GRAY); - public static final ScreenElement FUN_RET_TYPE = - new ScreenElement("Function Return Type", Color.BLACK); + new ScreenElement("Function Parameters", new GColor("color.fg.listing.function.param")); + + public static final ScreenElement FUN_TAG = + new ScreenElement("Function Tag", new GColor("color.fg.listing.function.tag")); + + public static final ScreenElement FUN_AUTO_PARAMS = new ScreenElement( + "Function Auto-Parameters", new GColor("color.fg.listing.function.param.auto")); + + public static final ScreenElement FUN_RET_TYPE = new ScreenElement("Function Return Type", + new GColor("color.fg.listing.function.return.type")); + public static final ScreenElement COMMENT_REPEATABLE = - new ScreenElement("Comment, Repeatable", DARK_ORANGE); - public static final ScreenElement COMMENT_REF_REPEAT = - new ScreenElement("Comment, Referenced Repeatable", new Color(190, 190, 255)); - public static final ScreenElement LABELS_LOCAL = new ScreenElement("Labels, Local", BLUE_GREEN); + new ScreenElement("Comment, Repeatable", new GColor("color.fg.listing.comment.repeatable")); + + public static final ScreenElement COMMENT_REF_REPEAT = new ScreenElement( + "Comment, Referenced Repeatable", new GColor("color.fg.listing.comment.ref.repeatable")); + + public static final ScreenElement LABELS_LOCAL = + new ScreenElement("Labels, Local", new GColor("color.fg.listing.label.local")); + public static final ScreenElement MNEMONIC_OVERRIDE = - new ScreenElement("Mnemonic, Override", new Color(255, 0, 204)); - public static final ScreenElement MNEMONIC = new ScreenElement("Mnemonic", DARK_BLUE); - public static final ScreenElement UNIMPL = - new ScreenElement("Unimplemented Mnemonic", Color.RED); - public static final ScreenElement FLOW_ARROW_NON_ACTIVE = - new ScreenElement("Flow Arrow, Not Active", new Color(160, 160, 160)); + new ScreenElement("Mnemonic, Override", new GColor("color.fg.listing.mnemonic.override")); + + public static final ScreenElement MNEMONIC = + new ScreenElement("Mnemonic", new GColor("color.fg.listing.mnemonic")); + + public static final ScreenElement UNIMPL = new ScreenElement("Unimplemented Mnemonic", + new GColor("color.fg.listing.mnemonic.unimplemented")); + + public static final ScreenElement FLOW_ARROW_NON_ACTIVE = new ScreenElement( + "Flow Arrow, Not Active", new GColor("color.fg.listing.flow.arrow.inactive")); + public static final ScreenElement FLOW_ARROW_ACTIVE = - new ScreenElement("Flow Arrow, Active", Color.BLACK); - public static final ScreenElement FLOW_ARROW_SELECTED = - new ScreenElement("Flow Arrow, Selected", new Color(0, 200, 0)); + new ScreenElement("Flow Arrow, Active", new GColor("color.fg.listing.flow.arrow.active")); + + public static final ScreenElement FLOW_ARROW_SELECTED = new ScreenElement( + "Flow Arrow, Selected", new GColor("color.fg.listing.flow.arrow.selected")); + public static final ScreenElement LABELS_NON_PRIMARY = - new ScreenElement("Labels, Non-primary", YELLOW_ORANGE); - public static final ScreenElement COMMENT_PLATE = - new ScreenElement("Comment, Plate", "Plate Comment", Color.GRAY); - public static final ScreenElement COMMENT_POST = - new ScreenElement("Comment, Post", "Post-Comment", Color.BLUE); - public static final ScreenElement COMMENT_PRE = - new ScreenElement("Comment, Pre", "Pre-Comment", DEEP_PURPLE); + new ScreenElement("Labels, Non-primary", new GColor("color.fg.listing.label.non.primary")); + + public static final ScreenElement COMMENT_PLATE = new ScreenElement("Comment, Plate", + "Plate Comment", new GColor("color.fg.listing.comment.plate")); + + public static final ScreenElement COMMENT_POST = new ScreenElement("Comment, Post", + "Post-Comment", new GColor("color.fg.listing.comment.post")); + + public static final ScreenElement COMMENT_PRE = new ScreenElement("Comment, Pre", "Pre-Comment", + new GColor("color.fg.listing.comment.pre")); + public static final ScreenElement LABELS_PRIMARY = - new ScreenElement("Labels, Primary", DARK_BLUE); - public static final ScreenElement SEPARATOR = new ScreenElement("Separator", Color.BLACK); - public static final ScreenElement VARIABLE = new ScreenElement("Variable", PURPLE); - public static final ScreenElement PARAMETER_CUSTOM = - new ScreenElement("Parameter, Custom Storage", DARK_PURPLE); - public static final ScreenElement PARAMETER_DYNAMIC = - new ScreenElement("Parameter, Dynamic Storage", DARK_CYAN); - public static final ScreenElement VERSION_TRAK = new ScreenElement("Version Track", PURPLE); - public static final ScreenElement XREF = new ScreenElement("XRef", DARK_GREEN); - public static final ScreenElement XREF_OFFCUT = new ScreenElement("XRef, Offcut", Color.GRAY); - public static final ScreenElement XREF_READ = new ScreenElement("XRef Read", Color.BLUE); - public static final ScreenElement XREF_WRITE = new ScreenElement("XRef Write", DARK_ORANGE); - public static final ScreenElement XREF_OTHER = new ScreenElement("XRef Other", Color.BLACK); - public static final ScreenElement REGISTERS = new ScreenElement("Registers", YELLOW_ORANGE); - public static final ScreenElement UNDERLINE = new ScreenElement("Underline", PALE_BLUE); + new ScreenElement("Labels, Primary", new GColor("color.fg.listing.label.primary")); + + public static final ScreenElement SEPARATOR = + new ScreenElement("Separator", new GColor("color.fg.listing.separator")); + + public static final ScreenElement VARIABLE = + new ScreenElement("Variable", new GColor("color.fg.listing.variable")); + + public static final ScreenElement PARAMETER_CUSTOM = new ScreenElement( + "Parameter, Custom Storage", new GColor("color.fg.listing.function.param.custom")); + + public static final ScreenElement PARAMETER_DYNAMIC = new ScreenElement( + "Parameter, Dynamic Storage", new GColor("color.fg.listing.function.param.dynamic")); + + public static final ScreenElement VERSION_TRAK = + new ScreenElement("Version Track", new GColor("color.fg.listing.version.tracking")); + + public static final ScreenElement XREF = + new ScreenElement("XRef", new GColor("color.fg.listing.xref")); + + public static final ScreenElement XREF_OFFCUT = + new ScreenElement("XRef, Offcut", new GColor("color.fg.listing.xref.offcut")); + + public static final ScreenElement XREF_READ = + new ScreenElement("XRef Read", new GColor("color.fg.listing.xref.read")); + + public static final ScreenElement XREF_WRITE = + new ScreenElement("XRef Write", new GColor("color.fg.listing.xref.write")); + + public static final ScreenElement XREF_OTHER = + new ScreenElement("XRef Other", new GColor("color.fg.listing.xref.other")); + + public static final ScreenElement REGISTERS = + new ScreenElement("Registers", new GColor("color.fg.listing.register")); + + public static final ScreenElement UNDERLINE = + new ScreenElement("Underline", new GColor("color.fg.listing.underline")); + public static final ScreenElement PCODE_LINE_LABEL = - new ScreenElement("P-code Line Label", Color.BLUE); + new ScreenElement("P-code Line Label", new GColor("color.fg.listing.pcode.label")); + public static final ScreenElement PCODE_ADDR_SPACE = - new ScreenElement("P-code Address Space", Color.BLUE); + new ScreenElement("P-code Address Space", new GColor("color.fg.listing.pcode.space")); + public static final ScreenElement PCODE_RAW_VARNODE = - new ScreenElement("P-code Raw Varnode", Color.BLUE); + new ScreenElement("P-code Raw Varnode", new GColor("color.fg.listing.pcode.varnode")); + public static final ScreenElement PCODE_USEROP = - new ScreenElement("P-code Userop", Color.BLUE); + new ScreenElement("P-code Userop", new GColor("color.fg.listing.pcode.userop")); + + //@formatter:on static ScreenElement[] elements = { ADDRESS, BACKGROUND, BAD_REF_ADDR, BYTES, COMMENT_AUTO, COMMENT_EOL, COMMENT_PLATE, COMMENT_POST, COMMENT_PRE, COMMENT_REPEATABLE, COMMENT_REF_REPEAT, CONSTANT, ENTRY_POINT, EXT_REF_RESOLVED, FIELD_NAME, FLOW_ARROW_ACTIVE, - FLOW_ARROW_NON_ACTIVE, FUN_CALL_FIXUP, FUN_NAME, FUN_PARAMS, FUN_AUTO_PARAMS, FUN_RET_TYPE, + FLOW_ARROW_NON_ACTIVE, FLOW_ARROW_SELECTED, FUN_CALL_FIXUP, FUN_NAME, FUN_PARAMS, + FUN_AUTO_PARAMS, FUN_RET_TYPE, FUN_TAG, LABELS_LOCAL, LABELS_NON_PRIMARY, LABELS_PRIMARY, LABELS_UNREFD, MNEMONIC, MNEMONIC_OVERRIDE, PARAMETER_CUSTOM, PARAMETER_DYNAMIC, PCODE_LINE_LABEL, PCODE_ADDR_SPACE, PCODE_RAW_VARNODE, PCODE_USEROP, REGISTERS, SEPARATOR, UNDERLINE, UNIMPL, VARIABLE, @@ -274,18 +334,12 @@ public class OptionsGui extends JPanel { } } - /** - * Sets the base font to be used by the fields. - */ public void setBaseFont(Font font) { baseFont = font; baseMetrics = getFontMetrics(font); metricsMap.clear(); } - /** - * Returns the current base font. - */ public Font getBaseFont() { return baseFont; } @@ -353,13 +407,13 @@ public class OptionsGui extends JPanel { GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment(); String envfonts[] = gEnv.getAvailableFontFamilyNames(); fontNameField = new GComboBox<>(envfonts); - fontNameField.setBackground(Color.white); + fontNameField.setBackground(Colors.BACKGROUND); fontNameField.setRenderer(new FontRenderer()); panel1.add(fontNameField); fontSizeField = new GComboBox<>(IntStream.rangeClosed(6, 32).boxed().toArray(Integer[]::new)); - fontSizeField.setBackground(Color.white); + fontSizeField.setBackground(Colors.BACKGROUND); panel1.add(fontSizeField); panel.add(panel1, BorderLayout.NORTH); @@ -377,8 +431,8 @@ public class OptionsGui extends JPanel { //Displays the font field with the actual fonts for easier selection class FontRenderer extends GDLabel implements ListCellRenderer { - private static final long serialVersionUID = 1L; - private final Color SELECTED_COLOR = new Color(10, 36, 106); + + private final Color SELECTED_COLOR = Palette.getColor("darkslategray"); public FontRenderer() { setOpaque(true); @@ -391,8 +445,8 @@ public class OptionsGui extends JPanel { Font origFont = fontNameField.getFont(); setFont(new Font(value.toString(), origFont.getStyle(), origFont.getSize())); - setBackground(isSelected ? SELECTED_COLOR : Color.white); - setForeground(isSelected ? Color.white : Color.black); + setBackground(isSelected ? SELECTED_COLOR : Colors.BACKGROUND); + setForeground(isSelected ? Tables.FG_SELECTED : Tables.FG_UNSELECTED); return this; } @@ -420,7 +474,7 @@ public class OptionsGui extends JPanel { subPanel = new JPanel(new BorderLayout()); subPanel.setBorder(BorderFactory.createTitledBorder(border, "Color")); colorPanel = new JPanel(); - colorPanel.setBackground(Color.white); + colorPanel.setBackground(Colors.BACKGROUND); subPanel.add(colorPanel, BorderLayout.CENTER); panel.add(subPanel, BorderLayout.NORTH); return panel; @@ -790,6 +844,7 @@ public class OptionsGui extends JPanel { size = (Integer) fontSizeField.getSelectedItem(); } catch (Exception e) { + // handled below } if (size < 6) { @@ -824,9 +879,6 @@ public class OptionsGui extends JPanel { return false; } - /** - * Returns a layout for the given index. - */ public Layout getLayout(int index) { return layouts[index]; } @@ -843,6 +895,7 @@ public class OptionsGui extends JPanel { @Override public void flushChanges() { + // stub } @Override @@ -901,9 +954,6 @@ public class OptionsGui extends JPanel { add(text, element, false); } - /** - * Adds the string and adorns it based on the given type (display index) - */ void add(String text, ScreenElement element, boolean underline) { // add some padding to push off of the edge @@ -928,9 +978,6 @@ public class OptionsGui extends JPanel { } } - /** - * Returns a layout consisting of all the added text fields. - */ Layout getLayout() { return new SingleRowLayout(fields); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ScreenElement.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ScreenElement.java index e701f15721..7068c80096 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ScreenElement.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/ScreenElement.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,52 +17,65 @@ package ghidra.app.util.viewer.options; import java.awt.Color; +import generic.theme.GColor; public class ScreenElement { private String name; private String optionsName; private Color color; - private Color defaultColor; + private GColor defaultColor; private int style; - - ScreenElement(String name, Color defaultColor) { + + ScreenElement(String name, GColor defaultColor) { this(name, name, defaultColor); } - - ScreenElement(String name, String optionsName, Color defaultColor) { + + ScreenElement(String name, String optionsName, GColor defaultColor) { this.name = name; this.optionsName = optionsName; this.defaultColor = defaultColor; this.color = defaultColor; this.style = -1; } - + + public String getThemeColorId() { + return defaultColor.getId(); + } + public String getName() { return name; } + public Color getColor() { return color; } + public int getStyle() { return style; } + public Color getDefaultColor() { return defaultColor; } + public void setColor(Color color) { this.color = color; } + public void setStyle(int style) { this.style = style; } + public String getColorOptionName() { return optionsName + " Color"; } + public String getStyleOptionName() { - return optionsName+ " Style"; + return optionsName + " Style"; } + @Override - public String toString() { + public String toString() { return name; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/CodeComparisonPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/CodeComparisonPanel.java index 02e9d9a78d..220b96eba4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/CodeComparisonPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/util/CodeComparisonPanel.java @@ -26,6 +26,7 @@ import docking.ComponentProvider; import docking.action.DockingAction; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.internal.FieldPanelCoordinator; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.functioncompare.FunctionComparisonPanel; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.AddressSet; @@ -40,8 +41,8 @@ import ghidra.util.classfinder.ExtensionPoint; * form of comparing two sections of code within the same or different programs *

* NOTE: ALL CodeComparisonPanel CLASSES MUST END IN - * CodeComparisonPanel so they are discoverable by the - * {@link ClassSearcher} + * CodeComparisonPanel so they are discoverable by the {@link ClassSearcher} + * @param the type */ public abstract class CodeComparisonPanel extends JPanel implements ExtensionPoint, FocusListener { @@ -52,9 +53,9 @@ public abstract class CodeComparisonPanel exten protected static final int LEFT = 0; protected static final int RIGHT = 1; - private static final Color BUBBLE_GUM_PINK_COLOR = new Color(0xff, 0xa5, 0xa5); + private static final Color FOCUS_BORDER_COLOR = Palette.getColor("lightpink"); protected static final Border FOCUS_BORDER = - BorderFactory.createMatteBorder(3, 3, 3, 3, BUBBLE_GUM_PINK_COLOR); + BorderFactory.createMatteBorder(3, 3, 3, 3, FOCUS_BORDER_COLOR); protected static final Border NON_FOCUS_BORDER = BorderFactory.createEmptyBorder(3, 3, 3, 3); protected static final AddressSetView EMPTY_ADDRESS_SET = new AddressSet(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java index d5887d3869..9592040821 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/FunctionsXmlMgr.java @@ -15,11 +15,12 @@ */ package ghidra.app.util.xml; -import java.awt.Color; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.cmd.function.*; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.NamespaceUtils; @@ -39,7 +40,6 @@ import ghidra.util.task.TaskMonitor; import ghidra.util.xml.*; import ghidra.xml.XmlElement; import ghidra.xml.XmlPullParser; -import resources.ResourceManager; class FunctionsXmlMgr { public final static String LIB_BOOKMARK_CATEGORY = "Library Identification"; @@ -127,9 +127,9 @@ class FunctionsXmlMgr { BookmarkManager bm = program.getBookmarkManager(); BookmarkType bt = bm.getBookmarkType("IMPORTED"); if (bt == null) { - ImageIcon icon = - ResourceManager.loadImage("images/imported_bookmark.gif"); - bt = bm.defineType("IMPORTED", icon, Color.DARK_GRAY, 0); + Icon icon = new GIcon("icon.base.util.xml.functions.bookmark"); + bt = bm.defineType("IMPORTED", icon, Palette.DARK_GRAY, + 0); } bm.setBookmark(entryPoint, "IMPORTED", LIB_BOOKMARK_CATEGORY, "Library function"); @@ -680,7 +680,7 @@ class FunctionsXmlMgr { private Parameter[] getRegisterParameters(Function function) { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); Parameter[] params = function.getParameters(); for (Parameter param : params) { if (param.isRegisterVariable()) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/PropertiesXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/PropertiesXmlMgr.java index 9d2cb81b83..da9d7c41c2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/PropertiesXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/PropertiesXmlMgr.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +15,6 @@ */ package ghidra.app.util.xml; -import ghidra.app.util.importer.MessageLog; -import ghidra.framework.options.*; -import ghidra.program.model.address.*; -import ghidra.program.model.listing.*; -import ghidra.program.model.util.*; -import ghidra.util.XmlProgramUtilities; -import ghidra.util.exception.*; -import ghidra.util.task.TaskMonitor; -import ghidra.util.xml.*; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; - import java.awt.Color; import java.awt.Font; import java.io.File; @@ -37,6 +24,19 @@ import javax.swing.KeyStroke; import org.xml.sax.SAXParseException; +import ghidra.app.util.importer.MessageLog; +import ghidra.framework.options.*; +import ghidra.program.model.address.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.util.*; +import ghidra.util.ColorUtils; +import ghidra.util.XmlProgramUtilities; +import ghidra.util.exception.*; +import ghidra.util.task.TaskMonitor; +import ghidra.util.xml.*; +import ghidra.xml.XmlElement; +import ghidra.xml.XmlPullParser; + class PropertiesXmlMgr { private final static String PROPERTY_LIST_CATEGORY_DELIMITER = Options.DELIMITER_STRING; @@ -209,7 +209,8 @@ class PropertiesXmlMgr { String listName = getPropertyList(pathname); String name = getPropertyName(pathname); if (listName == null || name == null) { - log.appendMsg("Property NAME attribute must contain both category prefix and property name"); + log.appendMsg( + "Property NAME attribute must contain both category prefix and property name"); return; } Options list = program.getOptions(listName); @@ -253,7 +254,8 @@ class PropertiesXmlMgr { list.setDate(name, new Date(value)); } else if ("color".equals(type)) { - Color color = new Color(XmlUtilities.parseInt(element.getAttribute("VALUE"))); + Color color = + ColorUtils.getColor(XmlUtilities.parseInt(element.getAttribute("VALUE"))); list.setColor(name, color); } else if ("file".equals(type)) { @@ -311,7 +313,8 @@ class PropertiesXmlMgr { // XML WRITE CURRENT DTD // /////////////////////////////////////////////////////////////////////////////////////// - void write(XmlWriter writer, AddressSetView set, TaskMonitor monitor) throws CancelledException { + void write(XmlWriter writer, AddressSetView set, TaskMonitor monitor) + throws CancelledException { monitor.setMessage("Writing PROPERTIES ..."); writer.startElement("PROPERTIES"); writePropertyMaps(writer, set, monitor); @@ -323,11 +326,11 @@ class PropertiesXmlMgr { throws CancelledException { List listNames = program.getOptionsNames(); Collections.sort(listNames); - for (int i = 0; i < listNames.size(); i++) { - Options propList = program.getOptions(listNames.get(i)); + for (String listName : listNames) { + Options propList = program.getOptions(listName); List propNames = propList.getOptionNames(); Collections.sort(propNames); - String prefix = listNames.get(i) + PROPERTY_LIST_CATEGORY_DELIMITER; + String prefix = listName + PROPERTY_LIST_CATEGORY_DELIMITER; for (String name : propNames) { if (monitor.isCancelled()) { throw new CancelledException(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/base/actions/HorizontalRuleAction.java b/Ghidra/Features/Base/src/main/java/ghidra/base/actions/HorizontalRuleAction.java index 7dc1aef5d9..e2f70ef438 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/base/actions/HorizontalRuleAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/base/actions/HorizontalRuleAction.java @@ -18,6 +18,7 @@ package ghidra.base.actions; import docking.ActionContext; import docking.action.DockingAction; import docking.action.MenuData; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.util.HTMLUtilities; /** @@ -41,7 +42,8 @@ public class HorizontalRuleAction extends DockingAction { markHelpUnnecessary(); // The menu name is both names, one over the other, in a small, light grayish font. - setMenuBarData(new MenuData(new String[] { "

" + + setMenuBarData(new MenuData(new String[] { "
" + fixupFirstAmp( HTMLUtilities.escapeHTML(topName) + "
" + HTMLUtilities.escapeHTML(bottomName)) + "
" })); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/base/help/GhidraHelpService.java b/Ghidra/Features/Base/src/main/java/ghidra/base/help/GhidraHelpService.java index 320d271455..2e6d4f3c34 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/base/help/GhidraHelpService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/base/help/GhidraHelpService.java @@ -22,8 +22,10 @@ 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; import ghidra.util.Msg; import help.HelpService; @@ -35,7 +37,14 @@ 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(); public static void install() { try { @@ -50,6 +59,7 @@ public class GhidraHelpService extends HelpManager { super(findMasterHelpSetUrl()); loadHelpSets(); registerHelp(); + Gui.addThemeListener(listener); } private static URL findMasterHelpSetUrl() { @@ -65,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> helpSetsByModule = findHelpSetsByModule(); @@ -116,4 +131,13 @@ public class GhidraHelpService extends HelpManager { return results; } + + class HelpThemeListener implements ThemeListener { + @Override + public void themeChanged(ThemeEvent event) { + if (event.isLookAndFeelChanged()) { + reload(); + } + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemProbeConflictResolver.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemProbeConflictResolver.java index dbc3e1ab60..73b4ff3422 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemProbeConflictResolver.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/FileSystemProbeConflictResolver.java @@ -17,6 +17,7 @@ package ghidra.formats.gfilesystem; import java.util.List; +import docking.widgets.SelectFromListDialog; import ghidra.formats.gfilesystem.factory.FileSystemInfoRec; /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/GhidraApplicationConfiguration.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/GhidraApplicationConfiguration.java index 25aa525ef2..c39a1351b2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/GhidraApplicationConfiguration.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/GhidraApplicationConfiguration.java @@ -15,16 +15,13 @@ */ package ghidra.framework; -import java.awt.Taskbar; -import java.awt.Toolkit; -import java.lang.reflect.Field; - import docking.DockingErrorDisplay; import docking.DockingWindowManager; import docking.framework.ApplicationInformationDisplayFactory; import docking.framework.SplashScreen; import docking.widgets.PopupKeyStorePasswordProvider; -import ghidra.docking.util.DockingWindowsLookAndFeelUtils; +import generic.theme.ApplicationThemeManager; +import ghidra.docking.util.LookAndFeelUtils; import ghidra.formats.gfilesystem.crypto.CryptoProviders; import ghidra.formats.gfilesystem.crypto.PopupGUIPasswordProvider; import ghidra.framework.main.GhidraApplicationInformationDisplayFactory; @@ -33,6 +30,7 @@ import ghidra.framework.preferences.Preferences; import ghidra.net.ApplicationKeyManagerFactory; import ghidra.util.ErrorDisplay; import ghidra.util.SystemUtilities; +import ghidra.util.task.TaskMonitorAdapter; public class GhidraApplicationConfiguration extends HeadlessGhidraApplicationConfiguration { @@ -46,34 +44,22 @@ public class GhidraApplicationConfiguration extends HeadlessGhidraApplicationCon @Override protected void initializeApplication() { - - DockingWindowsLookAndFeelUtils.loadFromPreferences(); - - platformSpecificFixups(); + ApplicationThemeManager.initialize(); + LookAndFeelUtils.performPlatformSpecificFixups(); if (showSplashScreen) { showUserAgreement(); SplashScreen.showSplashScreen(); + this.monitor = new StatusReportingTaskMonitor(); } super.initializeApplication(); - ApplicationKeyManagerFactory.setKeyStorePasswordProvider( - new PopupKeyStorePasswordProvider()); + ApplicationKeyManagerFactory + .setKeyStorePasswordProvider(new PopupKeyStorePasswordProvider()); CryptoProviders.getInstance().registerCryptoProvider(new PopupGUIPasswordProvider()); } - private static void platformSpecificFixups() { - - // Set the dock icon for macOS - if (Taskbar.isTaskbarSupported()) { - Taskbar taskbar = Taskbar.getTaskbar(); - if (taskbar.isSupported(Taskbar.Feature.ICON_IMAGE)) { - taskbar.setIconImage(ApplicationInformationDisplayFactory.getLargestWindowIcon()); - } - } - } - private static void showUserAgreement() { String value = Preferences.getProperty(USER_AGREEMENT_PROPERTY_NAME); if ("ACCEPT".equals(value)) { @@ -105,4 +91,17 @@ public class GhidraApplicationConfiguration extends HeadlessGhidraApplicationCon public ErrorDisplay getErrorDisplay() { return new DockingErrorDisplay(); } + + private static class StatusReportingTaskMonitor extends TaskMonitorAdapter { + @Override + public synchronized void setCancelEnabled(boolean enable) { + // Not permitted + } + + @Override + public void setMessage(String message) { + SplashScreen.updateSplashScreenStatus(message); + } + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/ConsoleTextPane.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/ConsoleTextPane.java index 4c9212a952..77891c21ae 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/ConsoleTextPane.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/ConsoleTextPane.java @@ -15,13 +15,15 @@ */ package ghidra.framework.main; -import java.awt.Color; import java.awt.Font; import java.util.LinkedList; import javax.swing.JTextPane; import javax.swing.text.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Ids.Fonts; +import generic.theme.Gui; import ghidra.framework.options.*; import ghidra.framework.plugintool.PluginTool; import ghidra.util.Msg; @@ -113,7 +115,8 @@ public class ConsoleTextPane extends JTextPane implements OptionsChangeListener private void updateFromOptions(Options options) { int newLimit = options.getInt(MAXIMUM_CHARACTERS_OPTION_NAME, DEFAULT_MAXIMUM_CHARS); - truncationFactor = options.getDouble(TRUNCATION_FACTOR_OPTION_NAME, DEFAULT_TRUNCATION_FACTOR); + truncationFactor = + options.getDouble(TRUNCATION_FACTOR_OPTION_NAME, DEFAULT_TRUNCATION_FACTOR); setMaximumCharacterLimit(newLimit); } @@ -141,7 +144,7 @@ public class ConsoleTextPane extends JTextPane implements OptionsChangeListener private void doAddMessage(MessageWrapper newMessage) { synchronized (messageList) { - if ( !messageList.isEmpty() ) { + if (!messageList.isEmpty()) { MessageWrapper lastMessage = messageList.getLast(); if (lastMessage.merge(newMessage)) { return; @@ -201,7 +204,7 @@ public class ConsoleTextPane extends JTextPane implements OptionsChangeListener } private void createAttribtues() { - createAttributes(new Font("monospaced", Font.PLAIN, 12)); + createAttributes(Gui.getFont(Fonts.MONOSPACED)); } private void createAttributes(Font font) { @@ -211,7 +214,8 @@ public class ConsoleTextPane extends JTextPane implements OptionsChangeListener outputAttributeSet.addAttribute(StyleConstants.FontSize, font.getSize()); outputAttributeSet.addAttribute(StyleConstants.Italic, font.isItalic()); outputAttributeSet.addAttribute(StyleConstants.Bold, font.isBold()); - outputAttributeSet.addAttribute(StyleConstants.Foreground, Color.BLACK); + outputAttributeSet.addAttribute(StyleConstants.Foreground, + new GColor("color.fg.consoletextpane")); errorAttributeSet = new SimpleAttributeSet(); errorAttributeSet.addAttribute(CUSTOM_ATTRIBUTE_KEY, ERROR_ATTRIBUTE_VALUE); @@ -219,7 +223,8 @@ public class ConsoleTextPane extends JTextPane implements OptionsChangeListener errorAttributeSet.addAttribute(StyleConstants.FontSize, font.getSize()); errorAttributeSet.addAttribute(StyleConstants.Italic, font.isItalic()); errorAttributeSet.addAttribute(StyleConstants.Bold, font.isBold()); - errorAttributeSet.addAttribute(StyleConstants.Foreground, Color.RED); + errorAttributeSet.addAttribute(StyleConstants.Foreground, + new GColor("color.fg.error.consoletextpane")); } private void doUpdate() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/GhidraApplicationInformationDisplayFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/GhidraApplicationInformationDisplayFactory.java index dd073093a0..6503315e3e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/GhidraApplicationInformationDisplayFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/GhidraApplicationInformationDisplayFactory.java @@ -19,13 +19,13 @@ import java.awt.Image; import java.util.ArrayList; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JComponent; import docking.framework.ApplicationInformationDisplayFactory; +import generic.theme.GIcon; import ghidra.app.util.GenericHelpTopics; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class GhidraApplicationInformationDisplayFactory extends ApplicationInformationDisplayFactory { @@ -33,17 +33,21 @@ public class GhidraApplicationInformationDisplayFactory @Override protected List doGetWindowIcons() { List list = new ArrayList<>(); - list.add(ResourceManager.loadImage("images/GhidraIcon16.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon24.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon32.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon40.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon48.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon64.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon128.png").getImage()); - list.add(ResourceManager.loadImage("images/GhidraIcon256.png").getImage()); + list.add(image("icon.base.application.16")); + list.add(image("icon.base.application.24")); + list.add(image("icon.base.application.32")); + list.add(image("icon.base.application.40")); + list.add(image("icon.base.application.48")); + list.add(image("icon.base.application.64")); + list.add(image("icon.base.application.128")); + list.add(image("icon.base.application.256")); return list; } + private Image image(String id) { + return new GIcon(id).getImageIcon().getImage(); + } + @Override protected String doCreateSplashScreenTitle() { return "Welcome To Ghidra"; @@ -65,8 +69,8 @@ public class GhidraApplicationInformationDisplayFactory } @Override - public ImageIcon doGetHomeIcon() { - return ResourceManager.loadImage("images/GhidraIcon16.png"); + public Icon doGetHomeIcon() { + return new GIcon("icon.base.application.home"); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/InfoPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/InfoPanel.java index 2e27f4e91e..d88f0b2c28 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/InfoPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/InfoPanel.java @@ -27,6 +27,8 @@ import javax.swing.text.View; import docking.DockingUtils; import docking.widgets.*; import docking.widgets.label.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.WindowUtilities; import ghidra.framework.Application; import ghidra.framework.ApplicationProperties; @@ -36,13 +38,10 @@ import resources.ResourceManager; import utilities.util.FileUtilities; /** - * Window to display version information about the current release of - * the ghidra application. + * Window to display version information about the current release of the application. */ class InfoPanel extends JPanel { - private final static Color RED = new Color(199, 0, 0); - private final static int MARGIN = 10; private String version; @@ -58,7 +57,7 @@ class InfoPanel extends JPanel { InfoPanel() { getAboutInfo(); - bgColor = new Color(243, 250, 255); + bgColor = new GColor("color.bg.splash.infopanel"); create(); } @@ -129,7 +128,7 @@ class InfoPanel extends JPanel { private Component buildMarkingLabel() { MultiLineLabel markingLabel = new MultiLineLabel(marking, 0, 3, MultiLineLabel.CENTER); - markingLabel.setForeground(RED); + markingLabel.setForeground(Palette.RED); return markingLabel; } @@ -144,7 +143,7 @@ class InfoPanel extends JPanel { private Component buildTestBuildLabel() { MultiLineLabel testLabel = new MultiLineLabel("-- UNSUPPORTED TEST BUILD --", 0, 3, MultiLineLabel.CENTER); - testLabel.setForeground(RED); + testLabel.setForeground(Palette.RED); return testLabel; } @@ -174,7 +173,7 @@ class InfoPanel extends JPanel { Font font = versionLabel.getFont(); font = font.deriveFont(14f).deriveFont(Font.BOLD); versionLabel.setFont(font); - versionLabel.setForeground(Color.BLACK); + versionLabel.setForeground(new GColor("color.fg.infopanel.version")); return versionLabel; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java index 012820e7e9..81d3e4fcc7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/VersionControlDataTypeArchiveUndoCheckoutAction.java @@ -19,9 +19,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datamgr.archive.*; import ghidra.app.plugin.core.datamgr.editor.DataTypeEditorManager; @@ -34,13 +35,15 @@ import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.Task; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * Action to undo checkouts for domain files in the repository. */ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionControlAction { + private static final Icon ICON = + new GIcon("icon.base.util.datatree.version.control.archive.dt.checkout.undo"); + private DataTypeManagerPlugin dtmPlugin; private ArchiveProvider archiveProvider; @@ -54,8 +57,8 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont super("UndoCheckOut", plugin.getName(), plugin.getTool()); this.dtmPlugin = plugin; this.archiveProvider = provider; - ImageIcon icon = ResourceManager.loadImage("images/vcUndoCheckOut.png"); - setPopupMenuData(new MenuData(new String[] { "Undo Checkout" }, icon, GROUP)); + + setPopupMenuData(new MenuData(new String[] { "Undo Checkout" }, ICON, GROUP)); setDescription("Undo checkout"); } @@ -135,7 +138,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont * will be undone. * @param unmodifiedArchivesList the list of unmodified archives * @param modifiedArchivesList the list of archives that have been modified - * @throws CancelledException if canclled + * @throws CancelledException if cancelled */ protected void undoCheckOuts(List unmodifiedArchivesList, List modifiedArchivesList) throws CancelledException { @@ -146,8 +149,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont // Now confirm the modified ones and undo checkout for the ones the user indicates. if (modifiedArchivesList.size() > 0) { UndoActionDialog dialog = new UndoActionDialog("Confirm Undo Checkout", - resources.ResourceManager.loadImage("images/vcUndoCheckOut.png"), "UndoCheckOut", - "checkout", getDomainFileList(modifiedArchivesList)); + ICON, "UndoCheckOut", "checkout", getDomainFileList(modifiedArchivesList)); int actionID = dialog.showDialog(tool); if (actionID != UndoActionDialog.CANCEL) { saveCopy = dialog.saveCopy(); @@ -245,8 +247,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont @Override public void run(TaskMonitor monitor) { try { - for (int i = 0; i < unmodifiedCheckOutsList.size(); i++) { - DomainFileArchive archive = unmodifiedCheckOutsList.get(i); + for (DomainFileArchive archive : unmodifiedCheckOutsList) { DomainFile df = archive.getDomainFile(); if (df.isCheckedOut() && (dtmPlugin != null)) { // TODO Need to close archive here if it is open. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/graph/ProgramGraphDisplayOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/graph/ProgramGraphDisplayOptions.java index 6fe3728ae1..cc385a1665 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/graph/ProgramGraphDisplayOptions.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/graph/ProgramGraphDisplayOptions.java @@ -21,7 +21,6 @@ import static ghidra.service.graph.VertexShape.*; import ghidra.framework.plugintool.PluginTool; import ghidra.service.graph.GraphDisplayOptions; import ghidra.service.graph.VertexShape; -import ghidra.util.WebColors; /** * {@link GraphDisplayOptions} for {@link ProgramGraphType} @@ -40,59 +39,64 @@ public class ProgramGraphDisplayOptions extends GraphDisplayOptions { @Override protected void initializeDefaults() { setDefaultVertexShape(ELLIPSE); - setDefaultVertexColor(WebColors.RED); - setDefaultEdgeColor(WebColors.RED); + setDefaultVertexColor("color.bg.plugin.programgraph.vertex.default"); + setDefaultEdgeColor("color.bg.plugin.programgraph.edge.default"); + setVertexSelectionColor("color.bg.plugin.programgraph.vertex.selection"); + setEdgeSelectionColor("color.bg.plugin.programgraph.edge.selection"); setFavoredEdgeType(FALL_THROUGH); - configureVertexType(BODY, RECTANGLE, WebColors.BLUE); - configureVertexType(ENTRY, TRIANGLE_DOWN, WebColors.DARK_ORANGE); - configureVertexType(EXIT, TRIANGLE_UP, WebColors.DARK_MAGENTA); - configureVertexType(SWITCH, DIAMOND, WebColors.DARK_CYAN); - configureVertexType(EXTERNAL, RECTANGLE, WebColors.DARK_GREEN); - configureVertexType(BAD, ELLIPSE, WebColors.RED); - configureVertexType(DATA, ELLIPSE, WebColors.PINK); - configureVertexType(ENTRY_NEXUS, ELLIPSE, WebColors.WHEAT); - configureVertexType(INSTRUCTION, VertexShape.HEXAGON, WebColors.BLUE); - configureVertexType(STACK, RECTANGLE, WebColors.GREEN); + //@formatter:off + configureVertexType(BODY, RECTANGLE, "color.bg.plugin.programgraph.vertex.body"); + configureVertexType(ENTRY, TRIANGLE_DOWN, "color.bg.plugin.programgraph.vertex.entry"); + configureVertexType(EXIT, TRIANGLE_UP, "color.bg.plugin.programgraph.vertex.exit"); + configureVertexType(SWITCH, DIAMOND, "color.bg.plugin.programgraph.vertex.switch"); + configureVertexType(EXTERNAL, RECTANGLE, "color.bg.plugin.programgraph.vertex.external"); + configureVertexType(BAD, ELLIPSE, "color.bg.plugin.programgraph.vertex.bad"); + configureVertexType(DATA, ELLIPSE, "color.bg.plugin.programgraph.vertex.data"); + configureVertexType(ENTRY_NEXUS, ELLIPSE, "color.bg.plugin.programgraph.vertex.entry.nexus"); + configureVertexType(INSTRUCTION, VertexShape.HEXAGON, "color.bg.plugin.programgraph.vertex.instruction"); + configureVertexType(STACK, RECTANGLE, "color.bg.plugin.programgraph.vertex.stack"); - configureEdgeType(ENTRY_EDGE, WebColors.GRAY); - configureEdgeType(FALL_THROUGH, WebColors.BLUE); - configureEdgeType(UNCONDITIONAL_JUMP, WebColors.DARK_GREEN); - configureEdgeType(UNCONDITIONAL_CALL, WebColors.DARK_ORANGE); - configureEdgeType(TERMINATOR, WebColors.PURPLE); - configureEdgeType(JUMP_TERMINATOR, WebColors.PURPLE); - configureEdgeType(INDIRECTION, WebColors.PINK); + configureEdgeType(ENTRY_EDGE, "color.bg.plugin.programgraph.edge.entry"); + configureEdgeType(FALL_THROUGH, "color.bg.plugin.programgraph.edge.fall.through"); + configureEdgeType(UNCONDITIONAL_JUMP, "color.bg.plugin.programgraph.edge.jump.unconditional"); + configureEdgeType(UNCONDITIONAL_CALL, "color.bg.plugin.programgraph.edge.call.unconditional"); + configureEdgeType(TERMINATOR, "color.bg.plugin.programgraph.edge.terminator"); + configureEdgeType(JUMP_TERMINATOR, "color.bg.plugin.programgraph.edge.jump.terminator"); + configureEdgeType(INDIRECTION, "color.bg.plugin.programgraph.edge.indirection"); - configureEdgeType(CONDITIONAL_JUMP, WebColors.DARK_GOLDENROD); - configureEdgeType(CONDITIONAL_CALL, WebColors.DARK_ORANGE); - configureEdgeType(CONDITIONAL_TERMINATOR, WebColors.PURPLE); - configureEdgeType(CONDITIONAL_CALL_TERMINATOR, WebColors.PURPLE); + configureEdgeType(CONDITIONAL_JUMP, "color.bg.plugin.programgraph.edge.jump.conditional"); + configureEdgeType(CONDITIONAL_CALL, "color.bg.plugin.programgraph.edge.call.conditional"); + configureEdgeType(CONDITIONAL_TERMINATOR, "color.bg.plugin.programgraph.edge.conditional.terminator"); + configureEdgeType(CONDITIONAL_CALL_TERMINATOR, "color.bg.plugin.programgraph.edge.call.conditional.terminator"); - configureEdgeType(COMPUTED_JUMP, WebColors.CYAN); - configureEdgeType(COMPUTED_CALL, WebColors.CYAN); - configureEdgeType(COMPUTED_CALL_TERMINATOR, WebColors.PURPLE); + configureEdgeType(COMPUTED_JUMP, "color.bg.plugin.programgraph.edge.jump.computed"); + configureEdgeType(COMPUTED_CALL, "color.bg.plugin.programgraph.edge.call.computed"); + configureEdgeType(COMPUTED_CALL_TERMINATOR, "color.bg.plugin.programgraph.edge.call.computed.terminator"); - configureEdgeType(CONDITIONAL_COMPUTED_CALL, WebColors.CYAN); - configureEdgeType(CONDITIONAL_COMPUTED_JUMP, WebColors.CYAN); + configureEdgeType(CONDITIONAL_COMPUTED_CALL, "color.bg.plugin.programgraph.edge.call.conditional.computed"); + configureEdgeType(CONDITIONAL_COMPUTED_JUMP, "color.bg.plugin.programgraph.edge.jump.conitional.computed"); - configureEdgeType(CALL_OVERRIDE_UNCONDITIONAL, WebColors.RED); - configureEdgeType(JUMP_OVERRIDE_UNCONDITIONAL, WebColors.RED); - configureEdgeType(CALLOTHER_OVERRIDE_CALL, WebColors.RED); - configureEdgeType(CALLOTHER_OVERRIDE_JUMP, WebColors.RED); + configureEdgeType(CALL_OVERRIDE_UNCONDITIONAL, "color.bg.plugin.programgraph.edge.call.unconditional.override"); + configureEdgeType(JUMP_OVERRIDE_UNCONDITIONAL, "color.bg.plugin.programgraph.edge.jump.unconditional.override"); + configureEdgeType(CALLOTHER_OVERRIDE_CALL, "color.bg.plugin.programgraph.edge.call.callother.override"); + configureEdgeType(CALLOTHER_OVERRIDE_JUMP, "color.bg.plugin.programgraph.edge.jump.callother.override"); - configureEdgeType(READ, WebColors.GREEN); - configureEdgeType(WRITE, WebColors.RED); - configureEdgeType(READ_WRITE, WebColors.DARK_GOLDENROD); - configureEdgeType(UNKNOWN_DATA, WebColors.BLACK); - configureEdgeType(EXTERNAL_REF, WebColors.PURPLE); + configureEdgeType(READ, "color.bg.plugin.programgraph.edge.read"); + configureEdgeType(WRITE, "color.bg.plugin.programgraph.edge.write"); + configureEdgeType(READ_WRITE, "color.bg.plugin.programgraph.edge.read.write"); + configureEdgeType(UNKNOWN_DATA, "color.bg.plugin.programgraph.edge.data.unknown"); + configureEdgeType(EXTERNAL_REF, "color.bg.plugin.programgraph.edge.external.ref"); - configureEdgeType(READ_INDIRECT, WebColors.DARK_GREEN); - configureEdgeType(WRITE_INDIRECT, WebColors.DARK_RED); - configureEdgeType(READ_WRITE_INDIRECT, WebColors.BROWN); - configureEdgeType(DATA_INDIRECT, WebColors.DARK_ORANGE); - - configureEdgeType(PARAM, WebColors.CYAN); - configureEdgeType(THUNK, WebColors.BLUE); + configureEdgeType(READ_INDIRECT, "color.bg.plugin.programgraph.edge.read.indirect"); + configureEdgeType(WRITE_INDIRECT, "color.bg.plugin.programgraph.edge.write.indirect"); + configureEdgeType(READ_WRITE_INDIRECT, "color.bg.plugin.programgraph.edge.read.write.indirect"); + configureEdgeType(DATA_INDIRECT, "color.bg.plugin.programgraph.edge.data.indirect"); + configureEdgeType(PARAM, "color.bg.plugin.programgraph.edge.param"); + configureEdgeType(THUNK, "color.bg.plugin.programgraph.edge.thunk"); + + setFont("font.plugin.programgraph"); + //@formatter:on } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java index e562d828ba..12b447bc45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java @@ -15,14 +15,13 @@ */ package ghidra.plugin.importer; -import java.util.*; -import java.util.List; -import java.util.stream.Collectors; - import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.IOException; +import java.util.*; +import java.util.List; +import java.util.stream.Collectors; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -38,6 +37,7 @@ import docking.widgets.combobox.GhidraComboBox; import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.label.GLabel; import docking.widgets.list.GListCellRenderer; +import generic.theme.GIcon; import ghidra.app.services.ProgramManager; import ghidra.app.util.*; import ghidra.app.util.bin.ByteProvider; @@ -56,7 +56,6 @@ import ghidra.util.*; import ghidra.util.layout.PairLayout; import ghidra.util.layout.VerticalLayout; import ghidra.util.task.TaskBuilder; -import resources.ResourceManager; /** * Dialog for importing a file into Ghidra as a program. @@ -244,7 +243,7 @@ public class ImporterDialog extends DialogComponentProvider { }); Font font = languageButton.getFont(); - languageButton.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); + languageButton.setFont(font.deriveFont(Font.BOLD)); JPanel panel = new JPanel(new BorderLayout()); panel.add(languageTextField, BorderLayout.CENTER); @@ -279,7 +278,7 @@ public class ImporterDialog extends DialogComponentProvider { private Component buildLoaderInfoButton() { JPanel panel = new JPanel(new BorderLayout()); EmptyBorderButton helpButton = - new EmptyBorderButton(ResourceManager.loadImage("images/information.png")); + new EmptyBorderButton(new GIcon("icon.information")); helpButton.setToolTipText("Show list of supported format/loaders"); helpButton.addActionListener(e -> showSupportedImportFormats()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/NewLanguagePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/NewLanguagePanel.java index 5358005492..ea028ed21b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/NewLanguagePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/NewLanguagePanel.java @@ -25,6 +25,7 @@ import javax.swing.border.Border; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.program.model.lang.*; import ghidra.program.util.DefaultLanguageService; import ghidra.util.table.*; @@ -84,7 +85,7 @@ public class NewLanguagePanel extends JPanel { formatLabel = new GDLabel(); formatLabel.setHorizontalAlignment(SwingConstants.CENTER); - formatLabel.setForeground(Color.BLUE); + formatLabel.setForeground(Messages.NORMAL); } private void layoutEverything() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java index 26ecb0bca1..eec3c39acf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBActionManager.java @@ -16,13 +16,12 @@ package ghidra.plugins.fsbrowser; import static ghidra.formats.gfilesystem.fileinfo.FileAttributeType.*; -import static java.util.Map.entry; - -import java.util.*; -import java.util.function.Function; +import static java.util.Map.*; import java.awt.Component; import java.io.*; +import java.util.*; +import java.util.function.Function; import javax.swing.*; @@ -31,6 +30,7 @@ import org.apache.commons.io.FilenameUtils; import docking.action.DockingAction; import docking.action.builder.ActionBuilder; import docking.widgets.OptionDialog; +import docking.widgets.SelectFromListDialog; import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooserMode; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBUtils.java index 7da421e420..0089879bb2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FSBUtils.java @@ -18,8 +18,8 @@ package ghidra.plugins.fsbrowser; import java.util.ArrayList; import java.util.List; +import docking.widgets.SelectFromListDialog; import ghidra.app.services.ProgramManager; -import ghidra.formats.gfilesystem.SelectFromListDialog; import ghidra.framework.plugintool.PluginTool; import ghidra.util.Msg; @@ -28,7 +28,6 @@ import ghidra.util.Msg; */ public class FSBUtils { - /** * Returns the {@link ProgramManager} associated with this fs browser plugin. *

diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileIconService.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileIconService.java index 1e05252199..122a1335d7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileIconService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileIconService.java @@ -15,23 +15,13 @@ */ package ghidra.plugins.fsbrowser; -import java.io.IOException; -import java.io.InputStream; import java.util.*; import javax.swing.Icon; -import javax.swing.ImageIcon; -import org.jdom.*; -import org.jdom.input.SAXBuilder; - -import generic.jar.ResourceFile; +import generic.theme.*; import ghidra.formats.gfilesystem.FSUtilities; -import ghidra.framework.Application; -import ghidra.util.Msg; -import ghidra.util.xml.XmlUtilities; -import resources.*; -import util.CollectionUtils; +import resources.MultiIcon; /** * Provides {@link Icon}s that represent the type and status of a file, based on @@ -45,7 +35,7 @@ import util.CollectionUtils; * are resized to be 1/2 the width and height of the icon they are being * overlaid on. *

- * Threadsafe + * Thread safe *

*/ public class FileIconService { @@ -58,76 +48,33 @@ public class FileIconService { return Singleton.INSTANCE; } - public static final String OVERLAY_IMPORTED = "imported"; - public static final String OVERLAY_FILESYSTEM = "filesystem"; - public static final String OVERLAY_MISSING_PASSWORD = "password_missing"; + public static final Icon IMPORTED_OVERLAY_ICON = + new GIcon("icon.fsbrowser.file.overlay.imported"); + public static final Icon FILESYSTEM_OVERLAY_ICON = + new GIcon("icon.fsbrowser.file.overlay.filesystem"); + public static final Icon MISSING_PASSWORD_OVERLAY_ICON = + new GIcon("icon.fsbrowser.file.overlay.missing.password"); + public static final Icon DEFAULT_ICON = new GIcon("icon.fsbrowser.file.extension.default"); - private static final String FILEEXT_MAPPING_FILE = "file_extension_icons.xml"; + private static final String EXTENSION_ICON_PREFIX = "icon.fsbrowser.file.extension"; + private static final String SUBSTRING_ICON_PREFIX = "icon.fsbrowser.file.substring"; - private Map fileExtToIconName = new HashMap<>(); - private Map fileSubstrToIconName = new HashMap<>(); - private Map overlayNameToIconName = new HashMap<>(); - private Map overlayNameToQuad = new HashMap<>(); - private String defaultIconPath = "images/famfamfam_silk_icons_v013/page_white.png"; - private int maxExtLevel = 1; - - private Map iconKeyToIcon = new HashMap<>(); - - private ResourceFile xmlFile; + private Map substringToIconMap = new HashMap<>(); private FileIconService() { - this.xmlFile = Application.findDataFileInAnyModule(FILEEXT_MAPPING_FILE); - if (xmlFile == null) { - Msg.error(this, "Cannot find " + FILEEXT_MAPPING_FILE + - ". File system browser will not have icons."); - } + createSubstringMap(); } - private String makeKey(String key, String[] overlays) { - StringBuilder sb = new StringBuilder(); - sb.append(key).append("__"); - for (String o : overlays) { - if (o == null || o.isEmpty()) { - continue; + private void createSubstringMap() { + GThemeValueMap values = ThemeManager.getInstance().getCurrentValues(); + List icons = values.getIcons(); + for (IconValue iconValue : icons) { + String id = iconValue.getId(); + if (id.startsWith(SUBSTRING_ICON_PREFIX)) { + String substring = id.substring(SUBSTRING_ICON_PREFIX.length()); + substringToIconMap.put(substring, new GIcon(id)); } - sb.append(o).append("__"); } - return sb.toString(); - } - - private Icon getCachedIcon(String key, String path, String... overlays) { - key = makeKey(key, overlays); - Icon cachedIcon = iconKeyToIcon.get(key); - if (cachedIcon == null) { - cachedIcon = ResourceManager.loadImage(path); - if (overlays.length > 0) { - int expectedOW = cachedIcon.getIconWidth() / 2; - int expectedOH = cachedIcon.getIconHeight() / 2; - - EnumSet usedQuads = EnumSet.noneOf(QUADRANT.class); - MultiIconBuilder iconBuilder = new MultiIconBuilder(cachedIcon); - for (String overlay : overlays) { - if (overlay == null || overlay.isEmpty()) { - continue; - } - String overlayPath = overlayNameToIconName.get(overlay); - QUADRANT quad = overlayNameToQuad.get(overlay); - if (overlayPath == null || quad == null) { - continue; - } - if (usedQuads.contains(quad)) { - Msg.warn(this, "File icon already contains an overlay at " + quad); - } - usedQuads.add(quad); - - ImageIcon overlayIcon = ResourceManager.loadImage(overlayPath); - iconBuilder.addIcon(overlayIcon, expectedOW, expectedOH, quad); - } - cachedIcon = iconBuilder.build(); - } - iconKeyToIcon.put(key, cachedIcon); - } - return cachedIcon; } /** @@ -135,106 +82,43 @@ public class FileIconService { * name. * * @param fileName name of file that an icon is being requested for. - * @param overlays optional list of overlay names, names of icons that - * should be overlaid on top of the base icon, that represent a + * @param overlays optional list of overlay icons that + * should be overlaid on top of the base icon. These icons represent a * status or feature independent of the file's base icon. * @return {@link Icon} instance that best represents the named file, never * null. */ - public synchronized Icon getImage(String fileName, String... overlays) { - loadIfNeeded(); - + public Icon getIcon(String fileName, List overlays) { fileName = fileName.toLowerCase(); - for (int extLevel = 1; extLevel <= maxExtLevel; extLevel++) { - String ext = FSUtilities.getExtension(fileName, extLevel); - if (ext == null) { - break; - } - String path = fileExtToIconName.get(ext); - if (path != null) { - return getCachedIcon(ext, path, overlays); + String ext = FSUtilities.getExtension(fileName, 1); + if (ext != null) { + String iconId = EXTENSION_ICON_PREFIX + ext; + if (Gui.hasIcon(iconId)) { + Icon base = new GIcon(iconId); + return buildIcon(base, overlays); } } - for (String substr : fileSubstrToIconName.keySet()) { - if (fileName.indexOf(substr) != -1) { - return getCachedIcon("####" + substr, fileSubstrToIconName.get(substr), overlays); + for (String substring : substringToIconMap.keySet()) { + if (fileName.indexOf(substring) != -1) { + return buildIcon(substringToIconMap.get(substring), overlays); } } // return default icon for generic file - return getCachedIcon("", defaultIconPath, overlays); + return buildIcon(DEFAULT_ICON, overlays); } - /** - * Loads XML file if it has not been loaded yet. - */ - protected void loadIfNeeded() { - if (fileExtToIconName.isEmpty()) { - load(); + private Icon buildIcon(Icon base, List overlays) { + if (overlays == null || overlays.isEmpty()) { + return base; } - } - - private void load() { - fileExtToIconName.clear(); - fileSubstrToIconName.clear(); - overlayNameToIconName.clear(); - overlayNameToQuad.clear(); - iconKeyToIcon.clear(); - defaultIconPath = null; - maxExtLevel = 1; - - try (InputStream xmlInputStream = xmlFile.getInputStream()) { - SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false); - Document doc = sax.build(xmlInputStream); - Element root = doc.getRootElement(); - for (Element child : CollectionUtils.asList(root.getChildren("file_extension"), - Element.class)) { - String extension = child.getAttributeValue("extension"); - String iconPath = child.getAttributeValue("icon"); - if (extension.endsWith(".")) { - addSubstrMapping(extension, iconPath); - } - else if (!extension.isEmpty()) { - addExtMapping(extension, iconPath); - } - else { - defaultIconPath = iconPath; - } - } - for (Element child : CollectionUtils.asList(root.getChildren("file_overlay"), - Element.class)) { - String name = child.getAttributeValue("name"); - String iconPath = child.getAttributeValue("icon"); - QUADRANT quadrant = - QUADRANT.valueOf(child.getAttributeValue("quadrant"), QUADRANT.LR); - - overlayNameToIconName.put(name, iconPath); - overlayNameToQuad.put(name, quadrant); + MultiIcon multiIcon = new MultiIcon(base); + for (Icon overlay : overlays) { + if (overlay != null) { + multiIcon.addIcon(overlay); } } - catch (JDOMException | IOException e) { - Msg.error(this, "Error reading file icon data: " + e.getMessage(), e); - } + return multiIcon; } - - private void addSubstrMapping(String substr, String iconPath) { - fileSubstrToIconName.put(substr, iconPath); - } - - private void addExtMapping(String ext, String iconPath) { - fileExtToIconName.put(ext, iconPath); - maxExtLevel = Math.max(maxExtLevel, countExtLevel(ext)); - } - - private int countExtLevel(String ext) { - int count = 0; - for (int i = 0; i < ext.length(); i++) { - if (ext.charAt(i) == '.') { - count++; - } - } - return count; - } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserComponentProvider.java index 17c3a1599a..1ff10a424a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/FileSystemBrowserComponentProvider.java @@ -15,7 +15,6 @@ */ package ghidra.plugins.fsbrowser; -import java.awt.Color; import java.awt.Component; import java.awt.event.MouseEvent; import java.util.ArrayList; @@ -30,6 +29,7 @@ import docking.event.mouse.GMouseListenerAdapter; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; import docking.widgets.tree.support.GTreeRenderer; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.services.ProgramManager; import ghidra.app.services.TextEditorService; import ghidra.formats.gfilesystem.*; @@ -87,6 +87,7 @@ class FileSystemBrowserComponentProvider extends ComponentProviderAdapter handleDoubleClick(gTree.getNodeForLocation(e.getX(), e.getY())); e.consume(); } + @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); @@ -127,33 +128,33 @@ class FileSystemBrowserComponentProvider extends ComponentProviderAdapter FSRLRoot fsFSRL = nodeFSRef.getFilesystem().getFSRL(); String containerFilename = fsFSRL.hasContainer() ? fsFSRL.getContainer().getName() : "unknown"; - Icon image = FileIconService.getInstance().getImage(containerFilename, - FileIconService.OVERLAY_FILESYSTEM); + Icon image = FileIconService.getInstance() + .getIcon(containerFilename, + List.of(FileIconService.FILESYSTEM_OVERLAY_ICON)); setIcon(image); } private void renderFile(FSBFileNode node, boolean selected) { FSRL fsrl = node.getFSRL(); String filename = fsrl.getName(); + List overlays = new ArrayList<>(3); - String importOverlay = ProgramMappingService.isFileImportedIntoProject(fsrl) - ? FileIconService.OVERLAY_IMPORTED - : null; - String mountedOverlay = fsService.isFilesystemMountedAt(fsrl) - ? FileIconService.OVERLAY_FILESYSTEM - : null; + if (ProgramMappingService.isFileImportedIntoProject(fsrl)) { + overlays.add(FileIconService.IMPORTED_OVERLAY_ICON); + } + if (fsService.isFilesystemMountedAt(fsrl)) { + overlays.add(FileIconService.FILESYSTEM_OVERLAY_ICON); + } + if (node.hasMissingPassword()) { + overlays.add(FileIconService.MISSING_PASSWORD_OVERLAY_ICON); + } - String missingPasswordOverlay = node.hasMissingPassword() - ? FileIconService.OVERLAY_MISSING_PASSWORD - : null; - - Icon ico = FileIconService.getInstance() - .getImage(filename, importOverlay, mountedOverlay, missingPasswordOverlay); - setIcon(ico); + Icon icon = FileIconService.getInstance().getIcon(filename, overlays); + setIcon(icon); if (ProgramMappingService.isFileOpen(fsrl)) { // TODO: change this to a OVERLAY_OPEN option when fetching icon - setForeground(selected ? Color.CYAN : Color.MAGENTA); + setForeground(selected ? Palette.CYAN : Palette.MAGENTA); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/ImageManager.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/ImageManager.java index b3bf88db42..3ea17f2af4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/ImageManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/fsbrowser/ImageManager.java @@ -15,10 +15,9 @@ */ package ghidra.plugins.fsbrowser; -import javax.swing.ImageIcon; +import javax.swing.Icon; -import resources.Icons; -import resources.ResourceManager; +import generic.theme.GIcon; /** * Static helper to register and load Icons for the file system browser plugin and its @@ -28,43 +27,39 @@ import resources.ResourceManager; */ public class ImageManager { //@formatter:off - public final static ImageIcon COPY = ResourceManager.loadImage("images/page_copy.png"); - public final static ImageIcon CUT = ResourceManager.loadImage("images/edit-cut.png"); - public final static ImageIcon DELETE = ResourceManager.loadImage("images/page_delete.png"); - public final static ImageIcon FONT = ResourceManager.loadImage("images/text_lowercase.png"); - public final static ImageIcon LOCKED = ResourceManager.loadImage("images/lock.gif"); - public final static ImageIcon NEW = ResourceManager.loadImage("images/page_add.png"); - public final static ImageIcon PASTE = ResourceManager.loadImage("images/page_paste.png"); - public final static ImageIcon REDO = ResourceManager.loadImage("images/redo.png"); - public final static ImageIcon RENAME = ResourceManager.loadImage("images/textfield_rename.png"); - public final static ImageIcon REFRESH = Icons.REFRESH_ICON; - public final static ImageIcon SAVE = ResourceManager.loadImage("images/disk.png"); - public final static ImageIcon SAVE_AS = ResourceManager.loadImage("images/disk_save_as.png"); - public final static ImageIcon UNDO = ResourceManager.loadImage("images/undo.png"); - public final static ImageIcon UNLOCKED = ResourceManager.loadImage("images/unlock.gif"); - public final static ImageIcon CLOSE = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door.png"); - public final static ImageIcon COLLAPSE_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/arrow_in.png"); - public final static ImageIcon COMPRESS = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/compress.png"); - public final static ImageIcon CREATE_FIRMWARE = ResourceManager.loadImage("images/media-flash.png"); - public final static ImageIcon EXPAND_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/arrow_inout.png"); - public final static ImageIcon EXTRACT = ResourceManager.loadImage("images/package_green.png"); - public final static ImageIcon INFO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/information.png"); - public final static ImageIcon OPEN = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/door_open.png"); - public final static ImageIcon OPEN_AS_BINARY = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/controller.png"); - public final static ImageIcon OPEN_IN_LISTING = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/folder_table.png"); - public final static ImageIcon OPEN_FILE_SYSTEM = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/folder_brick.png"); - public final static ImageIcon PHOTO = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/photo.png"); - public final static ImageIcon VIEW_AS_IMAGE = ResourceManager.loadImage("images/oxygen/16x16/games-config-background.png"); - public final static ImageIcon VIEW_AS_TEXT = ResourceManager.loadImage("images/format-text-bold.png"); - public final static ImageIcon UNKNOWN = ResourceManager.loadImage("images/help-browser.png"); - public final static ImageIcon IPOD = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/ipod.png"); - public final static ImageIcon IPOD_48 = ResourceManager.loadImage("images/oxygen/48x48/multimedia-player-apple-ipod.png"); - public final static ImageIcon ECLIPSE = ResourceManager.loadImage("images/eclipse.png"); - public final static ImageIcon JAR = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/page_white_cup.png"); - public final static ImageIcon KEY = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_key.png"); - public final static ImageIcon IMPORT = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_get.png"); - public final static ImageIcon iOS = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/phone.png"); - public final static ImageIcon OPEN_ALL = ResourceManager.loadImage("images/famfamfam_silk_icons_v013/application_cascade.png"); - public final static ImageIcon LIST_MOUNTED = ResourceManager.loadImage("images/downArrow.png"); + public final static Icon COPY = new GIcon("icon.plugin.fsbrowser.copy"); + public final static Icon CUT = new GIcon("icon.plugin.fsbrowser.cut"); + public final static Icon DELETE = new GIcon("icon.plugin.fsbrowser.delete"); + public final static Icon FONT = new GIcon("icon.plugin.fsbrowser.font"); + public final static Icon LOCKED = new GIcon("icon.plugin.fsbrowser.locked"); + public final static Icon NEW = new GIcon("icon.plugin.fsbrowser.new"); + public final static Icon PASTE = new GIcon("icon.plugin.fsbrowser.paste"); + public final static Icon REDO = new GIcon("icon.plugin.fsbrowser.redo"); + public final static Icon RENAME = new GIcon("icon.plugin.fsbrowser.rename"); + public final static Icon REFRESH = new GIcon("icon.plugin.fsbrowser.refresh"); + public final static Icon SAVE = new GIcon("icon.plugin.fsbrowser.save"); + public final static Icon SAVE_AS = new GIcon("icon.plugin.fsbrowser.save.as"); + public final static Icon UNDO = new GIcon("icon.plugin.fsbrowser.undo"); + public final static Icon UNLOCKED = new GIcon("icon.plugin.fsbrowser.unlocked"); + public final static Icon CLOSE = new GIcon("icon.plugin.fsbrowser.close"); + public final static Icon COLLAPSE_ALL = new GIcon("icon.plugin.fsbrowser.collapse.all"); + public final static Icon COMPRESS = new GIcon("icon.plugin.fsbrowser.compress"); + public final static Icon CREATE_FIRMWARE = new GIcon("icon.plugin.fsbrowser.create.firmware"); + public final static Icon EXPAND_ALL = new GIcon("icon.plugin.fsbrowser.expand.all"); + public final static Icon EXTRACT = new GIcon("icon.plugin.fsbrowser.extract"); + public final static Icon INFO = new GIcon("icon.plugin.fsbrowser.info"); + public final static Icon OPEN = new GIcon("icon.plugin.fsbrowser.open"); + public final static Icon OPEN_AS_BINARY = new GIcon("icon.plugin.fsbrowser.open.as.binary"); + public final static Icon OPEN_IN_LISTING = new GIcon("icon.plugin.fsbrowser.open.in.listing"); + public final static Icon OPEN_FILE_SYSTEM = new GIcon("icon.plugin.fsbrowser.open.file.system"); + public final static Icon PHOTO = new GIcon("icon.plugin.fsbrowser.photo"); + public final static Icon VIEW_AS_IMAGE = new GIcon("icon.plugin.fsbrowser.view.as.image"); + public final static Icon VIEW_AS_TEXT = new GIcon("icon.plugin.fsbrowser.view.as.text"); + public final static Icon ECLIPSE = new GIcon("icon.plugin.fsbrowser.eclipse"); + public final static Icon JAR = new GIcon("icon.plugin.fsbrowser.jar"); + public final static Icon IMPORT = new GIcon("icon.plugin.fsbrowser.import"); + public final static Icon iOS = new GIcon("icon.plugin.fsbrowser.ios"); + public final static Icon OPEN_ALL = new GIcon("icon.plugin.fsbrowser.open.all"); + public final static Icon LIST_MOUNTED = new GIcon("icon.plugin.fsbrowser.list.mounted"); //@formatter:on } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java index 4c8878cd3e..e738586a6f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/plugins/importer/batch/BatchImportDialog.java @@ -38,6 +38,7 @@ import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.label.GDLabel; import docking.widgets.table.*; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.services.ProgramManager; import ghidra.formats.gfilesystem.FSRL; import ghidra.formats.gfilesystem.FileSystemService; @@ -537,7 +538,8 @@ public class BatchImportDialog extends DialogComponentProvider { protected String getText(Object value) { BatchGroupLoadSpec bgls = (BatchGroupLoadSpec) value; return (bgls != null) ? bgls.toString() - : "Click to set language"; + : "Click to set language"; } }; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java index 0d100f86d9..cd86c27bff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/FunctionUtility.java @@ -15,9 +15,9 @@ */ package ghidra.program.util; -import java.awt.Color; import java.util.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.program.model.address.Address; import ghidra.program.model.data.DataType; import ghidra.program.model.data.GenericCallingConvention; @@ -381,7 +381,7 @@ public class FunctionUtility { String programStr = HTMLUtilities.friendlyEncodeHTML(program.getDomainFile().getPathname()); - String specialProgramStr = HTMLUtilities.colorString(Color.DARK_GRAY, programStr); + String specialProgramStr = HTMLUtilities.colorString(Palette.DARK_GRAY, programStr); buf.append(specialProgramStr); buf.append(padStr); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java index 4b6b6f8024..7d9108a85e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java @@ -21,6 +21,7 @@ import java.util.*; import javax.swing.text.*; +import generic.theme.GColor; import ghidra.program.database.properties.UnsupportedMapDB; import ghidra.program.model.address.*; import ghidra.program.model.data.*; @@ -43,20 +44,17 @@ public class ProgramDiffDetails { private static final int INDENT_SIZE = 4; private static final String STANDARD_NEW_LINE = "\n"; - public static Color RED = new Color(0xff, 0x00, 0x00); - public static Color MAROON = new Color(0x99, 0x00, 0x00); - public static Color GREEN = new Color(0x00, 0x99, 0x00); - public static Color BLUE = new Color(0x00, 0x00, 0x99); - public static Color PURPLE = new Color(0x99, 0x00, 0x99); - public static Color DARK_CYAN = new Color(0x00, 0x99, 0x99); - public static Color OLIVE = new Color(0x99, 0x99, 0x00); - public static Color ORANGE = new Color(0xff, 0x99, 0x00); - public static Color PINK = new Color(0xff, 0x99, 0x99); - public static Color YELLOW = new Color(0xff, 0xff, 0x00); - public static Color GRAY = new Color(0x88, 0x88, 0x88); - private static final Color EMPHASIZE_COLOR = GREEN; - private static final Color ADDRESS_COLOR = DARK_CYAN; - private static final Color COMMENT_COLOR = GREEN; + //@formatter:off + private static Color FG_COLOR_ADDRESS = new GColor("color.bg.plugin.programdiff.details.address"); + private static Color FG_COLOR_COMMENT = new GColor("color.bg.plugin.programdiff.details.comment"); + private static Color FG_COLOR_DANGER = new GColor("color.bg.plugin.programdiff.details.danger"); + private static Color FG_COLOR_EMPHASIZE = new GColor("color.bg.plugin.programdiff.details.emphasize"); + private static Color FG_COLOR_PROGRAM = new GColor("color.bg.plugin.programdiff.details.emphasize"); + //@formatter:on + + private static final Color EMPHASIZE_COLOR = FG_COLOR_EMPHASIZE; + private static final Color ADDRESS_COLOR = FG_COLOR_ADDRESS; + private static final Color COMMENT_COLOR = FG_COLOR_COMMENT; private static final BookmarkComparator BOOKMARK_COMPARATOR = new BookmarkComparator(); @@ -123,12 +121,9 @@ public class ProgramDiffDetails { return buf.toString(); } - /** - * - */ private void initAttributes() { textAttrSet = new SimpleAttributeSet(); - textAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12)); + textAttrSet.addAttribute(StyleConstants.FontSize, 12); } /** @@ -690,9 +685,6 @@ public class ProgramDiffDetails { return list.toArray(new Symbol[list.size()]); } - /** - * @param addr - */ private void addEntryPtLine(Address addr) { addText(indent2); addColorAddress(addr); @@ -744,7 +736,6 @@ public class ProgramDiffDetails { * @param nameLength the length of the name field. * @param typeLength the length of the type field. * @param sourceLength the length of the source field. - * @return the string with the label name and attributes. */ private void addDisplayLabel(Symbol symbol, int nameLength, int typeLength, int sourceLength) { String name = ""; @@ -1191,9 +1182,6 @@ public class ProgramDiffDetails { return hasAddrDiffs; } - /** - * @param opIndex - */ private void addOperandText(int opIndex) { addText(indent2); addText("Operand: "); @@ -1445,8 +1433,8 @@ public class ProgramDiffDetails { * tags passed-in. If a comment is present in the tag object, it will be shown * in parenthesis. * - * @param tags - * @return + * @param tags the tags + * @return the info */ private String getTagInfo(Collection tags) { if (tags == null || tags.size() == 0) { @@ -2179,8 +2167,10 @@ public class ProgramDiffDetails { for (String propertyName : names1) { if (cu.hasProperty(propertyName)) { // Handle case where the class for a Saveable property is missing (unsupported). - if (cu.getProgram().getListing().getPropertyMap( - propertyName) instanceof UnsupportedMapDB) { + if (cu.getProgram() + .getListing() + .getPropertyMap( + propertyName) instanceof UnsupportedMapDB) { buf.append( indent2 + propertyName + " is an unsupported property." + newLine); continue; @@ -2551,7 +2541,7 @@ public class ProgramDiffDetails { } private void addColorProgram(StyledDocument doc, String text) { - color(PURPLE); + color(FG_COLOR_PROGRAM); try { doc.insertString(doc.getLength(), text, textAttrSet); } @@ -2575,7 +2565,7 @@ public class ProgramDiffDetails { } private void addDangerColorText(String text) { - addColorText(RED, detailsDoc, text); + addColorText(FG_COLOR_DANGER, detailsDoc, text); } private void addColorText(Color color, StyledDocument doc, String text) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java index 367a1fad8f..dd7939d9c0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/processors/support/PCodeTestCombinedTestResults.java @@ -15,6 +15,7 @@ */ package ghidra.test.processors.support; +import java.awt.Color; import java.io.*; import java.util.*; @@ -23,6 +24,7 @@ import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.test.processors.support.PCodeTestResults.TestResults; import ghidra.util.HTMLUtilities; import ghidra.util.Msg; @@ -383,9 +385,9 @@ public class PCodeTestCombinedTestResults { w.println("

"); if (testResults.summaryHasIngestErrors) { - w.print("Ingest-Err
"); + w.print("Ingest-Err
"); } if (testResults.summaryHasRelocationErrors) { - w.print("Reloc-Err
"); + w.print("Reloc-Err
"); } if (testResults.summaryHasDisassemblyErrors) { - w.print("Dis-Err"); + w.print("Dis-Err"); } } else { w.print("
"); - writeResultCount(w, testResults.summaryPassCount, "green"); + writeResultCount(w, testResults.summaryPassCount, Palette.GREEN); w.print("/"); - writeResultCount(w, testResults.summaryFailCount, "red"); + writeResultCount(w, testResults.summaryFailCount, Palette.RED); w.print("/"); - writeResultCount(w, testResults.summaryCallOtherCount, "orange"); + writeResultCount(w, testResults.summaryCallOtherCount, Palette.ORANGE); if (testResults.summarySevereFailures != 0) { - w.print("
ERR: " + testResults.summarySevereFailures + + w.print("
ERR: " + + testResults.summarySevereFailures + ""); } } @@ -498,25 +501,26 @@ public class PCodeTestCombinedTestResults { namedTestColumn.getColumnWidth() + ">
"); } if (severeFailure) { - w.print("ERR"); + w.print("ERR"); } else { if (total == 0) { if (totalAsserts == 0) { - w.print("-"); + w.print("-"); } else { - w.print("x"); + w.print("x"); } } else { - writeResultCount(w, pass, "green"); + writeResultCount(w, pass, Palette.GREEN); w.print("/"); - writeResultCount(w, fail, "red"); + writeResultCount(w, fail, Palette.RED); w.print("/"); - writeResultCount(w, callother, "orange"); + writeResultCount(w, callother, Palette.ORANGE); if (total != totalAsserts) { - w.print("
(!=" + totalAsserts + ")"); + w.print("
(!=" + totalAsserts + + ")"); } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableCellRenderer.java index 93be27e470..aa98413eda 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableCellRenderer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +15,6 @@ */ package ghidra.util.table; -import ghidra.program.model.address.Address; -import ghidra.program.model.listing.Program; -import ghidra.program.model.mem.Memory; -import ghidra.program.model.symbol.ExternalLocation; -import ghidra.program.model.symbol.Symbol; - import java.awt.Color; import java.awt.Font; @@ -29,12 +22,23 @@ import javax.swing.JTable; import javax.swing.table.TableModel; import docking.widgets.table.GTableCellRenderer; +import generic.theme.GColor; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.symbol.ExternalLocation; +import ghidra.program.model.symbol.Symbol; public class GhidraTableCellRenderer extends GTableCellRenderer { // Defaults as defined by OptionsGui class - would be nice to use the tool options - private static final Color BAD_REF_ADDR_COLOR = Color.red; - private static final Color EXT_REF_RESOLVED_COLOR = Color.CYAN.darker().darker(); + private static final Color BAD_REF_ADDR_COLOR = new GColor("color.fg.listing.ref.bad"); + private static final Color EXT_REF_RESOLVED_COLOR = + new GColor("color.fg.listing.ref.ext.resolved"); + public Color SELECTED_CELL_COLOR = new GColor("color.bg.table.selected.ghidratable"); + public Color BAD_EQUATE_COLOR = new GColor("color.fg.table.ghidratable.equate.bad"); + public Color EQUATE_COLOR = new GColor("color.fg.table.ghidratable.equate"); + public Color SUGGESTION_COLOR = new GColor("color.fg.table.ghidratable.suggestion"); public GhidraTableCellRenderer() { // default constructor diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/PreviewDataTableCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/PreviewDataTableCellRenderer.java index a1725b4eae..c541f30002 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/PreviewDataTableCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/PreviewDataTableCellRenderer.java @@ -22,6 +22,7 @@ import javax.swing.JLabel; import javax.swing.JTable; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GColor; import ghidra.docking.settings.Settings; import ghidra.program.util.ProgramLocation; import ghidra.util.Msg; @@ -33,8 +34,10 @@ import ghidra.util.table.column.AbstractGColumnRenderer; * used directly with {@link PreviewTableCellData} column data. */ public class PreviewDataTableCellRenderer extends AbstractGColumnRenderer { - private static final Color DEFAULT_OFFCUT_FOREGROUND_COLOR = Color.RED; - private static final Color DEFAULT_SELECTED_OFFCUT_FOREGROUND_COLOR = Color.PINK; + private static final Color DEFAULT_OFFCUT_FOREGROUND_COLOR = + new GColor("color.fg.table.offcut.unselected"); + private static final Color DEFAULT_SELECTED_OFFCUT_FOREGROUND_COLOR = + new GColor("color.fg.table.offcut.selected"); @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/ReferencesFromTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/ReferencesFromTableModel.java index 0ebe84feec..926b9ae01b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/ReferencesFromTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/ReferencesFromTableModel.java @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import javax.swing.JLabel; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GColor; import ghidra.app.plugin.core.navigation.locationreferences.ReferenceUtils; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; @@ -98,6 +99,7 @@ public class ReferencesFromTableModel extends AddressBasedTableModel>" private static final String PLAIN_OFFCUT_TEXT = "<< OFFCUT >>"; private static final String HTML_OFFCUT_TEXT = " << OFFCUT >>"; + private static final Color OFFCUT_COLOR = new GColor("color.fg.table.offcut.unselected"); ReferenceTypeTableCellRenderer() { setHTMLRenderingEnabled(true); @@ -120,7 +122,7 @@ public class ReferencesFromTableModel extends AddressBasedTableModel { @@ -75,9 +76,9 @@ public class MemoryTypeProgramLocationBasedTableColumn private class MemoryTypeRenderer extends AbstractGhidraColumnRenderer { - private Color disabledColor = Color.LIGHT_GRAY; - private ImageIcon offIcon = ResourceManager.loadImage("images/EmptyIcon16.gif"); - private ImageIcon onIcon = ResourceManager.loadImage("images/check.png"); + private Color disabledColor = Colors.DISABLED; + private GIcon offIcon = (GIcon) Icons.EMPTY_ICON; + private GIcon onIcon = new GIcon("icon.check"); MemoryTypeRenderer() { setHTMLRenderingEnabled(true); @@ -96,8 +97,8 @@ public class MemoryTypeProgramLocationBasedTableColumn MemoryBlock block = (MemoryBlock) value; - StringBuffer buffy = new StringBuffer(""); - StringBuffer tooltipBuffy = new StringBuffer(""); + StringBuilder buffy = new StringBuilder(""); + StringBuilder tooltipBuffy = new StringBuilder(""); asString(block, buffy, tooltipBuffy); setText(buffy.toString()); @@ -105,66 +106,66 @@ public class MemoryTypeProgramLocationBasedTableColumn return theRenderer; } - private void asString(MemoryBlock block, StringBuffer buffy, StringBuffer tooltipBuffy) { + private void asString(MemoryBlock block, StringBuilder buffy, StringBuilder tooltipBuffy) { updateForRead(block, buffy, tooltipBuffy); updateForWrite(block, buffy, tooltipBuffy); updateForExecute(block, buffy, tooltipBuffy); updateForVolatile(block, buffy, tooltipBuffy); } - private void updateForVolatile(MemoryBlock block, StringBuffer buffy, - StringBuffer tooltipBuffy) { + private void updateForVolatile(MemoryBlock block, StringBuilder buffy, + StringBuilder tooltipBuffy) { if (block.isVolatile()) { buffy.append("V"); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } else { buffy.append(HTMLUtilities.colorString(disabledColor, "V")); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } tooltipBuffy.append(HTMLUtilities.spaces(2)).append("Volatile
"); } - private void updateForExecute(MemoryBlock block, StringBuffer buffy, - StringBuffer tooltipBuffy) { + private void updateForExecute(MemoryBlock block, StringBuilder buffy, + StringBuilder tooltipBuffy) { if (block.isExecute()) { buffy.append("E"); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } else { buffy.append(HTMLUtilities.colorString(disabledColor, "E")); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } tooltipBuffy.append(HTMLUtilities.spaces(2)).append("Execute
"); } - private void updateForWrite(MemoryBlock block, StringBuffer buffy, - StringBuffer tooltipBuffy) { + private void updateForWrite(MemoryBlock block, StringBuilder buffy, + StringBuilder tooltipBuffy) { if (block.isWrite()) { buffy.append("W"); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } else { buffy.append(HTMLUtilities.colorString(disabledColor, "W")); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } tooltipBuffy.append(HTMLUtilities.spaces(2)).append("Write
"); } - private void updateForRead(MemoryBlock block, StringBuffer buffy, - StringBuffer tooltipBuffy) { + private void updateForRead(MemoryBlock block, StringBuilder buffy, + StringBuilder tooltipBuffy) { if (block.isRead()) { buffy.append("R"); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } else { buffy.append(HTMLUtilities.colorString(disabledColor, "R")); - tooltipBuffy.append(""); + tooltipBuffy.append(""); } tooltipBuffy.append(HTMLUtilities.spaces(2)).append("Read
"); } @@ -175,8 +176,8 @@ public class MemoryTypeProgramLocationBasedTableColumn return ""; } - StringBuffer buffy = new StringBuffer(""); - StringBuffer tooltipBuffy = new StringBuffer(""); + StringBuilder buffy = new StringBuilder(""); + StringBuilder tooltipBuffy = new StringBuilder(""); asString(t, buffy, tooltipBuffy); return buffy.toString(); } diff --git a/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java b/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java index e3013d13e4..9e6e12327b 100644 --- a/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java +++ b/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java @@ -47,6 +47,9 @@ import docking.widgets.table.threaded.ThreadedTableModel; import docking.widgets.tree.GTree; import generic.jar.ResourceFile; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.image.ImageUtils; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.core.analysis.AnalysisOptionsDialog; @@ -76,6 +79,7 @@ import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramSelection; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; +import ghidra.util.ColorUtils; import ghidra.util.exception.AssertException; import resources.ResourceManager; @@ -420,7 +424,7 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn captureComponent(window); } } - drawBorder(Color.BLACK); + drawBorder(Java.BORDER); } public JPopupMenu getPopupMenu() { @@ -784,20 +788,20 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn BufferedImage combinedImage = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_ARGB); Graphics g = combinedImage.getGraphics(); - g.setColor(Color.WHITE); + g.setColor(Palette.WHITE); g.fillRect(0, 0, rect.width, rect.height); for (Component component : comps) { int pad = 6; Point p = component.getLocationOnScreen(); - g.setColor(new Color(250, 250, 250)); + g.setColor(ColorUtils.getOpaqueColor(0xfafafa)); // just slightly not white g.fillRoundRect(p.x - rect.x - pad, p.y - rect.y - pad, component.getWidth() + pad * 2, component.getHeight() + pad * 2, pad * 2, pad * 2); } for (Component component : comps) { int pad = 3; Point p = component.getLocationOnScreen(); - g.setColor(new Color(240, 240, 240)); + g.setColor(ColorUtils.getOpaqueColor(0xf0f0f0)); // faint gray g.fillRoundRect(p.x - rect.x - pad, p.y - rect.y - pad, component.getWidth() + pad * 2, component.getHeight() + pad * 2, pad * 2, pad * 2); } @@ -1372,7 +1376,7 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn } public void drawRectangleWithDropShadowAround(JComponent component, Color color, int padding) { - Rectangle r = drawRectangleAround(component, Color.BLACK, padding); + Rectangle r = drawRectangleAround(component, Java.BORDER, padding); // move it back a bit to create the drop-shadow effect r.x -= padding; @@ -1594,7 +1598,7 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn public Image takeSnippet(Rectangle bounds) { int margin = 20; int topMargin = 4; - padImage(Color.WHITE, 0, margin, 0, margin); + padImage(Colors.BACKGROUND, 0, margin, 0, margin); int rise = 8; bounds.width += 2 * margin; @@ -1625,7 +1629,7 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setColor(Color.BLACK); + g2.setColor(Java.BORDER); g2.setStroke(new BasicStroke(3f)); g2.draw(topPath); g2.draw(bottomPath); diff --git a/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java b/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java index f384c050c2..8a298ec967 100644 --- a/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java +++ b/Ghidra/Features/Base/src/main/java/help/screenshot/GhidraScreenShotGenerator.java @@ -15,7 +15,7 @@ */ package help.screenshot; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import java.awt.*; import java.awt.image.BufferedImage; @@ -31,14 +31,24 @@ import org.junit.Assert; import docking.*; import docking.action.DockingActionIf; import generic.jar.ResourceFile; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.WindowUtilities; import ghidra.framework.Application; import ghidra.framework.main.FrontEndTool; import ghidra.util.Msg; import ghidra.util.exception.AssertException; +/** + * Extend this class to create screen shot images for help. The name of the class determines the + * topic directory where the captured image will be stored. So if the class name is + * XyzShreenShots, the resulting captured image will appear in help topic directy "Xyz", regardless + * of which module has that topic. The test name will determine the name of the image file + * that is generated. So if the test name is testHappyBirthday, the filename will be + * HappyBirthday.png. + */ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenerator { + private static final Color FG_COLOR_TEXT = Palette.getColor("color.palate.cornflowerblue"); private static final String CAPTURE = "Capture"; protected GhidraScreenShotGenerator() { @@ -256,7 +266,7 @@ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenera int x = (width / 2) - (stringWidth / 2); int y = (height / 2) + (stringHeight / 2); - g.setColor(new Color(0, 0, 200, 100)); + g.setColor(FG_COLOR_TEXT); g.drawString(text, x, y); return gifImage; @@ -280,7 +290,7 @@ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenera int x = (width / 2) - (stringWidth / 2); int y = (height / 2) + (stringHeight / 2); - g.setColor(new Color(0, 0, 200, 100)); + g.setColor(FG_COLOR_TEXT); g.drawString(text, x, y); return gifImage; diff --git a/Ghidra/Features/Base/src/main/java/help/screenshot/ImageDialogProvider.java b/Ghidra/Features/Base/src/main/java/help/screenshot/ImageDialogProvider.java index 819b81be6a..49c68495f9 100644 --- a/Ghidra/Features/Base/src/main/java/help/screenshot/ImageDialogProvider.java +++ b/Ghidra/Features/Base/src/main/java/help/screenshot/ImageDialogProvider.java @@ -33,10 +33,12 @@ import docking.action.DockingAction; import docking.action.ToolBarData; import docking.widgets.combobox.GComboBox; import docking.widgets.label.*; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.util.Msg; import ghidra.util.bean.GGlassPane; import ghidra.util.bean.GGlassPanePainter; -import resources.ResourceManager; +import resources.Icons; public class ImageDialogProvider extends DialogComponentProvider { private GGlassPane glassPane; @@ -85,24 +87,14 @@ public class ImageDialogProvider extends DialogComponentProvider { @Override public void actionPerformed(ActionContext context) { if (dragShape != null) { - dragShape.setColor(Color.green.brighter()); + dragShape.setColor(Palette.GREEN); shapeList.add(dragShape); dragShape = null; glassPane.repaint(); } } }; - action.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/Plus.png"))); - addAction(action); - - action = new DockingAction("Write", "Test") { - - @Override - public void actionPerformed(ActionContext context) { - Msg.debug(this, "Just kidding..."); - } - }; - action.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/pencil16.png"))); + action.setToolBarData(new ToolBarData(Icons.ADD_ICON)); addAction(action); } @@ -143,12 +135,12 @@ public class ImageDialogProvider extends DialogComponentProvider { String selectedItem = (String) shapeCombo.getSelectedItem(); if ("Rectangle".equals(selectedItem)) { Rectangle r = new Rectangle(startPoint, new Dimension(width, height)); - dragShape = new ShapePainter(r, Color.RED); + dragShape = new ShapePainter(r, Palette.RED); } else if ("Oval".equals(selectedItem)) { Ellipse2D ellipse = new Ellipse2D.Double(startPoint.x, startPoint.y, width, height); - dragShape = new ShapePainter(ellipse, Color.RED); + dragShape = new ShapePainter(ellipse, Palette.RED); } else if ("Arrow".equals(selectedItem)) { // TODO @@ -174,25 +166,25 @@ public class ImageDialogProvider extends DialogComponentProvider { newImageLabel = new GIconLabel(new ImageIcon(newImage)); newImageLabel.setOpaque(true); - newImageLabel.setBackground(Color.BLACK); + newImageLabel.setBackground(Palette.BLACK); JPanel newLabelPanel = new JPanel(new BorderLayout()); if (oldImage != null) { oldImageLabel = new GIconLabel(new ImageIcon(oldImage)); oldImageLabel.setOpaque(true); - oldImageLabel.setBackground(Color.BLACK); + oldImageLabel.setBackground(Palette.BLACK); } else { oldImageLabel = new GLabel(" Old image not found "); } newLabelPanel.add(createImageLabelComponent("New Image"), BorderLayout.NORTH); - newLabelPanel.setBorder(BorderFactory.createLineBorder(Color.black, 20)); + newLabelPanel.setBorder(BorderFactory.createLineBorder(Java.BORDER, 20)); newLabelPanel.add(newImageLabel, BorderLayout.CENTER); JPanel oldLabelPanel = new JPanel(new BorderLayout()); oldLabelPanel.add(createImageLabelComponent("Old Image"), BorderLayout.NORTH); - oldLabelPanel.setBorder(BorderFactory.createLineBorder(Color.black, 20)); + oldLabelPanel.setBorder(BorderFactory.createLineBorder(Java.BORDER, 20)); oldLabelPanel.add(oldImageLabel, BorderLayout.CENTER); imagePanel.add(oldLabelPanel, BorderLayout.WEST); @@ -215,10 +207,10 @@ public class ImageDialogProvider extends DialogComponentProvider { } private JLabel createNameLabel(String name) { - JLabel label = new GDHtmlLabel("" + name); + JLabel label = + new GDHtmlLabel("" + name); label.setOpaque(true); - // label.setForeground(Color.YELLOW); - label.setBackground(Color.BLACK); + label.setBackground(Palette.BLACK); label.setHorizontalTextPosition(SwingConstants.CENTER); return label; } diff --git a/Ghidra/Features/FunctionGraph/src/main/resources/images/function_graph.png b/Ghidra/Features/Base/src/main/resources/images/function_graph.png similarity index 100% rename from Ghidra/Features/FunctionGraph/src/main/resources/images/function_graph.png rename to Ghidra/Features/Base/src/main/resources/images/function_graph.png diff --git a/Ghidra/Features/FunctionGraph/src/main/resources/images/function_graph_curvey.png b/Ghidra/Features/Base/src/main/resources/images/function_graph_curvey.png similarity index 100% rename from Ghidra/Features/FunctionGraph/src/main/resources/images/function_graph_curvey.png rename to Ghidra/Features/Base/src/main/resources/images/function_graph_curvey.png diff --git a/Ghidra/Features/Base/src/main/resources/images/no_small.png b/Ghidra/Features/Base/src/main/resources/images/no_small.png new file mode 100644 index 0000000000..98f9f0d8bd Binary files /dev/null and b/Ghidra/Features/Base/src/main/resources/images/no_small.png differ diff --git a/Ghidra/Features/VersionTracking/src/main/resources/images/page_white_c.png b/Ghidra/Features/Base/src/main/resources/images/page_white_c.png similarity index 100% rename from Ghidra/Features/VersionTracking/src/main/resources/images/page_white_c.png rename to Ghidra/Features/Base/src/main/resources/images/page_white_c.png diff --git a/Ghidra/Features/ProgramDiff/src/main/resources/images/table_relationship.png b/Ghidra/Features/Base/src/main/resources/images/table_relationship.png similarity index 100% rename from Ghidra/Features/ProgramDiff/src/main/resources/images/table_relationship.png rename to Ghidra/Features/Base/src/main/resources/images/table_relationship.png diff --git a/Ghidra/Features/Base/src/main/resources/images/oxygen/16x16/text-x-csrc.png b/Ghidra/Features/Base/src/main/resources/images/text-x-csrc.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/oxygen/16x16/text-x-csrc.png rename to Ghidra/Features/Base/src/main/resources/images/text-x-csrc.png diff --git a/Ghidra/Features/Base/src/test.slow/java/docking/ComponentProviderActionsTest.java b/Ghidra/Features/Base/src/test.slow/java/docking/ComponentProviderActionsTest.java index 4f57794763..7c46341c68 100644 --- a/Ghidra/Features/Base/src/test.slow/java/docking/ComponentProviderActionsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/docking/ComponentProviderActionsTest.java @@ -29,18 +29,18 @@ import docking.action.*; import docking.actions.KeyEntryDialog; import docking.actions.ToolActions; import docking.tool.util.DockingToolConstants; +import generic.theme.GIcon; import ghidra.framework.options.ToolOptions; import ghidra.framework.plugintool.PluginTool; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; import ghidra.util.*; import resources.Icons; -import resources.ResourceManager; public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegrationTest { // note: this has to happen after the test framework is initialized, so it cannot be static - private final Icon ICON = ResourceManager.loadImage("images/refresh.png"); + private final Icon ICON = Icons.REFRESH_ICON; private static final String PROVIDER_NAME = "Test Action Provider"; private static final KeyStroke CONTROL_T = KeyStroke.getKeyStroke(KeyEvent.VK_T, DockingUtils.CONTROL_KEY_MODIFIER_MASK); @@ -498,8 +498,19 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio private void assertWindowMenuActionHasIcon(Icon expected) { DockingActionIf action = getWindowMenuShowProviderAction(); + Icon menuIcon = action.getMenuBarData().getMenuIcon(); assertEquals("Windows menu icons for provider does not match the value set on the provider", - expected, action.getMenuBarData().getMenuIcon()); + getDescription(expected), getDescription(menuIcon)); + } + + private String getDescription(Icon icon) { + if (icon instanceof GIcon) { + return ((GIcon) icon).getUrl().toString(); + } + if (icon instanceof ImageIcon) { + return ((ImageIcon) icon).getDescription(); + } + return icon.toString(); } private void assertToolbarActionHasIcon(Icon expected) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/UserDefinedPropertyMergeManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/UserDefinedPropertyMergeManagerTest.java index cd48effcc7..ac83b84ae7 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/UserDefinedPropertyMergeManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/UserDefinedPropertyMergeManagerTest.java @@ -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); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalysisOptions2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalysisOptions2Test.java index d4efc22138..34eca7b1e7 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalysisOptions2Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalysisOptions2Test.java @@ -31,6 +31,7 @@ import docking.ActionContext; import docking.action.DockingActionIf; import docking.options.editor.DefaultOptionComponent; import docking.widgets.table.GTable; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; import ghidra.app.services.*; @@ -42,6 +43,7 @@ import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.Program; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; +import ghidra.util.ColorUtils; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -59,7 +61,7 @@ public class AnalysisOptions2Test extends AbstractGhidraHeadedIntegrationTest { private static final String OLD_OPTION_DEFAULT_VALUE = "Old Default Value"; private static final String UNCHANGING_OPTION_DEFAULT_VALUE = "Unchanging Default Value"; - private static final Color NEW_OPTION_DEFAULT_VALUE_AS_COLOR = Color.GREEN; + private static final Color NEW_OPTION_DEFAULT_VALUE_AS_COLOR = Palette.GREEN; private TestEnv env; private PluginTool tool; @@ -349,7 +351,7 @@ public class AnalysisOptions2Test extends AbstractGhidraHeadedIntegrationTest { int r = Integer.parseInt(parts[0]); int g = Integer.parseInt(parts[1]); int b = Integer.parseInt(parts[2]); - return new Color(r, g, b); + return ColorUtils.getColor(r, g, b); } private void selectAnalyzer(String name) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTaskTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTaskTest.java index f9c136496b..0a706caae9 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTaskTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTaskTest.java @@ -429,7 +429,7 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat @Override public void close() { - runSwing(super::close); + runSwing(() -> super.close()); } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java index ca9d948c3c..85ec74cdff 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java @@ -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") diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/colorizer/ColorizingPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/colorizer/ColorizingPluginTest.java index 6d36f0db19..b5335ac963 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/colorizer/ColorizingPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/colorizer/ColorizingPluginTest.java @@ -33,6 +33,7 @@ import docking.widgets.EventTrigger; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldSelection; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.marker.MarkerManagerPlugin; @@ -48,6 +49,7 @@ import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; +import ghidra.util.ColorUtils; public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { @@ -119,7 +121,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { assertNavigationActionsEnabled(false); assertSetColorActionEnabled(true); - Color color = Color.RED; + Color color = Palette.RED; setColor(color); assertColorForAddress(color); @@ -133,7 +135,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { assertSetColorActionEnabled(true); - Color selectionColor = Color.BLUE; + Color selectionColor = Palette.BLUE; setColor(selectionColor); assertColorForSelection(selectionColor); @@ -150,7 +152,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { Address address1 = cb.getCurrentAddress(); Address address2 = address1.add(8); - Color color = Color.RED; + Color color = Palette.RED; setColor(color, address1, address2); assertColorForAddress(color, address1, address2); @@ -160,7 +162,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { createSelection(); - Color selectionColor = Color.BLUE; + Color selectionColor = Palette.BLUE; setColor(selectionColor); assertColorForSelection(selectionColor); @@ -178,7 +180,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { Address address2 = address1.add(8); Address address3 = address2.add(16); - Color color = new Color(100, 100, 100, 100); + Color color = ColorUtils.getColor(100, 100, 100, 100); setColor(color, address1, address2, address3); assertColorForAddress(color, address1, address2, address3); @@ -198,7 +200,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { // change the location so that the current line marker does not affect our color check below address = address.add(400); - Color color = new Color(100, 100, 100); + Color color = ColorUtils.getColor(100, 100, 100); setBackgroundFromAPI(address, color); assertMarkerColorAtAddress(address, color); @@ -218,7 +220,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { Address address2 = address1.add(8); Address address3 = address2.add(8); - Color color = new Color(100, 100, 100, 100); + Color color = ColorUtils.getColor(100, 100, 100, 100); setColor(color, address1, address2, address3); // start before the first address to test that the next range action is enabled and the @@ -254,7 +256,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { assertPreviousButtonEnabled(true); } - /** + /* * Tests navigation of offcut ranges when coloring is set from a GUI/API point-of-view. * * @throws Exception @@ -266,7 +268,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { assertNavigationActionsEnabled(false); Address initialAddress = cb.getCurrentAddress(); // 0x1001000 - Color selectionColor = Color.YELLOW; + Color selectionColor = Palette.YELLOW; createSelectionBytes("0x10036c0", 0, 0, "0x10036c6", 1, 2); // Sets offcut at end of range setColor(selectionColor); @@ -320,7 +322,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { } - /** + /* * Tests navigation of offcut ranges when coloring is set from a plugin point-of-view. * * @throws Exception @@ -333,7 +335,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest { // // Set some color ranges // - Color selectionColor = Color.GRAY; + Color selectionColor = Palette.GRAY; setColorOverRange(selectionColor, addr("0x10036c0"), addr("0x10036c9")); setColorOverRange(selectionColor, addr("0x10036d3"), addr("0x10036d6")); setColorOverRange(selectionColor, addr("0x10036e1"), addr("0x10036e6")); @@ -439,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); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/DisassembledViewPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/DisassembledViewPluginTest.java index fc90caea00..f9b6ee03a7 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/DisassembledViewPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/disassembler/DisassembledViewPluginTest.java @@ -15,10 +15,8 @@ */ package ghidra.app.plugin.core.disassembler; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; -import java.awt.Color; import java.awt.Font; import java.util.HashMap; import java.util.Map; @@ -30,6 +28,7 @@ import org.junit.*; import docking.ComponentProvider; import docking.widgets.fieldpanel.FieldPanel; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.ProgramPlugin; @@ -92,7 +91,7 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT openProgram("notepad"); // get the list hiding inside of the component provider - JList list = (JList) getInstanceField("contentList", componentProvider); + JList list = (JList) getInstanceField("contentList", componentProvider); // sanity check assertEquals("The component provider has data when it is not visible.", 0, @@ -100,9 +99,9 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT // show the plugin and make sure it is visible before we continue tool.showComponentProvider(componentProvider, true); - waitForPostedSwingRunnables(); + waitForSwing(); - ListModel modelOne = list.getModel(); + ListModel modelOne = list.getModel(); // now the list should have data, as it will populate itself off of the // current program location of the plugin @@ -116,10 +115,10 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT // scroll the display and force a new selection pageDown(cbPlugin.getFieldPanel()); simulateButtonPress(cbPlugin); - waitForPostedSwingRunnables(); + waitForSwing(); // get the data - ListModel modelTwo = list.getModel(); + ListModel modelTwo = list.getModel(); boolean sameData = compareListData(modelOne, modelTwo); assertTrue("The contents of the two lists are the same when they " + "should not be.", @@ -127,7 +126,7 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT // make sure no work is done when we are not visible tool.showComponentProvider(componentProvider, false); - waitForPostedSwingRunnables(); + waitForSwing(); assertEquals("The component provider has data when it is not visible.", 0, list.getModel().getSize()); @@ -135,7 +134,7 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT // show the plugin so that it will get the program location change // data tool.showComponentProvider(componentProvider, true); - waitForPostedSwingRunnables(); + waitForSwing(); // test that sending a bad address will not return any results or // throw any exceptions @@ -178,11 +177,11 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT openProgram("notepad"); tool.showComponentProvider(componentProvider, true); - waitForPostedSwingRunnables(); + waitForSwing(); // the Java component that is our display for the plugin - JList list = (JList) getInstanceField("contentList", componentProvider); - ListModel listContents = list.getModel(); + JList list = (JList) getInstanceField("contentList", componentProvider); + ListModel listContents = list.getModel(); // make sure that nothing happens on a single-selection plugin.processEvent(createProgramSelectionEvent(false)); @@ -213,7 +212,7 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT openProgram("notepad"); tool.showComponentProvider(componentProvider, true); - waitForPostedSwingRunnables(); + waitForSwing(); String[] fieldNames = { "selectedAddressColor", "addressForegroundColor", "backgroundColor", "font" }; @@ -230,35 +229,30 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT // get and change each options of interest String optionToChange = GhidraOptions.OPTION_SELECTION_COLOR; - Color currentColor = - opt.getColor(optionToChange, (Color) optionsMap.get("selectedAddressColor")); - opt.setColor(optionToChange, deriveNewColor(currentColor)); + opt.setColor(optionToChange, Palette.LIME); // the rest of the options to change are stored under a different // options node opt = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY); optionToChange = (String) getInstanceField("ADDRESS_COLOR_OPTION", componentProvider); - currentColor = - opt.getColor(optionToChange, (Color) optionsMap.get("addressForegroundColor")); - opt.setColor(optionToChange, deriveNewColor(currentColor)); + opt.setColor(optionToChange, Palette.GOLD); optionToChange = (String) getInstanceField("BACKGROUND_COLOR_OPTION", componentProvider); - currentColor = opt.getColor(optionToChange, (Color) optionsMap.get("backgroundColor")); - opt.setColor(optionToChange, deriveNewColor(currentColor)); + opt.setColor(optionToChange, Palette.LAVENDER); optionToChange = (String) getInstanceField("ADDRESS_FONT_OPTION", componentProvider); Font currentFont = opt.getFont(optionToChange, (Font) optionsMap.get("font")); opt.setFont(optionToChange, currentFont.deriveFont((float) currentFont.getSize() + 1)); - // now make sure that the changes have been propogated - for (int i = 0; i < fieldNames.length; i++) { + // now make sure that the changes have been propagated + for (String fieldName : fieldNames) { - Object newValue = getInstanceField(fieldNames[i], componentProvider); + Object newValue = getInstanceField(fieldName, componentProvider); assertTrue("The old value has not changed in response to " + - "changing the options. Value: " + fieldNames[i], - !(newValue.equals(optionsMap.get(fieldNames[i])))); + "changing the options. Value: " + fieldName, + !(newValue.equals(optionsMap.get(fieldName)))); } } @@ -282,26 +276,6 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT return new ProgramSelectionPluginEvent("CodeBrowserPlugin", selection, program); } - /** - * Creates a new Color object that is different than the one provided. - * - * @param originalColor The color from which the new Color will be - * derived. - * @return A new color that is different than the one given. - */ - public Color deriveNewColor(Color originalColor) { - Color newColor = null; - - if (originalColor == Color.BLACK) { - newColor = originalColor.brighter(); - } - else { - newColor = originalColor.darker(); - } - - return newColor; - } - /** * Simulates a user click in the code browser plugin. * @@ -330,7 +304,7 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT * @param modelTwo The second list contents to compare * @return True if both lists hold the equal contents in the same order. */ - private boolean compareListData(ListModel modelOne, ListModel modelTwo) { + private boolean compareListData(ListModel modelOne, ListModel modelTwo) { boolean isSame = false; if (modelOne.getSize() == modelTwo.getSize()) { @@ -350,19 +324,12 @@ public class DisassembledViewPluginTest extends AbstractGhidraHeadedIntegrationT return isSame; } - /** - * Opens the program of the given name and shows the tool with that - * program. - * - * @param name - * @throws Exception - */ private void openProgram(String name) throws Exception { ClassicSampleX86ProgramBuilder builder = new ClassicSampleX86ProgramBuilder(); program = builder.getProgram(); env.showTool(program); - waitForPostedSwingRunnables(); + waitForSwing(); } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/interpreter/InterpreterPanelTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/interpreter/InterpreterPanelTest.java index 9887e24f6f..e080b39e2b 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/interpreter/InterpreterPanelTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/interpreter/InterpreterPanelTest.java @@ -201,7 +201,7 @@ public class InterpreterPanelTest extends AbstractGhidraHeadedIntegrationTest { } @Override - public ImageIcon getIcon() { + public Icon getIcon() { return Icons.STOP_ICON; } @@ -222,8 +222,7 @@ public class InterpreterPanelTest extends AbstractGhidraHeadedIntegrationTest { return result; } - private void doSwingMultilinePasteTest(List multiLineTestValues) - throws IOException { + private void doSwingMultilinePasteTest(List multiLineTestValues) throws IOException { // simulates what happens during a paste when multi-line string with // "\n"s is pasted. runSwingLater(() -> { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/marker/MarkerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/marker/MarkerTest.java index 3e8a6f6ee9..3f897f2b04 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/marker/MarkerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/marker/MarkerTest.java @@ -33,6 +33,7 @@ import docking.widgets.EventTrigger; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldSelection; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.cmd.data.CreateStructureCmd; import ghidra.app.events.ProgramActivatedPluginEvent; import ghidra.app.events.ProgramSelectionPluginEvent; @@ -342,7 +343,7 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest { Program program2 = loadSecondProgram(); - Color startColor = Color.PINK; + Color startColor = Palette.PINK; MarkerSet markersP1 = markerService.createPointMarker("Awesome Markers", "Description", program, 0, true, true, true, startColor, null, true); @@ -358,8 +359,8 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest { assertMarkerColor(program, addressP1, startColor); assertMarkerColor(program2, addressP2, startColor); - Color c1 = Color.ORANGE; - Color c2 = Color.BLUE; + Color c1 = Palette.ORANGE; + Color c2 = Palette.BLUE; setMarkerColor(markersP1, c1); setMarkerColor(markersP2, c2); @@ -367,8 +368,8 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest { assertMarkerColor(program, addressP1, c1); assertMarkerColor(program2, addressP2, c2); - Color c3 = Color.RED; - Color c4 = Color.GREEN; + Color c3 = Palette.RED; + Color c4 = Palette.GREEN; // change markers for current program setMarkerColor(markersP1, c3); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPluginTest.java index e2a4b9e0ab..37b8e85f39 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/NextPrevCodeUnitPluginTest.java @@ -17,16 +17,15 @@ package ghidra.app.plugin.core.navigation; import static org.junit.Assert.*; -import java.awt.Color; - import javax.swing.Icon; -import javax.swing.ImageIcon; import org.junit.*; import docking.action.DockingActionIf; import docking.menu.ActionState; import docking.menu.MultiStateDockingAction; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.cmd.data.CreateDataCmd; import ghidra.app.cmd.disassemble.DisassembleCommand; import ghidra.app.plugin.core.bookmark.BookmarkEditCmd; @@ -40,7 +39,7 @@ import ghidra.program.model.listing.*; import ghidra.program.model.mem.Memory; import ghidra.test.*; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; +import resources.Icons; public class NextPrevCodeUnitPluginTest extends AbstractGhidraHeadedIntegrationTest { @@ -122,8 +121,8 @@ public class NextPrevCodeUnitPluginTest extends AbstractGhidraHeadedIntegrationT @Test public void testToggle() throws Exception { - Icon upIcon = ResourceManager.loadImage("images/up.png"); - Icon downIcon = ResourceManager.loadImage("images/down.png"); + Icon upIcon = new GIcon("icon.up"); + Icon downIcon = new GIcon("icon.down"); assertEquals(downIcon, direction.getToolBarData().getIcon()); assertStartsWith("Go To Next Instruction", nextInstruction.getDescription()); @@ -796,10 +795,9 @@ public class NextPrevCodeUnitPluginTest extends AbstractGhidraHeadedIntegrationT public void testSearchCustomBobBookmark() throws Exception { assertAddress("01001000"); - ImageIcon bookmarkBobIcon = - ResourceManager.loadImage("images/applications-engineering.png"); + Icon bookmarkBobIcon = Icons.ADD_ICON; // arbitrary icon - BookmarkType bob = bookmarkManager.defineType("BOB", bookmarkBobIcon, Color.YELLOW, 0); + BookmarkType bob = bookmarkManager.defineType("BOB", bookmarkBobIcon, Palette.YELLOW, 0); String typeString = bob.getTypeString(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/progmgr/MultiTabPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/progmgr/MultiTabPluginTest.java index 66ba781b5b..4686802c1c 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/progmgr/MultiTabPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/progmgr/MultiTabPluginTest.java @@ -31,6 +31,7 @@ import org.junit.*; import docking.action.DockingAction; import docking.widgets.fieldpanel.FieldPanel; import generic.test.TestUtils; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.marker.MarkerManagerPlugin; import ghidra.app.services.*; @@ -338,20 +339,12 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest { fp.setCursorPosition(BigInteger.valueOf(4), 0, 0, 0); }); - assertEquals(Color.BLUE, getFieldPanelBackgroundColor(fp, BigInteger.ZERO)); - assertEquals(Color.WHITE, getFieldPanelBackgroundColor(fp, BigInteger.ONE)); assertEquals(BigInteger.valueOf(4), fp.getCursorLocation().getIndex()); - Color lineColor = (Color) getInstanceField("CURSOR_LINE_COLOR", CodeBrowserPlugin.class); - programManager.setCurrentProgram(p2); - assertEquals(lineColor, getFieldPanelBackgroundColor(fp, BigInteger.ZERO)); - assertEquals(Color.WHITE, getFieldPanelBackgroundColor(fp, BigInteger.ONE)); assertEquals(BigInteger.ZERO, fp.getCursorLocation().getIndex()); programManager.setCurrentProgram(p1); - assertEquals(Color.BLUE, getFieldPanelBackgroundColor(fp, BigInteger.ZERO)); - assertEquals(Color.WHITE, getFieldPanelBackgroundColor(fp, BigInteger.ONE)); assertEquals(BigInteger.valueOf(4), fp.getCursorLocation().getIndex()); } @@ -548,7 +541,7 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest { private MarkerSet createMarkers(final Program p) { final AtomicReference ref = new AtomicReference<>(); runSwing(() -> ref.set(markerService.createPointMarker("Test", "Test", p, 40, false, false, - true, Color.BLUE, null))); + true, Palette.BLUE, null))); return ref.get(); } @@ -558,10 +551,6 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest { return windowForComponent(listPanel); } - private Color getFieldPanelBackgroundColor(FieldPanel fp, BigInteger index) { - return runSwing(() -> fp.getBackgroundColor(index)); - } - private void performPreviousAction() throws Exception { MultiTabPlugin plugin = env.getPlugin(MultiTabPlugin.class); DockingAction goToPreviousProgramAction = @@ -613,8 +602,9 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest { private void addComment(Program p) { int transactionID = p.startTransaction("test"); try { - p.getListing().setComment(p.getAddressFactory().getAddress("01000000"), - CodeUnit.REPEATABLE_COMMENT, "This is a simple comment change."); + p.getListing() + .setComment(p.getAddressFactory().getAddress("01000000"), + CodeUnit.REPEATABLE_COMMENT, "This is a simple comment change."); } finally { p.endTransaction(transactionID, true); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin1Test.java index 4c555c0134..0287766aba 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin1Test.java @@ -30,6 +30,7 @@ import javax.swing.tree.TreePath; import org.junit.*; import docking.action.DockingActionIf; +import generic.theme.GIcon; import ghidra.app.services.GoToService; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; @@ -43,7 +44,6 @@ import ghidra.program.util.GroupPath; import ghidra.program.util.ProgramLocation; import ghidra.util.Swing; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest { @@ -633,7 +633,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest { int row = getRowForPath(nodes[0].getTreePath()); Component comp = getCellRendererComponentForLeaf(nodes[0], row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_FRAGMENT), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT), ((JLabel) comp).getIcon()); } @@ -676,12 +676,12 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest { int row = getRowForPath(node.getTreePath()); Component comp = getCellRendererComponentForLeaf(node, row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_FRAGMENT), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT), ((JLabel) comp).getIcon()); row = getRowForPath(n2.getTreePath()); comp = getCellRendererComponentForLeaf(n2, row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_FRAGMENT), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT), ((JLabel) comp).getIcon()); setSelectionPaths(new TreePath[] { n2.getTreePath() }); @@ -689,12 +689,12 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest { row = getRowForPath(n2.getTreePath()); comp = getCellRendererComponentForLeaf(n2, row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_FRAGMENT), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT), ((JLabel) comp).getIcon()); row = getRowForPath(node.getTreePath()); getCellRendererComponentForLeaf(node, row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.FRAGMENT), + assertEquals(new GIcon(DnDTreeCellRenderer.FRAGMENT), ((JLabel) comp).getIcon()); } @@ -735,9 +735,9 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest { runSwing(() -> tree.removeFromView(finalNode.getTreePath())); int row = getRowForPath(node.getTreePath()); - 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), ((JLabel) comp).getIcon()); } @@ -833,9 +833,10 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest { assertTrue(getView().hasSameAddresses(viewMgrService.getCurrentView())); int row = getRowForPath(child.getTreePath()); - 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), + ((JLabel) comp).getIcon()); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin2Test.java index 31a7ec6cfc..5fc53c71b1 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin2Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin2Test.java @@ -26,12 +26,12 @@ import org.junit.*; import docking.ActionContext; import docking.action.DockingActionIf; +import generic.theme.GIcon; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*; -import resources.ResourceManager; /** * Tests for cut/copy/paste in the Program tree. @@ -969,7 +969,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest { int row = getRowForPath(nodes[0].getTreePath()); Component comp = getCellRendererComponentForNonLeaf(nodes[0], row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_CLOSED_FOLDER_WITH_DESC), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_CLOSED_FOLDER_WITH_DESC), ((JLabel) comp).getIcon()); visitNode(nodes[0]); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin3Test.java index 8997562508..f88e97078e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePlugin3Test.java @@ -27,6 +27,7 @@ import javax.swing.JLabel; import org.junit.*; import docking.action.DockingActionIf; +import generic.theme.GIcon; import ghidra.app.util.SelectionTransferData; import ghidra.app.util.SelectionTransferable; import ghidra.program.database.ProgramBuilder; @@ -35,7 +36,6 @@ import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*; import ghidra.util.exception.NotFoundException; -import resources.ResourceManager; /** * Tests for drag/drop/reorder for copy and move in the program tree. @@ -183,7 +183,7 @@ public class ProgramTreePlugin3Test extends AbstractProgramTreePluginTest { setSelectionPath(node); AddressSet fragSet = new AddressSet(debugNode.getFragment()); - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); list.add(debugNode); //drag .debug_data to 01004a15 @@ -391,7 +391,7 @@ public class ProgramTreePlugin3Test extends AbstractProgramTreePluginTest { int row = getRowForPath(nodes[0].getTreePath()); Component comp = getCellRendererComponentForNonLeaf(nodes[0], row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_CLOSED_FOLDER_WITH_DESC), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_CLOSED_FOLDER_WITH_DESC), ((JLabel) comp).getIcon()); visitNode(nodes[0]); @@ -428,7 +428,7 @@ public class ProgramTreePlugin3Test extends AbstractProgramTreePluginTest { waitForSwing(); Component comp = getCellRendererComponentForLeaf(n, row); - assertEquals(ResourceManager.loadImage(DnDTreeCellRenderer.VIEWED_FRAGMENT), + assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT), ((JLabel) comp).getIcon()); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePluginShowInViewTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePluginShowInViewTest.java index 4ef19fac45..af616f17b0 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePluginShowInViewTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/programtree/ProgramTreePluginShowInViewTest.java @@ -30,6 +30,7 @@ import org.junit.*; import docking.ActionContext; import docking.action.DockingActionIf; import docking.action.ToggleDockingAction; +import generic.theme.GIcon; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin; import ghidra.app.services.*; @@ -42,7 +43,6 @@ import ghidra.program.util.GroupPath; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; import ghidra.util.task.RunManager; -import resources.ResourceManager; public class ProgramTreePluginShowInViewTest extends AbstractGhidraHeadedIntegrationTest { @@ -514,7 +514,7 @@ public class ProgramTreePluginShowInViewTest extends AbstractGhidraHeadedIntegra int row = getRow(node.getTreePath()); JLabel comp = render(tree, node, true, isExpanded, isLeaf, row, false); - assertEquals(ResourceManager.loadImage(iconName), getIcon(comp)); + assertEquals(new GIcon(iconName), getIcon(comp)); } private void waitForRunManager() { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java index 2592c99220..245f00a1ab 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/datatype/DataTypeSelectionDialogTest.java @@ -43,6 +43,7 @@ import docking.widgets.DropDownTextFieldDataModel; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; import generic.test.AbstractGTest; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.WindowUtilities; import generic.util.image.ImageUtils; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; @@ -1195,7 +1196,7 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration final JTextField panelUpdateField = new JTextField("Hey Mom"); Highlighter highlighter = panelUpdateField.getHighlighter(); highlighter.addHighlight(0, 2, - new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW)); + new DefaultHighlighter.DefaultHighlightPainter(Palette.YELLOW)); JPanel editorPanel = new JPanel(new BorderLayout()); DataTypeSelectionEditor editor = new DataTypeSelectionEditor(tool, AllowedDataTypes.ALL); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/viewer/field/AnnotationTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/viewer/field/AnnotationTest.java index 84057380b0..8bb7972354 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/viewer/field/AnnotationTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/viewer/field/AnnotationTest.java @@ -28,6 +28,8 @@ import org.junit.Before; import org.junit.Test; import docking.widgets.fieldpanel.field.*; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.nav.Navigatable; import ghidra.app.nav.TestDummyNavigatable; import ghidra.app.services.*; @@ -670,7 +672,7 @@ public class AnnotationTest extends AbstractGhidraHeadedIntegrationTest { FieldElement[] strings = getNumberOfSubFieldElements(fieldElement); assertEquals("Unexpected number of AttributedStrings from comment text.", 2, strings.length); - assertEquals("Did not get the expected error annotation string color.", Color.RED, + assertEquals("Did not get the expected error annotation string color.", Messages.ERROR, strings[1].getColor(0)); } @@ -703,7 +705,7 @@ public class AnnotationTest extends AbstractGhidraHeadedIntegrationTest { FieldElement[] strings = getNumberOfSubFieldElements(fieldElement); assertEquals("Unexpected number of AttributedStrings from comment text.", 2, strings.length); - assertEquals("Did not get the expected error annotation string color.", Color.RED, + assertEquals("Did not get the expected error annotation string color.", Messages.ERROR, strings[1].getColor(0)); } @@ -757,7 +759,7 @@ public class AnnotationTest extends AbstractGhidraHeadedIntegrationTest { private AttributedString prototype() { FontMetrics fontMetrics = getFontMetrics(); - AttributedString prototypeString = new AttributedString("", Color.BLACK, fontMetrics); + AttributedString prototypeString = new AttributedString("", Colors.FOREGROUND, fontMetrics); return prototypeString; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/FrontEndPluginActionsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/FrontEndPluginActionsTest.java index e270daac2b..1f516bbb64 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/FrontEndPluginActionsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/main/datatree/FrontEndPluginActionsTest.java @@ -52,7 +52,6 @@ import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; import ghidra.util.task.TaskMonitor; import resources.MultiIcon; -import resources.ResourceManager; /** * Tests for actions in the front end (Ghidra project window) @@ -749,9 +748,6 @@ public class FrontEndPluginActionsTest extends AbstractGhidraHeadedIntegrationTe performAction(readOnlyAction, getTreeActionContext(), true); assertTrue(((DomainFileNode) npNode).getDomainFile().isReadOnly()); - ImageIcon icon = ResourceManager.loadImage("fileIcons/ProgramReadOnly.gif"); - icon = ResourceManager.getScaledIcon(icon, 16, 16); - assertTrue(npNode.getIcon(false) instanceof MultiIcon); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java index ca07d00193..b23ec1bc91 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java @@ -26,6 +26,7 @@ import javax.swing.KeyStroke; import org.junit.*; import generic.stl.Pair; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.gotoquery.GoToServicePlugin; import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; @@ -91,7 +92,7 @@ public class ToolPluginOptionsTest extends AbstractGhidraHeadedIntegrationTest { String optionName = " Highlight Color"; Color highlightColor = options.getColor(optionName, null); assertNotNull("Existing option has been removed--update test", highlightColor); - options.setColor(optionName, Color.RED); + options.setColor(optionName, Palette.RED); optionName = "Highlight Search Results"; boolean highlightResults = options.getBoolean(optionName, true); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java index e5087e50b5..bb7cba6f52 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java @@ -31,7 +31,7 @@ import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.*; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; -import resources.ResourceManager; +import resources.Icons; /** * Tests for the configuring a tool. @@ -54,15 +54,13 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { public void tearDown() throws Exception { close(dialog); env.dispose(); - - sleep(1000); } @Test public void testPluginPackage_ReleasedPackage_ReleasedPlugins() throws Exception { PluginPackage testPackage = new PluginPackage("TEST", - ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") { + Icons.ADD_ICON, "Test plugin pacakge") { // }; @@ -99,7 +97,7 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { public void testPluginPackage_ReleasedPackage_ReleasedAndStablePlugins() throws Exception { PluginPackage testPackage = new PluginPackage("TEST", - ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") { + Icons.ADD_ICON, "Test plugin pacakge") { // }; @@ -140,7 +138,7 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { public void testPluginPackage_StablePackage_ReleasedAndStablePlugins() throws Exception { PluginPackage testPackage = new PluginPackage("TEST", - ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") { + Icons.ADD_ICON, "Test plugin pacakge") { @Override public PluginStatus getActivationLevel() { return PluginStatus.STABLE; @@ -185,7 +183,7 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { throws Exception { PluginPackage testPackage = new PluginPackage("TEST", - ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") { + Icons.ADD_ICON, "Test plugin pacakge") { @Override public PluginStatus getActivationLevel() { return PluginStatus.STABLE; @@ -235,7 +233,7 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { public void testPluginPackage_ReleasedPackage_StablePlugins() throws Exception { PluginPackage testPackage = new PluginPackage("TEST", - ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") { + Icons.ADD_ICON, "Test plugin pacakge") { // }; @@ -274,7 +272,7 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { throws Exception { PluginPackage testPackage = new PluginPackage("TEST", - ResourceManager.loadImage("images/Data_32.png"), "Test plugin pacakge") { + Icons.ADD_ICON, "Test plugin pacakge") { // }; @@ -456,25 +454,25 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest { } /* - + testPluginPackage_Released() { - + Click to add all - + Click to remove All - + } - - + + testPluginPackage_Stable_ReleasedPlugins() - + testPluginPackage_Stable_ReleasedAndStablePlugins() testPluginPackage_Stable_ReleasedAndStableAndUnstablePlugins() -unstable goes to 'experimental' - + testPluginPackage - + */ } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java index f06e93686d..af43b9faba 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/SettingsTest.java @@ -17,10 +17,9 @@ package ghidra.program.database.data; import static org.junit.Assert.*; -import java.awt.Color; - import org.junit.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.docking.settings.*; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; @@ -154,7 +153,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest { defaultSettings.getLong("padded").longValue()); try { - defaultSettings.setValue("format", Color.RED); + defaultSettings.setValue("format", Palette.RED); Assert.fail("Should not be able to set arbitrary objects"); } catch (IllegalArgumentException e) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java index b6da8f560a..48eff24326 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/bean/opteditor/OptionsDialogTest.java @@ -44,6 +44,7 @@ import docking.widgets.table.RowObjectFilterModel; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; import generic.test.TestUtils; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.GhidraOptions; import ghidra.app.plugin.core.console.ConsolePlugin; import ghidra.app.util.viewer.options.OptionsGui; @@ -55,6 +56,7 @@ import ghidra.framework.plugintool.dialog.KeyBindingsPanel; import ghidra.framework.preferences.Preferences; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; +import ghidra.util.ColorUtils; /** * Tests for the options dialog. @@ -123,7 +125,8 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { selectAddressEntryInScreenElementOptionsList(optionsGui); - Color newColor = new Color(255, addressFieldColor.getGreen(), addressFieldColor.getBlue()); + Color newColor = + ColorUtils.getColor(255, addressFieldColor.getGreen(), addressFieldColor.getBlue()); setAddressColorValueInOptionsGUI(optionsGui, newColor); // close the options @@ -349,13 +352,13 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { JColorChooser chooser = findComponent(window, JColorChooser.class); assertNotNull(chooser); - chooser.setColor(Color.BLUE); + chooser.setColor(Palette.BLUE); PropertyEditor editor = getPropertyEditorForProperty(simpleOptionsPanel, "Favorite Color"); JButton okButton = findButtonByText(window, "OK"); assertNotNull(okButton); pressButton(okButton); - assertEquals(Color.BLUE, editor.getValue()); + assertColorsEqual(Palette.BLUE, (Color) editor.getValue()); } @Test @@ -628,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(Color.BLUE); - - JButton okButton = findButtonByText(window, "OK"); - assertNotNull(okButton); - pressButton(okButton); + triggerText(component, "Bar"); waitForSwing(); @@ -654,9 +648,9 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { Options options = tool.getOptions(ToolConstants.TOOL_OPTIONS); - Color c = options.getColor("Favorite Color", Color.RED); - - assertEquals(Color.BLUE, c); + Color c = options.getColor("Favorite Color", Palette.RED); + String currentValue = options.getString("Favorite String", null); + assertEquals("Bar", currentValue); assertTrue(tool.hasConfigChanged()); } @@ -686,7 +680,7 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { JColorChooser chooser = findComponent(window, JColorChooser.class); assertNotNull(chooser); - chooser.setColor(Color.BLUE); + chooser.setColor(Palette.BLUE); JButton okButton = findButtonByText(window, "OK"); assertNotNull(okButton); @@ -700,17 +694,21 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { Options options = tool.getOptions(ToolConstants.TOOL_OPTIONS); - Color c = options.getColor("Favorite Color", Color.RED); + Color c = options.getColor("Favorite Color", Palette.RED); - assertEquals(Color.BLUE, c); + assertColorsEqual(Palette.BLUE, c); env.saveRestoreToolState(); tool = env.getTool(); - assertEquals(Color.BLUE, options.getColor("Favorite Color", null)); + assertColorsEqual(Palette.BLUE, options.getColor("Favorite Color", null)); } +//================================================================================================= +// Inner Classes +//================================================================================================= + private KeyStroke getKeyBinding(String actionName) throws Exception { OptionsEditor editor = seleNodeWithCustomEditor("Key Bindings"); KeyBindingsPanel panel = (KeyBindingsPanel) getInstanceField("panel", editor); @@ -1106,8 +1104,11 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest { options.setInt(name, 300); name = "Favorite Color"; - options.registerOption(name, Color.RED, null, "description"); - options.setColor(name, Color.RED); + + options.registerOption(name, Palette.RED, null, "description"); + + name = "Favorite String"; + options.registerOption(name, "Foo", null, "description"); // select the middle button name = "Mouse Buttons" + Options.DELIMITER + "Mouse Button To Activate"; diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/C/CParserUtilsTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/C/CParserUtilsTest.java index 35402ba727..4668285c76 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/C/CParserUtilsTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/C/CParserUtilsTest.java @@ -15,33 +15,30 @@ */ package ghidra.app.util.cparser.C; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import org.junit.Assert; import org.junit.Test; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class CParserUtilsTest extends AbstractGenericTest { - public CParserUtilsTest() { - super(); - } - @Test - public void testUserMessage_OnTokenMgrError() { + public void testUserMessage_OnTokenMgrError() { String function = "void bob@12(int a)"; Throwable t = getParseError(function); String message = CParserUtils.handleParseProblem(t, function); String characterInfo = "near character 8"; - String invalidInfo = "@"; + String invalidInfo = "@"; assertTrue(message.contains(characterInfo)); assertTrue(message.contains(invalidInfo)); } @Test - public void testUserMessage_OnParseException() { + public void testUserMessage_OnParseException() { String function = "void bob(int a)()"; Throwable t = getParseError(function); String message = CParserUtils.handleParseProblem(t, function); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/DataTypeDifferTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/DataTypeDifferTest.java index ad0ee0c5aa..c4ec247eaa 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/DataTypeDifferTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/DataTypeDifferTest.java @@ -27,6 +27,8 @@ import org.junit.Assert; import org.junit.Test; import docking.widgets.label.GHtmlLabel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.util.html.diff.*; public class DataTypeDifferTest { @@ -471,7 +473,7 @@ public class DataTypeDifferTest { for (ValidatableLine line : lines) { if (line.isDiffColored()) { - buffy.append(""); + buffy.append(""); } buffy.append(line.getText()); @@ -492,14 +494,14 @@ public class DataTypeDifferTest { JPanel rightPanel = new JPanel(new BorderLayout()); JLabel rightLabel = new GHtmlLabel(htmlLeft); rightLabel.setOpaque(true); - rightLabel.setBackground(Color.WHITE); + rightLabel.setBackground(Colors.BACKGROUND); rightLabel.setVerticalAlignment(SwingConstants.TOP); rightPanel.add(rightLabel); JPanel leftPanel = new JPanel(new BorderLayout()); JLabel leftLabel = new GHtmlLabel(htmlRight); leftLabel.setOpaque(true); - leftLabel.setBackground(Color.WHITE); + leftLabel.setBackground(Colors.BACKGROUND); leftLabel.setVerticalAlignment(SwingConstants.TOP); leftPanel.add(leftLabel); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java index 441144d0d8..bca1b00dd5 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/html/HTMLDataTypeRepresentationTest.java @@ -29,6 +29,7 @@ import org.junit.*; import docking.widgets.label.GDHtmlLabel; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.ToolTipUtils; import ghidra.program.model.data.*; import ghidra.program.model.data.Composite; @@ -1474,7 +1475,7 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest { StringBuffer buffy1 = new StringBuffer(rightHtml); JLabel rightLabel = new GDHtmlLabel(); rightLabel.setOpaque(true); - rightLabel.setBackground(Color.WHITE); + rightLabel.setBackground(Colors.BACKGROUND); rightLabel.setVerticalAlignment(SwingConstants.TOP); rightPanel.add(rightLabel); @@ -1484,7 +1485,7 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest { StringBuffer buffy2 = new StringBuffer(leftHtml); JLabel leftLabel = new GDHtmlLabel(); leftLabel.setOpaque(true); - leftLabel.setBackground(Color.WHITE); + leftLabel.setBackground(Colors.BACKGROUND); leftLabel.setVerticalAlignment(SwingConstants.TOP); leftPanel.add(leftLabel); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/data/OptionsDBTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/data/OptionsDBTest.java index 71b1396b8c..e48a7012e2 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/data/OptionsDBTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/data/OptionsDBTest.java @@ -29,7 +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.ThemeManager; 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); + ThemeManager.getInstance().setColor("color.test", Palette.MAGENTA); + testColor = new GColor("color.test"); } private void saveAndRestoreOptions() { @@ -194,9 +200,9 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testSaveColorOption() { - options.setColor("Foo", Color.RED); + options.setColor("Foo", Palette.RED); saveAndRestoreOptions(); - assertEquals(Color.RED, options.getColor("Foo", Color.BLUE)); + assertEquals(Palette.RED.getRGB(), options.getColor("Foo", Palette.BLUE).getRGB()); } @Test @@ -262,7 +268,7 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testRemove() { - options.setColor("COLOR", Color.RED); + options.setColor("COLOR", Palette.RED); assertTrue(options.contains("COLOR")); options.removeOption("COLOR"); assertTrue(!options.contains("COLOR")); @@ -271,7 +277,7 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testGetOptionNames() { - options.setColor("COLOR", Color.red); + options.setColor("COLOR", Palette.RED); options.setInt("INT", 3); List optionNames = options.getOptionNames(); assertTrue(optionNames.contains("COLOR")); @@ -280,18 +286,26 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testGetDefaultValue() { - options.registerOption("Foo", Color.RED, null, "description"); + options.registerOption("Foo", 5, null, "description"); + options.setInt("Foo", 10); + assertEquals(10, options.getInt("Foo", 0)); + assertEquals(Integer.valueOf(5), options.getDefaultValue("Foo")); + } + + @Test + public void testGetDefaultValueWithThemeValues() { + options.registerThemeColorBinding("Foo", "color.test", null, "description"); options.setColor("Foo", Color.BLUE); - assertEquals(Color.BLUE, options.getColor("Foo", null)); - assertEquals(Color.RED, options.getDefaultValue("Foo")); + assertColorsEqual(Color.BLUE, options.getColor("Foo", null)); + assertColorsEqual(Color.BLUE, (Color) options.getDefaultValue("Foo")); } @Test public void testRegisterPropertyEditor() { MyPropertyEditor editor = new MyPropertyEditor(); - options.registerOption("color", OptionType.COLOR_TYPE, Color.RED, null, "description", + options.registerOption("foo", OptionType.INT_TYPE, 5, null, "description", editor); - assertEquals(editor, options.getRegisteredPropertyEditor("color")); + assertEquals(editor, options.getRegisteredPropertyEditor("foo")); } @@ -304,12 +318,20 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testRestoreOptionValue() { - options.registerOption("Foo", Color.RED, null, "description"); - options.setColor("Foo", Color.BLUE); - assertEquals(Color.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(Color.RED, options.getColor("Foo", null)); + assertEquals(4, options.getInt("Foo", 0)); + } + @Test + public void testRestoreThemeOptionValue() { + options.registerThemeColorBinding("Foo", "color.test", 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 @@ -403,11 +425,11 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testCopyOptions() { options.setInt("INT", 3); - options.setColor("COLOR", Color.RED); + options.setColor("COLOR", Palette.RED); ToolOptions options2 = new ToolOptions("aaa"); options2.copyOptions(options); assertEquals(3, options.getInt("INT", 3)); - assertEquals(Color.RED, options.getColor("COLOR", null)); + assertEquals(Palette.RED, options.getColor("COLOR", null)); } @Test @@ -550,17 +572,32 @@ public class OptionsDBTest extends AbstractGenericTest { @Test public void testSettingValueToNull() { - options.registerOption("Bar", Color.BLUE, null, "description"); - options.setColor("Bar", Color.red); - options.setColor("Bar", null); - assertEquals(null, options.getColor("Bar", null)); + // 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", 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.registerThemeColorBinding("Bar", "color.test", null, "description"); + try { + options.setColor("Bar", null); + fail("Expected exception setting theme value to null"); + } + catch (IllegalArgumentException e) { + // expected + } } @Test public void testNullValueWillUsedPassedInDefault() { - options.setColor("Bar", Color.red); + options.setColor("Bar", Palette.RED); options.setColor("Bar", null); - assertEquals(Color.BLUE, options.getColor("Bar", Color.BLUE)); + assertEquals(Palette.BLUE, options.getColor("Bar", Palette.BLUE)); } @Test diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/FileOptionsTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/FileOptionsTest.java index 4015093c27..5c327725d8 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/FileOptionsTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/FileOptionsTest.java @@ -24,6 +24,7 @@ import java.io.IOException; import org.junit.Test; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class FileOptionsTest extends AbstractGenericTest { @@ -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(Color.BLUE, restored.getColor("ccc", null)); + assertEquals(Color.BLUE.getRGB(), restored.getColor("ccc", null).getRGB()); assertEquals(custom, restored.getCustomOption("ddd", null)); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionTypeTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionTypeTest.java index 41c826b459..34cab00442 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionTypeTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionTypeTest.java @@ -15,8 +15,7 @@ */ package ghidra.framework.options; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.awt.Color; import java.awt.Font; @@ -28,6 +27,7 @@ import javax.swing.KeyStroke; import org.junit.Test; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class OptionTypeTest extends AbstractGenericTest { static public enum FOO { @@ -39,63 +39,63 @@ public class OptionTypeTest extends AbstractGenericTest { } @Test - public void testIntConversion() { + public void testIntConversion() { String string = OptionType.INT_TYPE.convertObjectToString(7); assertEquals(Integer.valueOf(7), OptionType.INT_TYPE.convertStringToObject(string)); } @Test - public void testLongConversion() { + public void testLongConversion() { String string = OptionType.LONG_TYPE.convertObjectToString(7); assertEquals(Long.valueOf(7), OptionType.LONG_TYPE.convertStringToObject(string)); } @Test - public void testFloatConversion() { + public void testFloatConversion() { String string = OptionType.FLOAT_TYPE.convertObjectToString(2.5); assertEquals(Float.valueOf(2.5f), OptionType.FLOAT_TYPE.convertStringToObject(string)); } @Test - public void testDoubleConversion() { + public void testDoubleConversion() { String string = OptionType.DOUBLE_TYPE.convertObjectToString(2.5); assertEquals(Double.valueOf(2.5f), OptionType.DOUBLE_TYPE.convertStringToObject(string)); } @Test - public void testStringConversion() { + public void testStringConversion() { String string = OptionType.STRING_TYPE.convertObjectToString("HEY"); assertEquals("HEY", OptionType.STRING_TYPE.convertStringToObject(string)); } @Test - public void testBooleanConversion() { + public void testBooleanConversion() { String string = OptionType.BOOLEAN_TYPE.convertObjectToString(Boolean.FALSE); assertEquals(Boolean.FALSE, OptionType.BOOLEAN_TYPE.convertStringToObject(string)); } @Test - public void testDateConversion() { + public void testDateConversion() { Date date = new Date(); String string = OptionType.DATE_TYPE.convertObjectToString(date); assertEquals(date, OptionType.DATE_TYPE.convertStringToObject(string)); } @Test - public void testEnumConversion() { + public void testEnumConversion() { String string = OptionType.ENUM_TYPE.convertObjectToString(FOO.BBB); assertEquals(FOO.BBB, OptionType.ENUM_TYPE.convertStringToObject(string)); } @Test - public void testCustomConversion() { + public void testCustomConversion() { String string = OptionType.CUSTOM_TYPE.convertObjectToString(new MyCustomOption(5, "ABC")); assertEquals(new MyCustomOption(5, "ABC"), OptionType.CUSTOM_TYPE.convertStringToObject(string)); } @Test - public void testByteArrayConversion() { + public void testByteArrayConversion() { byte[] bytes = { (byte) 3, (byte) 4 }; String string = OptionType.BYTE_ARRAY_TYPE.convertObjectToString(bytes); byte[] newBytes = (byte[]) OptionType.BYTE_ARRAY_TYPE.convertStringToObject(string); @@ -105,7 +105,7 @@ public class OptionTypeTest extends AbstractGenericTest { } @Test - public void testFileConversion() { + public void testFileConversion() { String testPath = "users/bin/what"; File file = new File(testPath); String string = OptionType.FILE_TYPE.convertObjectToString(file); @@ -116,21 +116,22 @@ public class OptionTypeTest extends AbstractGenericTest { } @Test - public void testColorConversion() { - Color c = new Color(100, 150, 200); + public void testColorConversion() { + Color c = Palette.BLUE; String string = OptionType.COLOR_TYPE.convertObjectToString(c); - assertEquals(c, OptionType.COLOR_TYPE.convertStringToObject(string)); + assertEquals(c.getRGB(), + ((Color) OptionType.COLOR_TYPE.convertStringToObject(string)).getRGB()); } @Test - public void testFontConversion() { + public void testFontConversion() { Font font = new Font("Monospaced", Font.BOLD, 24); String string = OptionType.FONT_TYPE.convertObjectToString(font); assertEquals(font, OptionType.FONT_TYPE.convertStringToObject(string)); } @Test - public void testKeyStrokeConversion() { + public void testKeyStrokeConversion() { KeyStroke keyStroke = KeyStroke.getKeyStroke('+'); String string = OptionType.KEYSTROKE_TYPE.convertObjectToString(keyStroke); assertEquals(keyStroke, OptionType.KEYSTROKE_TYPE.convertStringToObject(string)); @@ -160,21 +161,27 @@ public class OptionTypeTest extends AbstractGenericTest { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - MyCustomOption other = (MyCustomOption) obj; - if (a != other.a) - return false; - if (b == null) { - if (other.b != null) - return false; } - else if (!b.equals(other.b)) + if (obj == null) { return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MyCustomOption other = (MyCustomOption) obj; + if (a != other.a) { + return false; + } + if (b == null) { + if (other.b != null) { + return false; + } + } + else if (!b.equals(other.b)) { + return false; + } return true; } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java index 9e0f92868f..4258e982f8 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java @@ -31,6 +31,7 @@ import org.jdom.Element; import org.junit.*; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.util.HelpLocation; import ghidra.util.bean.opteditor.OptionsVetoException; import ghidra.util.exception.InvalidInputException; @@ -137,9 +138,9 @@ public class OptionsTest extends AbstractGenericTest { @Test public void testSaveColorOption() { - options.setColor("Foo", Color.RED); + options.setColor("Foo", Palette.RED); saveAndRestoreOptions(); - assertEquals(Color.RED, options.getColor("Foo", Color.BLUE)); + assertColorsEqual(Palette.RED, options.getColor("Foo", Palette.BLUE)); } @Test @@ -195,7 +196,7 @@ public class OptionsTest extends AbstractGenericTest { @Test public void testCopy() { options.setInt("Foo", 3); - options.setColor("COLOR", Color.RED); + options.setColor("COLOR", Palette.RED); options.getLong("LONG", 10); options.registerOption("Bar", true, null, null); Options optionsCopy = options.copy(); @@ -238,39 +239,39 @@ public class OptionsTest extends AbstractGenericTest { @Test public void testVeto() { - options.setColor("COLOR", Color.RED); + options.setColor("COLOR", Palette.RED); OptionsChangeListenerForTestVeto listener1 = new OptionsChangeListenerForTestVeto(); OptionsChangeListenerForTestVeto listener2 = new OptionsChangeListenerForTestVeto(); options.addOptionsChangeListener(listener1); options.addOptionsChangeListener(listener2); - options.setColor("COLOR", Color.BLUE); + options.setColor("COLOR", Palette.BLUE); - assertEquals(Color.RED, options.getColor("COLOR", Color.RED)); + assertEquals(Palette.RED, options.getColor("COLOR", Palette.RED)); if (listener1.callOrder == 1) { - assertEquals(Color.RED, listener1.value); + assertEquals(Palette.RED, listener1.value); assertEquals(null, listener2.value); } if (listener2.callOrder == 1) { - assertEquals(Color.RED, listener2.value); + assertEquals(Palette.RED, listener2.value); assertEquals(null, listener1.value); } } @Test public void testRemove() { - options.setColor("COLOR", Color.RED); + options.setColor("COLOR", Palette.RED); assertTrue(options.contains("COLOR")); options.removeOption("COLOR"); - assertTrue(!options.contains("COLOR")); + assertFalse(options.contains("COLOR")); } @Test public void testGetOptionNames() { - options.setColor("COLOR", Color.red); + options.setColor("COLOR", Palette.RED); options.setInt("INT", 3); List optionNames = options.getOptionNames(); assertEquals(2, optionNames.size()); @@ -282,8 +283,8 @@ public class OptionsTest extends AbstractGenericTest { public void testGetDefaultValue() { options.registerOption("Foo", Color.RED, null, null); options.setColor("Foo", Color.BLUE); - assertEquals(Color.BLUE, options.getColor("Foo", null)); - assertEquals(Color.RED, options.getDefaultValue("Foo")); + assertColorsEqual(Color.BLUE, options.getColor("Foo", null)); + assertColorsEqual(Color.RED, (Color) options.getDefaultValue("Foo")); } @Test @@ -305,10 +306,10 @@ public class OptionsTest extends AbstractGenericTest { options.registerOption("Foo", Color.RED, null, null); options.setColor("Foo", Color.BLUE); - assertEquals(Color.BLUE, options.getColor("Foo", null)); + assertColorsEqual(Color.BLUE, options.getColor("Foo", null)); options.restoreDefaultValue("Foo"); - assertEquals(Color.RED, options.getColor("Foo", null)); + assertColorsEqual(Color.RED, options.getColor("Foo", null)); } @Test @@ -427,11 +428,11 @@ public class OptionsTest extends AbstractGenericTest { @Test public void testCopyOptions() { options.setInt("INT", 3); - options.setColor("COLOR", Color.RED); + options.setColor("COLOR", Palette.RED); ToolOptions options2 = new ToolOptions("aaa"); options2.copyOptions(options); assertEquals(3, options.getInt("INT", 3)); - assertEquals(Color.RED, options.getColor("COLOR", null)); + assertColorsEqual(Palette.RED, options.getColor("COLOR", null)); } @Test @@ -573,16 +574,16 @@ public class OptionsTest extends AbstractGenericTest { @Test public void testSettingValueToNull() { - options.setColor("Bar", Color.red); + options.setColor("Bar", Palette.RED); options.setColor("Bar", null); assertEquals(null, options.getColor("Bar", null)); } @Test - public void testNullValueWillUsedPassedInDefault() { - options.setColor("Bar", Color.red); + public void testNullValueWillUsePassedInDefault() { + options.setColor("Bar", Palette.RED); options.setColor("Bar", null); - assertEquals(Color.BLUE, options.getColor("Bar", Color.BLUE)); + assertColorsEqual(Palette.BLUE, options.getColor("Bar", Palette.BLUE)); } @Test diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/SaveStateTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/SaveStateTest.java index 8d9c8b2e68..aa3af510dc 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/SaveStateTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/SaveStateTest.java @@ -35,6 +35,7 @@ import org.junit.Test; import com.google.gson.JsonObject; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.overview.addresstype.AddressType; import ghidra.program.model.lang.Endian; import ghidra.util.xml.GenericXMLOutputter; @@ -68,15 +69,15 @@ public class SaveStateTest extends AbstractGenericTest { @Test public void testColor() throws Exception { - ss.putColor("TEST", Color.RED); + ss.putColor("TEST", Palette.RED); Color c = ss.getColor("TEST", null); - assertEquals(Color.RED, c); + assertEquals(Palette.RED.getRGB(), c.getRGB()); SaveState restoredState = saveAndRestoreToXml(); // make sure our value is inside c = restoredState.getColor("TEST", null); - assertEquals(Color.RED, c); + assertEquals(Palette.RED.getRGB(), c.getRGB()); } @Test @@ -421,9 +422,9 @@ public class SaveStateTest extends AbstractGenericTest { @Test public void testJsonColorRoundTrip() { - ss.putColor("foo", Color.BLUE); + ss.putColor("foo", Palette.BLUE); SaveState restored = jsonRoundTrip(ss); - assertEquals(Color.BLUE, restored.getColor("foo", null)); + assertEquals(Palette.BLUE.getRGB(), restored.getColor("foo", null).getRGB()); } @Test diff --git a/Ghidra/Features/Base/src/test/java/ghidra/plugins/fsbrowser/FileIconServiceTest.java b/Ghidra/Features/Base/src/test/java/ghidra/plugins/fsbrowser/FileIconServiceTest.java index c30f75511a..7756fdf654 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/plugins/fsbrowser/FileIconServiceTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/plugins/fsbrowser/FileIconServiceTest.java @@ -15,23 +15,57 @@ */ package ghidra.plugins.fsbrowser; +import static org.junit.Assert.*; + +import java.util.List; + +import javax.swing.Icon; + import org.junit.Assert; import org.junit.Test; -import generic.test.AbstractGenericTest; +import docking.test.AbstractDockingTest; +import generic.theme.GIcon; +import resources.MultiIcon; -public class FileIconServiceTest extends AbstractGenericTest -{ +public class FileIconServiceTest extends AbstractDockingTest { @Test public void testGetIcon() { FileIconService fis = FileIconService.getInstance(); - Assert.assertNotNull(fis.getImage("blah.txt")); + Icon icon = fis.getIcon("blah.txt", null); + Assert.assertNotNull(icon); + assertTrue(icon instanceof GIcon); + GIcon gIcon = (GIcon) icon; + assertEquals("icon.fsbrowser.file.extension.txt", gIcon.getId()); } @Test public void testGetOverlayIcon() { FileIconService fis = FileIconService.getInstance(); - Assert.assertNotNull(fis.getImage("blah.txt", FileIconService.OVERLAY_FILESYSTEM)); + Icon icon = fis.getIcon("blah.txt", List.of(FileIconService.FILESYSTEM_OVERLAY_ICON)); + Assert.assertNotNull(icon); + assertTrue(icon instanceof MultiIcon); + MultiIcon multiIcon = (MultiIcon) icon; + assertEquals( + "MultiIcon[icon.fsbrowser.file.extension.txt, icon.fsbrowser.file.overlay.filesystem]", + multiIcon.toString()); + } + + @Test + public void testGetSubstringIcon() { + FileIconService fis = FileIconService.getInstance(); + Icon icon = fis.getIcon("blah.release.abcx.123", null); + Assert.assertNotNull(icon); + assertTrue(icon instanceof GIcon); + GIcon gIcon = (GIcon) icon; + assertEquals("icon.fsbrowser.file.substring.release.", gIcon.getId()); + } + + @Test + public void testNoMatch() { + FileIconService fis = FileIconService.getInstance(); + Icon icon = fis.getIcon("aaaaaaaa.bbbbbbbb.cccccccc", null); + assertEquals(FileIconService.DEFAULT_ICON, icon); } } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeProgramGenerator_DiffTestPrograms.java b/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeProgramGenerator_DiffTestPrograms.java index 3eb983cd37..bc748c5c0a 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeProgramGenerator_DiffTestPrograms.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/database/MergeProgramGenerator_DiffTestPrograms.java @@ -15,10 +15,10 @@ */ package ghidra.program.database; -import java.awt.Color; import java.util.Date; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.program.model.data.*; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; @@ -133,10 +133,10 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { builder.setIntProperty("10018ff", "Space", 1); builder.setIntProperty("100248c", "Space", 1); - builder.setObjectProperty("100248c", "testColor", new SaveableColor(Color.CYAN)); - builder.setObjectProperty("10039dd", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Color.RED)); + builder.setObjectProperty("100248c", "testColor", new SaveableColor(Palette.CYAN)); + builder.setObjectProperty("10039dd", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Palette.RED)); AbstractGenericTest.setInstanceField("recordChanges", program, Boolean.TRUE); @@ -145,8 +145,8 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { if (lastGeneratedUniversalID != null) { if (!lastGeneratedUniversalID.equals(ID)) { // if this happens, update initializeStaticUniversalIDUsage() - throw new AssertException("Expected Test UniversalID has changed. " - + "This is probably due to an new static usage of the UniversalIDGenerator."); + throw new AssertException("Expected Test UniversalID has changed. " + + "This is probably due to an new static usage of the UniversalIDGenerator."); } } @@ -173,10 +173,10 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { builder.setIntProperty("1002428", "Space", 1); builder.setIntProperty("100248c", "Space", 1); - builder.setObjectProperty("100248c", "testColor", new SaveableColor(Color.WHITE)); - builder.setObjectProperty("10039f1", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Color.GREEN)); + builder.setObjectProperty("100248c", "testColor", new SaveableColor(Palette.WHITE)); + builder.setObjectProperty("10039f1", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Palette.GREEN)); AbstractGenericTest.setInstanceField("recordChanges", program, Boolean.TRUE); @@ -185,8 +185,8 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { if (lastGeneratedUniversalID != null) { if (!lastGeneratedUniversalID.equals(ID)) { // if this happens, update initializeStaticUniversalIDUsage() - throw new AssertException("Expected Test UniversalID has changed. " - + "This is probably due to an new static usage of the UniversalIDGenerator."); + throw new AssertException("Expected Test UniversalID has changed. " + + "This is probably due to an new static usage of the UniversalIDGenerator."); } } @@ -228,7 +228,8 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { Parameter p_dh = new ParameterImpl(null, dt, dh, builder.getProgram()); Parameter p_ecx = new ParameterImpl(null, dt, ecx, builder.getProgram()); builder.createEmptyFunction(null, null, null, true, "10018cf", 10, null, p_al); - builder.createEmptyFunction(null, null, null, true, "100299e", 10, null, p_fee, p_ah, p_dr1); + builder.createEmptyFunction(null, null, null, true, "100299e", 10, null, p_fee, p_ah, + p_dr1); builder.createEmptyFunction(null, null, null, true, "1002cf5", 10, null, p1, p_cs, p3, p4, p5); builder.createEmptyFunction(null, null, null, true, "1002c93", 10, null, p_ecx, p1, p2); @@ -250,8 +251,8 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { if (lastGeneratedUniversalID != null) { if (!lastGeneratedUniversalID.equals(ID)) { // if this happens, update initializeStaticUniversalIDUsage() - throw new AssertException("Expected Test UniversalID has changed. " - + "This is probably due to an new static usage of the UniversalIDGenerator."); + throw new AssertException("Expected Test UniversalID has changed. " + + "This is probably due to an new static usage of the UniversalIDGenerator."); } } @@ -276,8 +277,8 @@ class MergeProgramGenerator_DiffTestPrograms implements MergeProgramGenerator { if (lastGeneratedUniversalID != null) { if (!lastGeneratedUniversalID.equals(ID)) { // if this happens, update initializeStaticUniversalIDUsage() - throw new AssertException("Expected Test UniversalID has changed. " - + "This is probably due to an new static usage of the UniversalIDGenerator."); + throw new AssertException("Expected Test UniversalID has changed. " + + "This is probably due to an new static usage of the UniversalIDGenerator."); } } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/CodeManagerTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/CodeManagerTest.java index 81a1da1f66..80dd505f89 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/CodeManagerTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/CodeManagerTest.java @@ -17,13 +17,13 @@ package ghidra.program.database.code; import static org.junit.Assert.*; -import java.awt.Color; import java.math.BigInteger; import java.util.Iterator; import org.junit.*; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.program.database.ProgramDB; import ghidra.program.model.address.*; import ghidra.program.model.data.*; @@ -473,7 +473,7 @@ public class CodeManagerTest extends AbstractGenericTest { PropertyMap map = listing.getPropertyMap("Numbers"); assertNotNull(map); - inst.setProperty("FavoriteColor", new SaveableColor(Color.RED)); + inst.setProperty("FavoriteColor", new SaveableColor(Palette.RED)); map = listing.getPropertyMap("FavoriteColor"); assertNotNull(map); @@ -487,10 +487,10 @@ public class CodeManagerTest extends AbstractGenericTest { inst.setProperty("Numbers", 12); assertEquals(12, inst.getIntProperty("Numbers")); - inst.setProperty("FavoriteColor", new SaveableColor(Color.RED)); + inst.setProperty("FavoriteColor", new SaveableColor(Palette.RED)); SaveableColor c = (SaveableColor) inst.getObjectProperty("FavoriteColor"); assertNotNull(c); - assertEquals(Color.RED, c.getColor()); + assertEquals(Palette.RED.getRGB(), c.getColor().getRGB()); Iterator iter = listing.getUserDefinedProperties(); String name1 = iter.next(); @@ -516,7 +516,7 @@ public class CodeManagerTest extends AbstractGenericTest { // expected } - inst.setProperty("FavoriteColor", new SaveableColor(Color.RED)); + inst.setProperty("FavoriteColor", new SaveableColor(Palette.RED)); SaveableColor c = (SaveableColor) inst.getObjectProperty("FavoriteColor"); assertNotNull(c); listing.removeUserDefinedProperty("FavoriteColor"); @@ -543,7 +543,7 @@ public class CodeManagerTest extends AbstractGenericTest { cu.setProperty("Numbers", 12); assertEquals(12, cu.getIntProperty("Numbers")); - cu.setProperty("FavoriteColor", new SaveableColor(Color.RED)); + cu.setProperty("FavoriteColor", new SaveableColor(Palette.RED)); SaveableColor c = (SaveableColor) cu.getObjectProperty("FavoriteColor"); mem.moveBlock(block, addr(0x8000), new TaskMonitorAdapter()); diff --git a/Ghidra/Features/BytePatterns/certification.manifest b/Ghidra/Features/BytePatterns/certification.manifest index 67172590b3..5d7f4c0f6d 100644 --- a/Ghidra/Features/BytePatterns/certification.manifest +++ b/Ghidra/Features/BytePatterns/certification.manifest @@ -1,6 +1,7 @@ ##VERSION: 2.0 ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||reviewed||END| +data/bytepatterns.theme.properties||GHIDRA||||END| data/test/FileBitPatternInfoReaderTestFile1.xml||GHIDRA||||END| data/test/FileBitPatternInfoReaderTestFile2.xml||GHIDRA||||END| ghidra_scripts/DumpFunctionPatternInfoScript.properties||GHIDRA||||END| diff --git a/Ghidra/Features/BytePatterns/data/bytepatterns.theme.properties b/Ghidra/Features/BytePatterns/data/bytepatterns.theme.properties new file mode 100644 index 0000000000..650b2fc49e --- /dev/null +++ b/Ghidra/Features/BytePatterns/data/bytepatterns.theme.properties @@ -0,0 +1,18 @@ + +[Defaults] + +icon.bytepatterns.send.to.clipboard = 2rightarrow.png + +icon.bytepatterns.byte.sequence.analyzer.clipboard.merged = smallRightArrow.png +icon.bytepatterns.byte.sequence.analyzer.merge = xor.png + +icon.bytepatterns.closed.pattern = 2rightarrow.png + +icon.bytepatterns.pattern.mining.analyzer = magnifier.png + +icon.bytepatterns.function.bit.patterns.disabled = ledred.png +icon.bytepatterns.function.bit.patterns.enabled = ledgreen.png +font.bytepatterns.table = monospaced-PLAIN-16 + +[Dark Defaults] + diff --git a/Ghidra/Features/BytePatterns/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/BytePatterns/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/BytePatterns/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/BytePatterns/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceAnalyzerProvider.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceAnalyzerProvider.java index ce17de6f98..be54566d49 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceAnalyzerProvider.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceAnalyzerProvider.java @@ -25,16 +25,20 @@ import docking.*; import docking.action.DockingAction; import docking.action.MenuData; import docking.widgets.table.GFilterTable; +import generic.theme.GColor; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; import ghidra.bitpatterns.info.*; import ghidra.util.HelpLocation; import ghidra.util.bytesearch.DittedBitSequence; -import resources.ResourceManager; /** * This is a base class for providers which allow the user to analyze sequences of bytes. */ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvider { + private static final Color BG_DISABLED = new GColor("color.bg.uneditable"); + protected ByteSequenceTableModel byteSequenceTable; protected FunctionBitPatternsExplorerPlugin plugin; protected JPanel mainPanel; @@ -154,7 +158,7 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid } }; - ImageIcon icon = ResourceManager.loadImage("images/2rightarrow.png"); + Icon icon = new GIcon("icon.bytepatterns.send.to.clipboard"); sendSelectedToClipboardAction.setPopupMenuData( new MenuData(new String[] { "Send Selected to Clipboard" }, icon)); sendSelectedToClipboardAction.setDescription( @@ -175,9 +179,9 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid } mergedSeqTextField.setText(merged.getHexString()); bitsOfCheckField.setText(Integer.toString(merged.getNumFixedBits())); - mergedSeqTextField.setBackground(Color.WHITE); - bitsOfCheckField.setBackground(Color.WHITE); - noteField.setBackground(Color.WHITE); + mergedSeqTextField.setBackground(Colors.BACKGROUND); + bitsOfCheckField.setBackground(Colors.BACKGROUND); + noteField.setBackground(Colors.BACKGROUND); mergedToSend = true; } @@ -192,7 +196,7 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid } }; - ImageIcon icon = ResourceManager.loadImage("images/xor.png"); + Icon icon = new GIcon("icon.bytepatterns.byte.sequence.analyzer.merge"); mergeAction.setPopupMenuData(new MenuData(new String[] { "Merge Selected Rows" }, icon)); mergeAction.setDescription("Merges the currently selected rows"); mergeAction.setHelpLocation( @@ -211,9 +215,9 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid mergedInfo.setNote(note); plugin.addPattern(mergedInfo); plugin.updateClipboard(); - mergedSeqTextField.setBackground(Color.lightGray); - bitsOfCheckField.setBackground(Color.LIGHT_GRAY); - noteField.setBackground(Color.LIGHT_GRAY); + mergedSeqTextField.setBackground(BG_DISABLED); + bitsOfCheckField.setBackground(BG_DISABLED); + noteField.setBackground(BG_DISABLED); mergedToSend = false; } } @@ -230,7 +234,7 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid } }; - ImageIcon icon = ResourceManager.loadImage("images/smallRightArrow.png"); + Icon icon = new GIcon("icon.bytepatterns.byte.sequence.analyzer.clipboard.merged"); sendMergedToClipboardAction.setPopupMenuData( new MenuData(new String[] { "Send Merged to Clipboard" }, icon)); sendMergedToClipboardAction.setDescription("Sends the Merge Patterns to the Clipboard"); @@ -244,7 +248,7 @@ public abstract class ByteSequenceAnalyzerProvider extends DialogComponentProvid * Creates the table to byte sequences to analyze * @param FBPplugin plugin * @param rows row objects containing sequences to analyze - * @return + * @return the model */ abstract ByteSequenceTableModel createByteSequenceTable( FunctionBitPatternsExplorerPlugin FBPplugin, List rows); diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceTableModel.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceTableModel.java index 7f712ca961..c476481a98 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceTableModel.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ByteSequenceTableModel.java @@ -18,15 +18,13 @@ */ package ghidra.bitpatterns.gui; -import java.awt.Font; +import java.awt.Component; import java.util.List; -import javax.swing.JTable; -import javax.swing.table.TableModel; - import docking.widgets.table.AbstractDynamicTableColumn; import docking.widgets.table.TableColumnDescriptor; import docking.widgets.table.threaded.ThreadedTableModelStub; +import generic.theme.Gui; import ghidra.bitpatterns.info.ByteSequenceRowObject; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; @@ -38,7 +36,7 @@ import ghidra.util.table.column.GColumnRenderer; import ghidra.util.task.TaskMonitor; public class ByteSequenceTableModel extends ThreadedTableModelStub { - private static final int MONOSPACE_FONT_SIZE = 16; + private static final String FONT_ID = "font.bytepatterns.table"; List rowObjects; public ByteSequenceTableModel(FunctionBitPatternsExplorerPlugin plugin, @@ -51,10 +49,13 @@ public class ByteSequenceTableModel extends ThreadedTableModelStub monospacedRenderer = new AbstractGColumnRenderer() { + @Override - protected void configureFont(JTable table, TableModel model, int column) { - Font f = new Font("monospaced", getFixedWidthFont().getStyle(), MONOSPACE_FONT_SIZE); - setFont(f); + public Component getTableCellRendererComponent( + docking.widgets.table.GTableCellRenderingData data) { + Component component = super.getTableCellRendererComponent(data); + component.setFont(Gui.getFont(FONT_ID)); + return component; } @Override diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableDialog.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableDialog.java index dc04c25f3d..7ca0a09c8e 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableDialog.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableDialog.java @@ -19,18 +19,18 @@ import java.awt.BorderLayout; import java.awt.Component; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import javax.swing.JPanel; import docking.*; import docking.action.DockingAction; import docking.action.MenuData; import docking.widgets.table.threaded.GThreadedTablePanel; +import generic.theme.GIcon; import ghidra.bitpatterns.info.ContextRegisterFilter; import ghidra.bitpatterns.info.PatternType; import ghidra.util.HelpLocation; import ghidra.util.bytesearch.DittedBitSequence; -import resources.ResourceManager; /** * This provider is used to display tables containing patterns found by @@ -114,7 +114,7 @@ public class ClosedPatternTableDialog extends DialogComponentProvider { } }; - ImageIcon icon = ResourceManager.loadImage("images/2rightarrow.png"); + Icon icon = new GIcon("icon.bytepatterns.send.to.clipboard"); sendToClipboardAction.setPopupMenuData( new MenuData(new String[] { "Send Selected Sequences to Clipboard" }, icon)); sendToClipboardAction.setDescription( diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableModel.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableModel.java index 98d4a8d0f9..be2d50dd9f 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableModel.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/ClosedPatternTableModel.java @@ -15,15 +15,13 @@ */ package ghidra.bitpatterns.gui; -import java.awt.Font; +import java.awt.Component; import java.util.List; -import javax.swing.JTable; -import javax.swing.table.TableModel; - import docking.widgets.table.AbstractDynamicTableColumn; import docking.widgets.table.TableColumnDescriptor; import docking.widgets.table.threaded.ThreadedTableModelStub; +import generic.theme.Gui; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; import ghidra.util.datastruct.Accumulator; @@ -42,12 +40,13 @@ public class ClosedPatternTableModel extends ThreadedTableModelStub rowObjects; private static final String MODEL_NAME = "Closed Patterns"; - private static final int MONOSPACE_FONT_SIZE = 16; + + protected static final String FONT_ID = "font.bytepatterns.table"; /** * Creates a table model for closed patterns mined from byte sequences - * @param rowObjects - * @param serviceProvider + * @param rowObjects the row objects + * @param serviceProvider the service provider */ public ClosedPatternTableModel(List rowObjects, ServiceProvider serviceProvider) { @@ -57,11 +56,12 @@ public class ClosedPatternTableModel extends ThreadedTableModelStub monospacedRenderer = new AbstractGColumnRenderer() { - @Override - protected void configureFont(JTable table, TableModel model, int column) { - Font f = new Font("monospaced", getFixedWidthFont().getStyle(), MONOSPACE_FONT_SIZE); - setFont(f); - } + public java.awt.Component getTableCellRendererComponent( + docking.widgets.table.GTableCellRenderingData data) { + Component component = super.getTableCellRendererComponent(data); + component.setFont(Gui.getFont(FONT_ID)); + return component; + }; @Override public String getFilterString(String t, Settings settings) { diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternEvalTabelModel.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternEvalTabelModel.java index c0e85191c5..9b835cd00a 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternEvalTabelModel.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternEvalTabelModel.java @@ -15,14 +15,12 @@ */ package ghidra.bitpatterns.gui; -import java.awt.Font; +import java.awt.Component; import java.util.List; -import javax.swing.JTable; -import javax.swing.table.TableModel; - import docking.widgets.table.AbstractDynamicTableColumn; import docking.widgets.table.TableColumnDescriptor; +import generic.theme.Gui; import ghidra.bitpatterns.info.PatternEvalRowObject; import ghidra.bitpatterns.info.PatternMatchType; import ghidra.docking.settings.Settings; @@ -37,7 +35,7 @@ import ghidra.util.table.column.GColumnRenderer; import ghidra.util.task.TaskMonitor; public class PatternEvalTabelModel extends AddressBasedTableModel { - private static final int MONOSPACE_FONT_SIZE = 14; + protected static final String FONT_ID = "font.bytepatterns.table"; private List rowObjects; /** @@ -62,10 +60,11 @@ public class PatternEvalTabelModel extends AddressBasedTableModel monospacedRenderer = new AbstractGColumnRenderer() { @Override - protected void configureFont(JTable table, TableModel model, int column) { - Font f = - new Font("monospaced", getFixedWidthFont().getStyle(), MONOSPACE_FONT_SIZE); - setFont(f); + public java.awt.Component getTableCellRendererComponent( + docking.widgets.table.GTableCellRenderingData data) { + Component component = super.getTableCellRendererComponent(data); + component.setFont(Gui.getFont(FONT_ID)); + return component; } @Override diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternInfoTableModel.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternInfoTableModel.java index 440c040715..51720e1cd3 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternInfoTableModel.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternInfoTableModel.java @@ -15,14 +15,12 @@ */ package ghidra.bitpatterns.gui; -import java.awt.Font; - -import javax.swing.JTable; -import javax.swing.table.TableModel; +import java.awt.Component; import docking.widgets.table.AbstractDynamicTableColumn; import docking.widgets.table.TableColumnDescriptor; import docking.widgets.table.threaded.ThreadedTableModelStub; +import generic.theme.Gui; import ghidra.bitpatterns.info.PatternType; import ghidra.docking.settings.Settings; import ghidra.framework.plugintool.ServiceProvider; @@ -42,7 +40,7 @@ public class PatternInfoTableModel extends ThreadedTableModelStub monospacedRenderer = new AbstractGColumnRenderer() { - @Override - protected void configureFont(JTable table, TableModel model, int column) { - Font f = new Font("monospaced", getFixedWidthFont().getStyle(), MONOSPACE_FONT_SIZE); - setFont(f); + public Component getTableCellRendererComponent( + docking.widgets.table.GTableCellRenderingData data) { + Component component = super.getTableCellRendererComponent(data); + component.setFont(Gui.getFont(FONT_ID)); + return component; } @Override diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternMiningAnalyzerProvider.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternMiningAnalyzerProvider.java index a98e544721..e083a959c7 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternMiningAnalyzerProvider.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/gui/PatternMiningAnalyzerProvider.java @@ -18,15 +18,15 @@ package ghidra.bitpatterns.gui; import java.awt.Component; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.bitpatterns.info.*; import ghidra.closedpatternmining.SequenceMiningParams; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * @@ -100,7 +100,7 @@ public class PatternMiningAnalyzerProvider extends ByteSequenceAnalyzerProvider } }; - ImageIcon icon = ResourceManager.loadImage("images/magnifier.png"); + Icon icon = new GIcon("icon.bytepatterns.pattern.mining.analyzer"); mineClosedPatternsAction.setPopupMenuData( new MenuData(new String[] { "Mine Sequential Patterns" }, icon)); mineClosedPatternsAction.setDescription("Mine Sequential Patterns"); diff --git a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/info/FunctionBitPatternsGTreeNode.java b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/info/FunctionBitPatternsGTreeNode.java index 2c82a4f9e2..cd9eb048a3 100644 --- a/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/info/FunctionBitPatternsGTreeNode.java +++ b/Ghidra/Features/BytePatterns/src/main/java/ghidra/bitpatterns/info/FunctionBitPatternsGTreeNode.java @@ -20,8 +20,7 @@ import java.util.*; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; -import docking.widgets.tree.GTreeNode; -import resources.ResourceManager; +import generic.theme.GIcon; /** * @@ -30,9 +29,11 @@ import resources.ResourceManager; */ public class FunctionBitPatternsGTreeNode extends GTreeNode { - private static final Icon DISABLED_ICON = ResourceManager.loadImage("images/ledred.png"); + private static final Icon DISABLED_ICON = + new GIcon("icon.bytepatterns.function.bit.patterns.disabled"); - private static final Icon ENABLED_ICON = ResourceManager.loadImage("images/ledgreen.png"); + private static final Icon ENABLED_ICON = + new GIcon("icon.bytepatterns.function.bit.patterns.enabled"); private String name; private String instruction; diff --git a/Ghidra/Features/ByteViewer/certification.manifest b/Ghidra/Features/ByteViewer/certification.manifest index 65455bf81c..b6da5c7ed5 100644 --- a/Ghidra/Features/ByteViewer/certification.manifest +++ b/Ghidra/Features/ByteViewer/certification.manifest @@ -3,6 +3,7 @@ ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||reviewed||END| +data/byteviewer.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||reviewed||END| src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END| src/main/help/help/shared/close16.gif||GHIDRA||reviewed||END| diff --git a/Ghidra/Features/ByteViewer/data/byteviewer.theme.properties b/Ghidra/Features/ByteViewer/data/byteviewer.theme.properties new file mode 100644 index 0000000000..bb57276970 --- /dev/null +++ b/Ghidra/Features/ByteViewer/data/byteviewer.theme.properties @@ -0,0 +1,24 @@ +[Defaults] + +color.bg.byteviewer = color.bg +color.bg.byteviewer.highlight = yellow + +color.fg.byteviewer.separator = blue +color.fg.byteviewer.changed = red +color.cursor.byteviewer.focused.active = color.cursor.focused +color.cursor.byteviewer.focused.not.active = black +color.cursor.byteviewer.unfocused = color.cursor.unfocused + +icon.plugin.byteviewer.provider = binaryData.gif +icon.plugin.byteviewer.options = wrench.png +font.byteviewer = font.monospaced +font.byteviewer.header = SansSerif-PLAIN-11 +font.byteviewer.status = SansSerif-PLAIN-11 + +[Dark Defaults] + +color.bg.byteviewer.highlight = rgb(191, 191, 64) // olive +color.fg.byteviewer.changed = indianRed +color.fg.byteviewer.separator = darkBlue +color.cursor.byteviewer.focused.not.active = gray + diff --git a/Ghidra/Features/ByteViewer/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/ByteViewer/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/ByteViewer/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/ByteViewer/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java index f9eaf80da4..3f8ecca425 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponent.java @@ -29,6 +29,7 @@ import docking.widgets.fieldpanel.Layout; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.listener.*; import docking.widgets.fieldpanel.support.*; +import generic.theme.GColor; import ghidra.app.plugin.core.format.*; import ghidra.program.model.address.*; import ghidra.util.Msg; @@ -729,9 +730,9 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene createFields(); setCursorOn(true); - editColor = ByteViewerComponentProvider.DEFAULT_EDIT_COLOR; - currentCursorColor = ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR; - setNonFocusCursorColor(ByteViewerComponentProvider.DEFAULT_NONFOCUS_CURSOR_COLOR); + editColor = ByteViewerComponentProvider.CHANGED_VALUE_COLOR; + currentCursorColor = ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR; + setNonFocusCursorColor(ByteViewerComponentProvider.CURSOR_NOT_FOCUSED_COLOR); setFocusedCursorColor(currentCursorColor); updateColorRunner = () -> updateColor(); @@ -885,7 +886,7 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene private class ByteViewerBackgroundColorModel implements BackgroundColorModel { - private Color defaultBackgroundColor = Color.WHITE; + private Color defaultBackgroundColor = new GColor("color.bg.byteviewer"); @Override public Color getBackgroundColor(BigInteger index) { diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java index 42a0ac0ec5..4202146c82 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerComponentProvider.java @@ -25,6 +25,7 @@ import java.util.List; import javax.swing.JComponent; import docking.action.ToggleDockingAction; +import generic.theme.*; import ghidra.GhidraOptions; import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES; import ghidra.app.plugin.core.format.*; @@ -36,7 +37,6 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.util.*; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.task.SwingUpdateManager; -import resources.ResourceManager; public abstract class ByteViewerComponentProvider extends ComponentProviderAdapter implements OptionsChangeListener { @@ -53,36 +53,40 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt private static final String OFFSET_NAME = "Offset"; static final int DEFAULT_NUMBER_OF_CHARS = 8; - static final Font DEFAULT_FONT = new Font("Monospaced", Font.PLAIN, 12); + static final String DEFAULT_FONT_ID = "font.byteviewer"; static final int DEFAULT_BYTES_PER_LINE = 16; - static final Color DEFAULT_MISSING_VALUE_COLOR = Color.blue; - static final Color DEFAULT_EDIT_COLOR = Color.red; - static final Color DEFAULT_CURRENT_CURSOR_COLOR = Color.magenta.brighter(); - static final Color DEFAULT_CURSOR_COLOR = Color.black; - static final Color DEFAULT_NONFOCUS_CURSOR_COLOR = Color.darkGray; - private static final Color DEFAULT_CURSOR_LINE_COLOR = GhidraOptions.DEFAULT_CURSOR_LINE_COLOR; + + //@formatter:off + static final String FG = "byteviewer.color.fg"; + static final String CURSOR = "byteviewer.color.cursor"; + + static final GColor SEPARATOR_COLOR = new GColor("color.fg.byteviewer.separator"); + static final GColor CHANGED_VALUE_COLOR = new GColor("color.fg.byteviewer.changed"); + static final GColor CURSOR_ACTIVE_COLOR = new GColor("color.cursor.byteviewer.focused.active"); + static final GColor CURSOR_NON_ACTIVE_COLOR = new GColor("color.cursor.byteviewer.focused.not.active"); + static final GColor CURSOR_NOT_FOCUSED_COLOR = new GColor("color.cursor.byteviewer.unfocused"); + + static final GColor CURRENT_LINE_COLOR = GhidraOptions.DEFAULT_CURSOR_LINE_COLOR; + //@formatter:on static final String DEFAULT_INDEX_NAME = "Addresses"; - static final String OPTION_EDIT_COLOR = "Edit Cursor Color"; - static final String OPTION_SEPARATOR_COLOR = "Block Separator Color"; - static final String OPTION_CURRENT_VIEW_CURSOR_COLOR = "Current View Cursor Color"; - static final String OPTION_CURSOR_COLOR = "Cursor Color"; + static final String SEPARATOR_COLOR_OPTION_NAME = "Block Separator Color"; + static final String CHANGED_VALUE_COLOR_OPTION_NAME = "Changed Values Color"; + static final String CURSOR_ACTIVE_COLOR_OPTION_NAME = "Active Cursor Color"; + static final String CURSOR_NON_ACTIVE_COLOR_OPTION_NAME = "Non-Active Cursor Color"; + static final String CURSOR_NOT_FOCUSED_COLOR_OPTION_NAME = "Non-Focused Cursor Color"; + static final String OPTION_FONT = "Font"; - static final String OPTION_NONFOCUS_CURSOR_COLOR = "Non-Focus Cursor Color"; private static final String DEFAULT_VIEW = "Hex"; - private static final String OPTION_CURRENT_LINE_COLOR = + private static final String CURRENT_LINE_COLOR_OPTION_NAME = GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR_OPTION_NAME; private static final String OPTION_HIGHLIGHT_CURSOR_LINE = GhidraOptions.HIGHLIGHT_CURSOR_LINE_OPTION_NAME; protected ByteViewerPanel panel; - private Color editColor; - private Color currentCursorColor; - private Color defaultCursorColor; - private int bytesPerLine; private int offset; private int hexGroupSize = 1; @@ -101,16 +105,16 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt private Map> dataFormatModelClassMap; protected ByteViewerComponentProvider(PluginTool tool, AbstractByteViewerPlugin plugin, - String name, - Class contextType) { + String name, Class contextType) { super(tool, name, plugin.getName(), contextType); this.plugin = plugin; + registerAdjustableFontId(DEFAULT_FONT_ID); initializedDataFormatModelClassMap(); panel = newByteViewerPanel(); bytesPerLine = DEFAULT_BYTES_PER_LINE; - setIcon(ResourceManager.loadImage("images/binaryData.gif")); + setIcon(new GIcon("icon.plugin.byteviewer.provider")); setOptions(); createActions(); @@ -168,26 +172,7 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { if (options.getName().equals("ByteViewer")) { - - if (optionName.equals(OPTION_CURRENT_VIEW_CURSOR_COLOR)) { - panel.setCurrentCursorColor((Color) newValue); - } - else if (optionName.equals(OPTION_CURSOR_COLOR)) { - panel.setCursorColor((Color) newValue); - } - else if (optionName.equals(OPTION_CURRENT_LINE_COLOR)) { - panel.setCurrentCursorLineColor((Color) newValue); - } - else if (optionName.equals(OPTION_EDIT_COLOR)) { - panel.setEditColor((Color) newValue); - } - else if (optionName.equals(OPTION_SEPARATOR_COLOR)) { - panel.setSeparatorColor((Color) newValue); - } - else if (optionName.equals(OPTION_NONFOCUS_CURSOR_COLOR)) { - panel.setNonFocusCursorColor((Color) newValue); - } - else if (optionName.equals(OPTION_FONT)) { + if (optionName.equals(OPTION_FONT)) { setFont(SystemUtilities.adjustForFontSizeOverride((Font) newValue)); } } @@ -214,48 +199,45 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt HelpLocation help = new HelpLocation("ByteViewerPlugin", "Option"); opt.setOptionsHelpLocation(help); - opt.registerOption(OPTION_SEPARATOR_COLOR, DEFAULT_MISSING_VALUE_COLOR, help, + opt.registerThemeColorBinding(SEPARATOR_COLOR_OPTION_NAME, SEPARATOR_COLOR.getId(), help, "Color used for separator shown between memory blocks."); - opt.registerOption(OPTION_SEPARATOR_COLOR, DEFAULT_MISSING_VALUE_COLOR, help, - "Color used for separator shown between memory blocks."); - opt.registerOption(OPTION_EDIT_COLOR, DEFAULT_EDIT_COLOR, + + opt.registerThemeColorBinding(CHANGED_VALUE_COLOR_OPTION_NAME, CHANGED_VALUE_COLOR.getId(), new HelpLocation("ByteViewerPlugin", "EditColor"), - "Color of cursor when the current view is in edit mode and can support editing."); - opt.registerOption(OPTION_CURRENT_VIEW_CURSOR_COLOR, DEFAULT_CURRENT_CURSOR_COLOR, help, - "Color of cursor when it is in the current view."); - opt.registerOption(OPTION_NONFOCUS_CURSOR_COLOR, DEFAULT_NONFOCUS_CURSOR_COLOR, help, - "Color of cursor when it is not the current view."); - opt.registerOption(OPTION_CURSOR_COLOR, DEFAULT_CURSOR_COLOR, help, - "Color of cursor for other views other than the current view."); - opt.registerOption(OPTION_FONT, DEFAULT_FONT, help, "Font used in the views."); - opt.registerOption(OPTION_CURRENT_LINE_COLOR, DEFAULT_CURSOR_LINE_COLOR, help, + "Color of changed bytes when editing."); + + opt.registerThemeColorBinding(CURSOR_ACTIVE_COLOR_OPTION_NAME, CURSOR_ACTIVE_COLOR.getId(), + help, "Color of cursor in the active view."); + + opt.registerThemeColorBinding(CURSOR_NON_ACTIVE_COLOR_OPTION_NAME, + CURSOR_NON_ACTIVE_COLOR.getId(), + help, "Color of cursor in the non-active views."); + + opt.registerThemeColorBinding(CURSOR_NOT_FOCUSED_COLOR_OPTION_NAME, + CURSOR_NOT_FOCUSED_COLOR.getId(), + help, "Color of cursor when the byteview does not have focus."); + + opt.registerThemeColorBinding(CURRENT_LINE_COLOR_OPTION_NAME, + GhidraOptions.DEFAULT_CURSOR_LINE_COLOR.getId(), help, "Color of the line containing the cursor"); + + opt.registerThemeFontBinding(OPTION_FONT, DEFAULT_FONT_ID, help, + "Font used in the views."); opt.registerOption(OPTION_HIGHLIGHT_CURSOR_LINE, true, help, "Toggles highlighting background color of line containing the cursor"); - Color missingValueColor = opt.getColor(OPTION_SEPARATOR_COLOR, DEFAULT_MISSING_VALUE_COLOR); + Color missingValueColor = opt.getColor(SEPARATOR_COLOR_OPTION_NAME, SEPARATOR_COLOR); panel.setSeparatorColor(missingValueColor); - editColor = opt.getColor(OPTION_EDIT_COLOR, DEFAULT_EDIT_COLOR); - currentCursorColor = - opt.getColor(OPTION_CURRENT_VIEW_CURSOR_COLOR, DEFAULT_CURRENT_CURSOR_COLOR); - panel.setCurrentCursorColor(currentCursorColor); + panel.setCurrentCursorColor(CURSOR_ACTIVE_COLOR); + panel.setNonFocusCursorColor(CURSOR_NOT_FOCUSED_COLOR); + panel.setCursorColor(CURSOR_NON_ACTIVE_COLOR); + panel.setCurrentCursorLineColor(CURRENT_LINE_COLOR); - Color nonFocusCursorColor = - opt.getColor(OPTION_NONFOCUS_CURSOR_COLOR, DEFAULT_NONFOCUS_CURSOR_COLOR); - panel.setNonFocusCursorColor(nonFocusCursorColor); - - defaultCursorColor = opt.getColor(OPTION_CURSOR_COLOR, DEFAULT_CURSOR_COLOR); - panel.setCursorColor(defaultCursorColor); - - Color cursorLineColor = opt.getColor(OPTION_CURRENT_LINE_COLOR, DEFAULT_CURSOR_LINE_COLOR); - panel.setCurrentCursorLineColor(cursorLineColor); - - Font font = - SystemUtilities.adjustForFontSizeOverride(opt.getFont(OPTION_FONT, DEFAULT_FONT)); + Font font = Gui.getFont(DEFAULT_FONT_ID); FontMetrics fm = panel.getFontMetrics(font); - panel.restoreConfigState(fm, editColor); + panel.restoreConfigState(fm, CHANGED_VALUE_COLOR); opt.addOptionsChangeListener(this); @@ -265,13 +247,15 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt CURSOR_HIGHLIGHT_BUTTON_NAME, GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES.MIDDLE); panel.setHighlightButton(mouseButton.getMouseEventID()); - panel.setMouseButtonHighlightColor(opt.getColor(HIGHLIGHT_COLOR_NAME, Color.YELLOW)); + panel.setMouseButtonHighlightColor( + opt.getColor(HIGHLIGHT_COLOR_NAME, DEFAULT_HIGHLIGHT_COLOR)); opt.addOptionsChangeListener(this); } /** * Set the offset that is applied to each block. + * @param blockOffset the new block offset */ void setBlockOffset(int blockOffset) { if (blockOffset == offset) { @@ -304,6 +288,7 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt /** * Get the number of bytes displayed in a line. + * @return the number of bytes displayed in a line */ int getBytesPerLine() { return bytesPerLine; @@ -311,13 +296,14 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt /** * Get the offset that should be applied to each byte block. + * @return the offset that should be applied to each byte block */ int getOffset() { return offset; } Color getCursorColor() { - return defaultCursorColor; + return CURSOR_NON_ACTIVE_COLOR; } int getGroupSize() { diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHeader.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHeader.java index 06c7577c6a..a3b15b5438 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHeader.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHeader.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +15,6 @@ */ package ghidra.app.plugin.core.byteviewer; -import ghidra.util.table.GhidraTable; - import java.awt.*; import java.util.HashMap; import java.util.Iterator; @@ -26,6 +23,9 @@ import javax.swing.*; import javax.swing.event.TableColumnModelListener; import javax.swing.table.*; +import generic.theme.Gui; +import ghidra.util.table.GhidraTable; + /** * JTableHeader that uses the default table column model to manage * TableColumns. Sizes the column according to its corresponding viewer @@ -33,6 +33,7 @@ import javax.swing.table.*; */ class ByteViewerHeader extends JTableHeader implements Scrollable { + private static final String FONT_ID = "font.byteviewer.header"; private TableColumnModel columnModel; private Component container; @@ -50,8 +51,7 @@ class ByteViewerHeader extends JTableHeader implements Scrollable { this.container = container; components = new HashMap(); - Font font = new Font("Tahoma", Font.PLAIN, 11); - setFont(font); + Gui.registerFont(this, FONT_ID); setResizingAllowed(false); table = new GhidraTable(); setTable(table); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHighlightProvider.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHighlightProvider.java index d26bf8f0b2..0b85bed4c5 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHighlightProvider.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerHighlightProvider.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +15,19 @@ */ package ghidra.app.plugin.core.byteviewer; -import ghidra.app.util.HighlightProvider; -import ghidra.app.util.viewer.field.FieldFactory; - import java.awt.Color; import docking.widgets.fieldpanel.support.Highlight; +import generic.theme.GColor; +import ghidra.app.util.HighlightProvider; +import ghidra.app.util.viewer.field.FieldFactory; public class ByteViewerHighlightProvider implements HighlightProvider { private static Highlight[] NO_HIGHLIGHTS = new Highlight[0]; private String highlightText; - private Color highlightColor = Color.YELLOW; + private Color highlightColor = new GColor("color.bg.byteviewer.highlight"); + @Override public Highlight[] getHighlights(String text, Object obj, Class fieldFactoryClass, int cursorTextOffset) { diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerOptionsDialog.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerOptionsDialog.java index f6c9f7e581..3a53335d29 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerOptionsDialog.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerOptionsDialog.java @@ -15,12 +15,12 @@ */ package ghidra.app.plugin.core.byteviewer; -import java.awt.*; +import java.awt.Component; +import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigInteger; import java.util.*; -import java.util.List; import java.util.Map.Entry; import javax.swing.*; @@ -31,6 +31,8 @@ import javax.swing.event.ChangeListener; import docking.DialogComponentProvider; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.format.ByteBlockSelection; import ghidra.app.plugin.core.format.DataFormatModel; import ghidra.app.util.AddressInput; @@ -266,10 +268,10 @@ public class ByteViewerOptionsDialog extends DialogComponentProvider JCheckBox checkBox = entry.getValue(); DataFormatModel model = provider.getDataFormatModel(entry.getKey()); if (model.validateBytesPerLine(bytesPerLine)) { - checkBox.setForeground(Color.BLACK); + checkBox.setForeground(Colors.FOREGROUND); } else { - checkBox.setForeground(Color.RED); + checkBox.setForeground(Messages.ERROR); isBad |= checkBox.isSelected(); } } diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java index b395cd35a2..13db74bbd7 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteViewerPanel.java @@ -31,6 +31,8 @@ import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.*; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; +import generic.theme.GColor; +import generic.theme.Gui; import ghidra.app.plugin.core.format.*; import ghidra.app.util.viewer.listingpanel.AddressSetDisplayListener; import ghidra.program.model.address.AddressSet; @@ -44,11 +46,12 @@ import help.Help; import help.HelpService; /** - * Top level component that contains has a scrolled pane for the panel of components that show the + * Top level component that has a scrolled pane for the panel of components that show the * view for each format. */ public class ByteViewerPanel extends JPanel implements TableColumnModelListener, LayoutModel, LayoutListener { + private static final String FONT_STATUS_ID = "font.byteviewer.status"; // private ByteViewerPlugin plugin; private List viewList; // list of field viewers private FieldPanel indexPanel; // panel for showing indexes @@ -71,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; @@ -93,7 +95,7 @@ public class ByteViewerPanel extends JPanel viewList = new ArrayList<>(); indexMap = new IndexMap(); create(); - editColor = ByteViewerComponentProvider.DEFAULT_EDIT_COLOR; + editColor = ByteViewerComponentProvider.CHANGED_VALUE_COLOR; } /** @@ -215,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); @@ -259,8 +260,8 @@ public class ByteViewerPanel extends JPanel String start = blocks[0].getLocationRepresentation(BigInteger.ZERO); startField.setText(start); ByteBlock lastBlock = blocks[blocks.length - 1]; - endField.setText(lastBlock.getLocationRepresentation( - lastBlock.getLength().subtract(BigInteger.ONE))); + endField.setText(lastBlock + .getLocationRepresentation(lastBlock.getLength().subtract(BigInteger.ONE))); indexPanelWidth = getIndexPanelWidth(blocks); int center = indexPanelWidth / 2; @@ -415,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); @@ -811,7 +812,7 @@ public class ByteViewerPanel extends JPanel columnHeader = new ByteViewerHeader(this); - fm = getFontMetrics(ByteViewerComponentProvider.DEFAULT_FONT); + fm = getFontMetrics(Gui.getFont(ByteViewerComponentProvider.DEFAULT_FONT_ID)); fontHeight = fm.getHeight(); // for the index/address column @@ -833,7 +834,8 @@ public class ByteViewerPanel extends JPanel columnHeader.addColumn(ByteViewerComponentProvider.DEFAULT_INDEX_NAME, indexPanel); scrollp.setColumnHeaderComp(columnHeader); - compPanel.setBackground(Color.WHITE); + + compPanel.setBackground(new GColor("color.bg.byteviewer")); statusPanel = createStatusPanel(); add(scrollp, BorderLayout.CENTER); @@ -862,15 +864,14 @@ public class ByteViewerPanel extends JPanel insertionField = new GDLabel("00000000"); insertionField.setName("Insertion"); - Font f = new Font("SansSerif", Font.PLAIN, 11); - startLabel.setFont(f); - endLabel.setFont(f); - offsetLabel.setFont(f); - insertionLabel.setFont(f); - startField.setFont(f); - endField.setFont(f); - offsetField.setFont(f); - insertionField.setFont(f); + Gui.registerFont(startLabel, FONT_STATUS_ID); + Gui.registerFont(endLabel, FONT_STATUS_ID); + Gui.registerFont(offsetLabel, FONT_STATUS_ID); + Gui.registerFont(insertionLabel, FONT_STATUS_ID); + Gui.registerFont(startField, FONT_STATUS_ID); + Gui.registerFont(endField, FONT_STATUS_ID); + Gui.registerFont(offsetField, FONT_STATUS_ID); + Gui.registerFont(insertionField, FONT_STATUS_ID); // make a panel for each label/value pair JPanel p1 = new JPanel(new PairLayout(0, 5)); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java index 81ed547bfb..622ebf3ca6 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java @@ -61,8 +61,8 @@ class FieldFactory { this.highlightFactory = new SimpleHighlightFactory(highlightProvider); charWidth = fm.charWidth('W'); width = charWidth * model.getDataUnitSymbolSize(); - editColor = ByteViewerComponentProvider.DEFAULT_EDIT_COLOR; - separatorColor = ByteViewerComponentProvider.DEFAULT_MISSING_VALUE_COLOR; + editColor = ByteViewerComponentProvider.CHANGED_VALUE_COLOR; + separatorColor = ByteViewerComponentProvider.SEPARATOR_COLOR; unitByteSize = model.getUnitByteSize(); } diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java index cb7ae28d6c..a2e94b586a 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java @@ -48,7 +48,7 @@ class IndexFieldFactory { charWidth = fm.charWidth('W'); width = ByteViewerComponentProvider.DEFAULT_NUMBER_OF_CHARS * charWidth; - missingValueColor = ByteViewerComponentProvider.DEFAULT_MISSING_VALUE_COLOR; + missingValueColor = ByteViewerComponentProvider.SEPARATOR_COLOR; } /** diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/OptionsAction.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/OptionsAction.java index 0817d4c4af..6ba6e1c197 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/OptionsAction.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/OptionsAction.java @@ -15,17 +15,17 @@ */ package ghidra.app.plugin.core.byteviewer; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.DockingAction; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; -import resources.ResourceManager; class OptionsAction extends DockingAction { - public static final ImageIcon OPTIONS_ICON = ResourceManager.loadImage("images/wrench.png"); + public static final Icon OPTIONS_ICON = new GIcon("icon.plugin.byteviewer.options"); private final ByteViewerComponentProvider provider; diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java index df931344fd..bd6c07bb0d 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ProgramByteViewerComponentProvider.java @@ -25,6 +25,7 @@ import javax.swing.*; import docking.ActionContext; import docking.action.*; import docking.widgets.fieldpanel.support.ViewerPosition; +import generic.theme.GIcon; import ghidra.app.events.*; import ghidra.app.nav.*; import ghidra.app.plugin.core.format.*; @@ -43,7 +44,6 @@ import ghidra.util.HelpLocation; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; -import resources.ResourceManager; public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvider implements DomainObjectListener, Navigatable { @@ -77,7 +77,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi AbstractByteViewerPlugin plugin, String name, boolean isConnected) { super(tool, plugin, name, ByteViewerActionContext.class); this.isConnected = isConnected; - setIcon(ResourceManager.loadImage("images/binaryData.gif")); + setIcon(new GIcon("icon.plugin.byteviewer.provider")); if (!isConnected) { setTransient(); } @@ -742,7 +742,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi public CloneByteViewerAction() { super("ByteViewer Clone", plugin.getName()); - ImageIcon image = ResourceManager.loadImage("images/camera-photo.png"); + Icon image = new GIcon("icon.provider.clone"); setToolBarData(new ToolBarData(image, "ZZZ")); setDescription("Create a snapshot (disconnected) copy of this Bytes window "); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ToggleEditAction.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ToggleEditAction.java index c900cae83e..fea85ae1c2 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ToggleEditAction.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ToggleEditAction.java @@ -20,8 +20,8 @@ import java.awt.event.KeyEvent; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.framework.plugintool.Plugin; -import resources.ResourceManager; class ToggleEditAction extends ToggleDockingAction { private final ByteViewerComponentProvider provider; @@ -29,8 +29,7 @@ class ToggleEditAction extends ToggleDockingAction { public ToggleEditAction(ByteViewerComponentProvider provider, Plugin plugin) { super("Enable/Disable Byteviewer Editing", plugin.getName()); this.provider = provider; - setToolBarData(new ToolBarData( - ResourceManager.loadImage("images/editbytes.gif"), "Byteviewer")); + setToolBarData(new ToolBarData(new GIcon("icon.base.edit.bytes"), "Byteviewer")); setKeyBindingData(new KeyBindingData( KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK)); diff --git a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerConnectedToolBehaviorTest.java b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerConnectedToolBehaviorTest.java index 55433aacda..a6f0c734b0 100644 --- a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerConnectedToolBehaviorTest.java +++ b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerConnectedToolBehaviorTest.java @@ -157,7 +157,6 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt }); assertTrue(action.isSelected()); final ByteViewerComponent c = panelOne.getCurrentComponent(); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_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(), @@ -167,7 +166,7 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt ByteViewerComponent c2 = panel2.getCurrentComponent(); ByteField f2 = c2.getField(BigInteger.ZERO, 0); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, f2.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, f2.getForeground()); } @Test @@ -188,7 +187,6 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt }); assertTrue(action.isSelected()); final ByteViewerComponent c = panelOne.getCurrentComponent(); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_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(), @@ -198,7 +196,7 @@ public class ByteViewerConnectedToolBehaviorTest extends AbstractGhidraHeadedInt ByteViewerComponent c2 = panel2.getCurrentComponent(); ByteField f2 = c2.getField(BigInteger.ZERO, 0); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, f2.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, f2.getForeground()); undo(program); diff --git a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin2Test.java b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin2Test.java index a0962a6022..33204ed217 100644 --- a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin2Test.java +++ b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPlugin2Test.java @@ -34,6 +34,7 @@ import docking.action.DockingActionIf; import docking.action.ToggleDockingAction; import docking.widgets.EventTrigger; import docking.widgets.fieldpanel.support.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.format.*; import ghidra.app.plugin.core.navigation.*; @@ -147,7 +148,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { }); assertTrue(action.isSelected()); final ByteViewerComponent c = panel.getCurrentComponent(); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); SwingUtilities.invokeAndWait(() -> { KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_A, 'a'); @@ -156,7 +157,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { }); program.flushEvents(); assertEquals((byte) 0xa0, program.getMemory().getByte(getAddr(0x01001000))); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, ((ByteField) c.getCurrentField()).getForeground()); SwingUtilities.invokeAndWait(() -> { @@ -164,7 +165,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { action.actionPerformed(new ActionContext()); }); assertTrue(!action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, c.getFocusedCursorColor()); } @@ -191,7 +192,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { }); assertTrue(action.isSelected()); final ByteViewerComponent c = panel.getCurrentComponent(); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); SwingUtilities.invokeAndWait(() -> { KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_A, 'a'); @@ -204,7 +205,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(b, program.getMemory().getByte(addr)); Color fg = ((ByteField) c.getCurrentField()).getForeground(); if (fg != null) { - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, fg); + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, fg); } Window w = windowForComponent(plugin.getProvider().getComponent()); String str = findLabelStr(w, "Tool Status"); @@ -250,7 +251,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertEquals((byte) 0xa0, program.getMemory().getByte(addr)); FieldLocation loc = getFieldLocation(addr); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); } @@ -295,21 +296,21 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertEquals((byte) 0xa0, program.getMemory().getByte(addr)); FieldLocation loc = getFieldLocation(addr); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); final ByteViewerComponent asciiC = findComponent(panel, "Ascii"); SwingUtilities.invokeAndWait(() -> panel.setCurrentView(asciiC)); loc = getFieldLocation(addr); field = asciiC.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); final ByteViewerComponent hexIntC = findComponent(panel, "HexInteger"); SwingUtilities.invokeAndWait(() -> panel.setCurrentView(hexIntC)); loc = getFieldLocation(addr); field = asciiC.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); } @Test @@ -345,7 +346,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); Color fg = field.getForeground(); assertTrue(fg == null || - ByteViewerComponentProvider.DEFAULT_CURSOR_COLOR == field.getForeground()); + ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR == field.getForeground()); redo(program); program.flushEvents(); @@ -353,7 +354,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { // field color should show edit color loc = getFieldLocation(addr); field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); } @@ -403,19 +404,19 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { FieldLocation loc2 = new FieldLocation(0, 1, 0, 0); // second byte on first line undo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); - testFieldColor(loc2, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); + testFieldColor(loc2, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); undo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); - testFieldColor(loc2, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); + testFieldColor(loc2, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); undo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); testFieldColor(loc2, null); undo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); testFieldColor(loc2, null); undo(program); @@ -424,24 +425,24 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertTrue(!program.canUndo()); redo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); testFieldColor(loc2, null); redo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); testFieldColor(loc2, null); redo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); - testFieldColor(loc2, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); + testFieldColor(loc2, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); redo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); - testFieldColor(loc2, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); + testFieldColor(loc2, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); redo(program); - testFieldColor(loc1, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); - testFieldColor(loc2, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + testFieldColor(loc1, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); + testFieldColor(loc2, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); assertTrue(program.canUndo()); } @@ -492,14 +493,14 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); Color fg = field.getForeground(); assertTrue(fg == null || - ByteViewerComponentProvider.DEFAULT_CURSOR_COLOR == field.getForeground()); + ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR == field.getForeground()); redo(program); // field color should show edit color loc = getFieldLocation(addr); field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); } @@ -557,10 +558,10 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Color fg = field.getForeground(); if (i == 4) { assertTrue(fg == null || - ByteViewerComponentProvider.DEFAULT_CURSOR_COLOR == field.getForeground()); + ByteViewerComponentProvider.CURSOR_NON_ACTIVE_COLOR == field.getForeground()); } else { - assertEquals(fg, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + assertEquals(fg, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); } } assertTrue(!program.canUndo()); @@ -572,7 +573,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { FieldLocation loc = c.getCursorLocation(); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); Color fg = field.getForeground(); - assertEquals(fg, ByteViewerComponentProvider.DEFAULT_EDIT_COLOR); + assertEquals(fg, ByteViewerComponentProvider.CHANGED_VALUE_COLOR); } assertTrue(program.canUndo()); @@ -592,7 +593,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { }); assertTrue(action.isSelected()); final ByteViewerComponent c = panel.getCurrentComponent(); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); byte value = program.getMemory().getByte(getAddr(0x01001000)); SwingUtilities.invokeAndWait(() -> { KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_P, 'p'); @@ -622,7 +623,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { }); waitForPostedSwingRunnables(); assertTrue(action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); SwingUtilities.invokeAndWait(() -> { KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_Z, 'z'); @@ -633,14 +634,14 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Address addr = getAddr(0x01001000); assertEquals((byte) 0x7a, program.getMemory().getByte(addr)); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); SwingUtilities.invokeAndWait(() -> { action.setSelected(false); action.actionPerformed(new ActionContext()); }); assertTrue(!action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, c.getFocusedCursorColor()); } @@ -662,7 +663,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { action.actionPerformed(new ActionContext()); }); assertTrue(action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); SwingUtilities.invokeAndWait(() -> { FieldLocation loc = getFieldLocation(addr); @@ -675,14 +676,14 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertEquals((byte) 0x40, program.getMemory().getByte(addr)); FieldLocation loc = getFieldLocation(addr); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); SwingUtilities.invokeAndWait(() -> { action.setSelected(false); action.actionPerformed(new ActionContext()); }); assertTrue(!action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, c.getFocusedCursorColor()); } @@ -704,7 +705,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { action.actionPerformed(new ActionContext()); }); assertTrue(action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); byte value = program.getMemory().getByte(getAddr(0x01001000)); SwingUtilities.invokeAndWait(() -> { @@ -734,7 +735,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { action.actionPerformed(new ActionContext()); }); assertTrue(action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, c.getFocusedCursorColor()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, c.getFocusedCursorColor()); SwingUtilities.invokeAndWait(() -> { KeyEvent ev = new KeyEvent(c, 0, new Date().getTime(), 0, KeyEvent.VK_1, '1'); @@ -743,7 +744,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { }); program.flushEvents(); assertEquals((byte) 0x10, program.getMemory().getByte(getAddr(0x01001003))); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, ((ByteField) c.getCurrentField()).getForeground()); SwingUtilities.invokeAndWait(() -> { @@ -751,7 +752,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { action.actionPerformed(new ActionContext()); }); assertTrue(!action.isSelected()); - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, c.getFocusedCursorColor()); } @@ -801,7 +802,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { // verify that the bytes are rendered in red FieldLocation loc = getFieldLocation(addr); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, field.getForeground()); + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, field.getForeground()); addr = addr.add(i); } } @@ -1215,10 +1216,10 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Options opt = tool.getOptions("ByteViewer"); // change the color for Current View Cursor Color - putColor(opt, ByteViewerComponentProvider.OPTION_CURRENT_VIEW_CURSOR_COLOR, Color.GREEN); + putColor(opt, ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR_OPTION_NAME, Palette.GREEN); ByteViewerComponent c = panel.getCurrentComponent(); - assertEquals(Color.GREEN, c.getFocusedCursorColor()); + assertColorsEqual(Palette.GREEN, c.getFocusedCursorColor()); } @Test @@ -1235,10 +1236,11 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Options opt = tool.getOptions("ByteViewer"); // change the color for Current View Cursor Color - putColor(opt, ByteViewerComponentProvider.OPTION_CURSOR_COLOR, Color.GREEN); + putColor(opt, ByteViewerComponentProvider.CURSOR_NOT_FOCUSED_COLOR_OPTION_NAME, + Palette.GREEN); ByteViewerComponent c = findComponent(panel, "Octal"); - assertEquals(Color.GREEN, c.getNonFocusCursorColor()); + assertColorsEqual(Palette.GREEN, c.getNonFocusCursorColor()); } @Test @@ -1254,10 +1256,11 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Options opt = tool.getOptions("ByteViewer"); // change the color for Current View Cursor Color - putColor(opt, ByteViewerComponentProvider.OPTION_NONFOCUS_CURSOR_COLOR, Color.CYAN); + putColor(opt, ByteViewerComponentProvider.CURSOR_NOT_FOCUSED_COLOR_OPTION_NAME, + Palette.CYAN); ByteViewerComponent c = findComponent(panel, "Octal"); - assertEquals(Color.CYAN, c.getNonFocusCursorColor()); + assertColorsEqual(Palette.CYAN, c.getNonFocusCursorColor()); } private void putFont(final Options options, final String optionName, final Font font) { @@ -1282,7 +1285,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Options opt = tool.getOptions("ByteViewer"); // change the color for Edit Color - putColor(opt, ByteViewerComponentProvider.OPTION_EDIT_COLOR, Color.GREEN); + putColor(opt, ByteViewerComponentProvider.CHANGED_VALUE_COLOR_OPTION_NAME, Palette.GREEN); final FieldLocation loc = getFieldLocation(getAddr(0x01001000)); SwingUtilities.invokeAndWait(() -> { @@ -1302,7 +1305,7 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { program.flushEvents(); ByteViewerComponent c = panel.getCurrentComponent(); ByteField field = c.getField(loc.getIndex(), loc.getFieldNum()); - assertEquals(Color.GREEN, field.getForeground()); + assertColorsEqual(Palette.GREEN, field.getForeground()); } @Test @@ -1340,12 +1343,12 @@ public class ByteViewerPlugin2Test extends AbstractGhidraHeadedIntegrationTest { Options opt = tool.getOptions("ByteViewer"); // change the color for block separator - putColor(opt, ByteViewerComponentProvider.OPTION_SEPARATOR_COLOR, Color.GREEN); + putColor(opt, ByteViewerComponentProvider.SEPARATOR_COLOR_OPTION_NAME, Palette.GREEN); ByteViewerComponent c = panel.getCurrentComponent(); FieldLocation loc = getFieldLocation(getAddr(0x0f001000)); ByteField field = c.getField(loc.getIndex().subtract(BigInteger.ONE), 0); - assertEquals(Color.GREEN, field.getForeground()); + assertColorsEqual(Palette.GREEN, field.getForeground()); } @Test diff --git a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPluginFormatsTest.java b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPluginFormatsTest.java index cbd4235eaf..87a27d707f 100644 --- a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPluginFormatsTest.java +++ b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/app/plugin/core/byteviewer/ByteViewerPluginFormatsTest.java @@ -292,7 +292,7 @@ public class ByteViewerPluginFormatsTest extends AbstractGhidraHeadedIntegration hexComp.setCursorPosition(l.getIndex(), l.getFieldNum(), 0, 0); }); - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, ((ByteField) hexComp.getCurrentField()).getForeground()); } @@ -342,7 +342,7 @@ public class ByteViewerPluginFormatsTest extends AbstractGhidraHeadedIntegration // does not support editing Color fg = ((ByteField) c.getCurrentField()).getForeground(); if (fg != null) { - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, fg); + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, fg); } } @@ -391,7 +391,7 @@ public class ByteViewerPluginFormatsTest extends AbstractGhidraHeadedIntegration // does not support editing Color fg = ((ByteField) c.getCurrentField()).getForeground(); if (fg != null) { - assertEquals(ByteViewerComponentProvider.DEFAULT_CURRENT_CURSOR_COLOR, fg); + assertEquals(ByteViewerComponentProvider.CURSOR_ACTIVE_COLOR, fg); } } @@ -436,7 +436,7 @@ public class ByteViewerPluginFormatsTest extends AbstractGhidraHeadedIntegration intComp.setCursorPosition(l.getIndex(), l.getFieldNum(), 0, 0); }); // color should indicate the edit - assertEquals(ByteViewerComponentProvider.DEFAULT_EDIT_COLOR, + assertEquals(ByteViewerComponentProvider.CHANGED_VALUE_COLOR, ((ByteField) intComp.getCurrentField()).getForeground()); } diff --git a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java index c3f220b2c3..a528b49a82 100644 --- a/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java +++ b/Ghidra/Features/ByteViewer/src/test.slow/java/ghidra/framework/plugintool/dialog/SaveToolConfigDialogTest.java @@ -64,9 +64,8 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes private TestEnv env; private SaveToolConfigDialog saveDialog; private JTextField toolNameField; - private JList iconList; + private JList iconList; private JTextField iconNameField; - private PluginTool newtool; public SaveToolConfigDialogTest() { super(); @@ -161,11 +160,13 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes ToolTemplate template = tc.getToolTemplate("MyTestTool"); tc.remove("MyTestTool"); - ImageIcon icon = ResourceManager.getScaledIcon( - ResourceManager.loadImage("defaultTools/images/Caution.png"), + Icon icon = ResourceManager.getScaledIcon( + ResourceManager.loadIcon("defaultTools/images/Caution.png"), ToolIconURL.LARGE_ICON_SIZE, ToolIconURL.LARGE_ICON_SIZE); - assertEquals(icon.getDescription(), template.getIcon().getDescription()); + String expected = ResourceManager.getIconName(icon); + String actual = ResourceManager.getIconName(template.getIcon()); + assertEquals(expected, actual); } @Test @@ -323,7 +324,7 @@ public class SaveToolConfigDialogTest extends AbstractGhidraHeadedIntegrationTes assertNotNull(saveDialog); toolNameField = (JTextField) findComponentByName(saveDialog, "ToolName"); - iconList = (JList) findComponentByName(saveDialog, "IconList"); + iconList = (JList) findComponentByName(saveDialog, "IconList"); iconNameField = (JTextField) findComponentByName(saveDialog, "IconName"); } diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 48719dae14..2a833581c8 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -6,6 +6,7 @@ ##MODULE IP: Tango Icons - Public Domain .gitignore||GHIDRA||||END| Module.manifest||GHIDRA||||END| +data/decompiler.theme.properties||GHIDRA||||END| src/decompile/.cproject||GHIDRA||||END| src/decompile/.project||GHIDRA||||END| src/decompile/cpp/.gitignore||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/data/decompiler.theme.properties b/Ghidra/Features/Decompiler/data/decompiler.theme.properties new file mode 100644 index 0000000000..d25ca6ec0b --- /dev/null +++ b/Ghidra/Features/Decompiler/data/decompiler.theme.properties @@ -0,0 +1,60 @@ +[Defaults] + +color.bg.decompiler = color.bg +color.fg.decompiler = color.fg + +color.fg.decompiler.keyword = #0001e6 +color.fg.decompiler.function.name = blue +color.fg.decompiler.comment = blueViolet +color.fg.decompiler.error = crimson +color.fg.decompiler.variable = #999900 // close to oliveDrab +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 + +color.bg.decompiler.highlights.default = rgba(255, 255, 0, .5) +color.bg.decompiler.highlights.special = sandybrown +color.bg.decompiler.highlights.search = mediumslateblue + +color.bg.decompiler.pcode.dfg.vertex.default = red +color.bg.decompiler.pcode.dfg.vertex.selected = deeppink +color.bg.decompiler.pcode.dfg.vertex.constant = darkgreen +color.bg.decompiler.pcode.dfg.vertex.register = navy +color.bg.decompiler.pcode.dfg.vertex.unique = black +color.bg.decompiler.pcode.dfg.vertex.persistent = darkorange +color.bg.decompiler.pcode.dfg.vertex.address.tied = orange +color.bg.decompiler.pcode.dfg.vertex.op = red +color.bg.decompiler.pcode.dfg.edge.default = navy +color.bg.decompiler.pcode.dfg.edge.selected = deeppink +color.bg.decompiler.pcode.dfg.edge.within.block = black +color.bg.decompiler.pcode.dfg.edge.between.blocks = red +font.decompiler.pcode.dfg = font.graphdisplay.default + +icon.decompiler.action.provider = decompileFunction.gif +icon.decompiler.action.provider.clone = icon.provider.clone +icon.decompiler.action.export = page_edit.png + +font.decompiler = font.monospaced + +[Dark Defaults] + +color.fg.decompiler.keyword = color.palette.cyan +color.fg.decompiler.function.name = color.palette.blue +color.fg.decompiler.comment = color.palette.indigo +color.fg.decompiler.error = color.palette.red +color.fg.decompiler.variable = color.palette.olive +color.fg.decompiler.constant = color.palette.green +color.fg.decompiler.type = color.palette.cyan +color.fg.decompiler.parameter = color.palette.violetred +color.fg.decompiler.global = color.palette.teal +color.fg.decompiler.special = color.palette.red + + +color.bg.decompiler.middle.mouse = rgb(55,59,65) +color.bg.decompiler.current.variable = rgb(55, 59, 65) + diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java index 3a72b6a72a..09d7b29b26 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java @@ -54,18 +54,11 @@ import java.io.File; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; -import classrecovery.DecompilerScriptUtils; -import classrecovery.RTTIClassRecoverer; -import classrecovery.RTTIGccClassRecoverer; -import classrecovery.RTTIWindowsClassRecoverer; -import classrecovery.RecoveredClass; -import classrecovery.RecoveredClassHelper; +import classrecovery.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.decompiler.DecompInterface; import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.analysis.DecompilerFunctionAnalyzer; @@ -81,29 +74,11 @@ import ghidra.app.util.importer.MessageLog; import ghidra.app.util.opinion.ElfLoader; import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSet; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.DataTypeManager; -import ghidra.program.model.data.Structure; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.Parameter; -import ghidra.program.model.listing.Program; +import ghidra.program.model.address.*; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; -import ghidra.service.graph.AttributedEdge; -import ghidra.service.graph.AttributedGraph; -import ghidra.service.graph.AttributedVertex; -import ghidra.service.graph.GraphDisplay; -import ghidra.service.graph.GraphDisplayOptions; -import ghidra.service.graph.GraphDisplayOptionsBuilder; -import ghidra.service.graph.GraphDisplayProvider; -import ghidra.service.graph.GraphType; -import ghidra.service.graph.GraphTypeBuilder; -import ghidra.service.graph.VertexShape; -import ghidra.util.WebColors; +import ghidra.service.graph.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.GraphException; import ghidra.util.task.TaskMonitor; @@ -401,13 +376,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return analysisMode; } - - @Override - public void analyzeChanges(Program program) { - AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program); - mgr.startAnalysis(monitor, false); - } + @Override + public void analyzeChanges(Program program) { + AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program); + mgr.startAnalysis(monitor, false); + } /** * Method to create a class hierarchy graph where the parents are at the top of the graph and @@ -486,7 +460,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { edge.setEdgeType(NON_VIRTUAL_INHERITANCE); } - } } @@ -508,13 +481,13 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { display = service.getGraphDisplay(false, TaskMonitor.DUMMY); GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType()) - .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE) - .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN) - .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED) - .edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN) - .edge(VIRTUAL_INHERITANCE, WebColors.ORANGE) - .defaultVertexColor(WebColors.PURPLE) - .defaultEdgeColor(WebColors.PURPLE) + .vertex(NO_INHERITANCE, VertexShape.RECTANGLE, Palette.BLUE) + .vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, Palette.GREEN) + .vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, Palette.RED) + .edge(NON_VIRTUAL_INHERITANCE, Palette.LIME) + .edge(VIRTUAL_INHERITANCE, Palette.ORANGE) + .defaultVertexColor(Palette.PURPLE) + .defaultEdgeColor(Palette.PURPLE) .defaultLayoutAlgorithm("Compact Hierarchical") .build(); @@ -534,7 +507,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return doOutput; } - private void printClassHierarchyLists(List recoveredClasses) throws CancelledException { @@ -551,9 +523,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - - - /** * Script works on versions of ghidra including and after 9.2 except for 9.2.1 because a method * was accidentally removed from FillOutStructureCmd that is needed @@ -579,8 +548,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } boolean isCompilerSpecGcc = - currentProgram.getCompilerSpec().getCompilerSpecID().getIdAsString().equalsIgnoreCase( - "gcc"); + currentProgram.getCompilerSpec() + .getCompilerSpecID() + .getIdAsString() + .equalsIgnoreCase( + "gcc"); if (isCompilerSpecGcc) { return true; } @@ -598,8 +570,9 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { byte[] gccBytes = { (byte) 0x47, (byte) 0x43, (byte) 0x43, (byte) 0x3a }; byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; - Address found = currentProgram.getMemory().findBytes(commentBlock.getStart(), - commentBlock.getEnd(), gccBytes, maskBytes, true, monitor); + Address found = currentProgram.getMemory() + .findBytes(commentBlock.getStart(), + commentBlock.getEnd(), gccBytes, maskBytes, true, monitor); if (found == null) { isGcc = false; } @@ -621,8 +594,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return isWindows; } - - /** * Method to determine if somehow the constructor list and destructor list for a class contain * overlapping functions @@ -637,12 +608,18 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { recoverClassesFromRTTI.getAllClassDestructors(recoveredClass); List commonFunctions1 = - allClassConstructors.stream().distinct().filter(allClassDestructors::contains).collect( - Collectors.toList()); + allClassConstructors.stream() + .distinct() + .filter(allClassDestructors::contains) + .collect( + Collectors.toList()); List commonFunctions2 = - allClassDestructors.stream().distinct().filter(allClassConstructors::contains).collect( - Collectors.toList()); + allClassDestructors.stream() + .distinct() + .filter(allClassConstructors::contains) + .collect( + Collectors.toList()); if (commonFunctions1.isEmpty() && commonFunctions2.isEmpty()) { return false; @@ -661,8 +638,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { analyzer.added(currentProgram, set, monitor, new MessageLog()); } - - /** * Get the version of Ghidra that was used to analyze this program * @return a string containing the version number of Ghidra used to analyze the current program @@ -673,7 +648,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return options.getString("Created With Ghidra Version", null); } - /** * Method to bookmark all of the constructor/destructor/indeterminate functions * @param recoveredClasses List of classes @@ -686,7 +660,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { bookmarkRemainingIndeterminateConstructorsAndDestructors(recoveredClasses); } - /** * Method to print class hierarchy of the form child : parent: grandparent : etc... * @param stringBuffer the buffer to add the newly created string to @@ -707,7 +680,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { Map> classHierarchyMap = recoveredClass.getClassHierarchyMap(); - List parents = new ArrayList(classHierarchyMap.keySet()); + List parents = new ArrayList<>(classHierarchyMap.keySet()); // if single inheritance - simple linear case if (recoveredClass.hasSingleInheritance()) { @@ -742,9 +715,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } - - - /** * Method to retrieve the AddressSet of the current program's initialized memory * @return the AddressSet of the current program's initialized memory @@ -765,8 +735,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return dataAddresses; } - - /** * Method to bookmark found constructor functions * @param recoveredClasses List of classes @@ -810,7 +778,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - /** * Method to add/append analysis bookmarks with the given comment to the given list of functions * @param functions List of functions @@ -831,7 +798,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - /** * Method to optionally print to console or output to file various types of class information * depending on the options set at top of script @@ -894,7 +860,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - private void outputClassDefinitions(List recoveredClasses, PrintWriter out) throws CancelledException { for (RecoveredClass recoveredClass : recoveredClasses) { @@ -904,7 +869,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - } /** @@ -938,7 +902,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - /** * Method to print class hierarchies for the given list of classes starting with the lowest child classes in each family of classes * @param recoveredClasses the list of classes @@ -947,7 +910,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private void printClassHierarchiesFromLowestChildren( List recoveredClasses) throws CancelledException { - StringBuffer wholeBuffer = new StringBuffer(); wholeBuffer.append("\r\n"); for (RecoveredClass recoveredClass : recoveredClasses) { @@ -1006,7 +968,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - /** * Method to print counts of various class items for the given classes, such as number of constructors, destructors, etc... * @param recoveredClasses list of classes @@ -1014,7 +975,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { */ private void printCounts(List recoveredClasses) throws CancelledException { - println("Total number of constructors: " + recoverClassesFromRTTI.getNumberOfConstructors(recoveredClasses)); println("Total number of inlined constructors: " + @@ -1050,7 +1010,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } - /** * Method to get the total number of * @param recoveredClasses list of classes @@ -1099,7 +1058,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } } - /** * Method to output the class, it's parents and it's children for each of the listed classes * @param recoveredClasses the given classes @@ -1219,7 +1177,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("\tNone\r\n"); } - // print child classes stringBuffer.append("\r\n"); stringBuffer.append("child class(es):\r\n"); @@ -1279,7 +1236,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { // print const/dest that couldn't be classified correctly List indeterminateList = recoveredClass.getIndeterminateList(); if (indeterminateList.size() > 0) { - stringBuffer.append("\r\nindeterminate constructor(s) or destructor(s):\r\n"); + stringBuffer.append("\r\nindeterminate constructor(s) or destructor(s):\r\n"); for (Function indeterminateFunction : indeterminateList) { monitor.checkCanceled(); stringBuffer.append("\t" + indeterminateFunction.getName() + " " + @@ -1332,7 +1289,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return stringBuffer; } - /** * Method to get the function signature string, from the decompiler if possible, otherwise from * the listing @@ -1387,7 +1343,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return stringBuffer.toString(); } - /** * Method to create a string containing a C++-like representation of the given class * @param recoveredClass the given class @@ -1397,7 +1352,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { private StringBuffer createClassDefinitionString(RecoveredClass recoveredClass) throws CancelledException { - StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("\r\n\r\n"); @@ -1405,7 +1359,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { stringBuffer.append("\r\n{\r\n"); - // print constructor signature(s) stringBuffer.append("constructor(s):\r\n"); List constructorList = recoveredClass.getConstructorList(); @@ -1474,7 +1427,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { } stringBuffer.append("};\r\n"); - // Then recursively process the child classes if (recoveredClass.hasChildClass()) { List childClasses = recoveredClass.getChildClasses(); @@ -1487,6 +1439,4 @@ public class RecoverClassesFromRTTIScript extends GhidraScript { return stringBuffer; } - - } diff --git a/Ghidra/Features/Decompiler/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/Decompiler/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/Decompiler/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/Decompiler/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java index fb5d59265f..1ec6590391 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileOptions.java @@ -24,6 +24,9 @@ import java.awt.Font; import java.awt.event.MouseEvent; import java.io.IOException; +import generic.theme.GColor; +import generic.theme.Gui; +import ghidra.GhidraOptions; import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES; import ghidra.app.util.HelpTopics; import ghidra.framework.options.Options; @@ -37,7 +40,6 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.pcode.ElementId; import ghidra.program.model.pcode.Encoder; import ghidra.util.HelpLocation; -import ghidra.util.SystemUtilities; /** * Configuration options for the decompiler @@ -298,64 +300,60 @@ public class DecompileOptions { } } + //@formatter:off private final static IntegerFormatEnum INTEGERFORMAT_OPTIONDEFAULT = IntegerFormatEnum.BestFit; // Must match PrintLanguage::resetDefaultsInternal private IntegerFormatEnum integerFormat; - private final static Color HIGHLIGHT_MIDDLE_MOUSE_DEF = new Color(255, 255, 0, 128); - private Color middleMouseHighlightColor; private int middleMouseHighlightButton = MouseEvent.BUTTON2; - private final static String HIGHLIGHT_CURRENT_VARIABLE_MSG = - "Display.Color for Current Variable Highlight"; - private final static Color HIGHLIGHT_CURRENT_VARIABLE_DEF = new Color(255, 255, 0, 128); - private Color currentVariableHighlightColor; + private final static String HIGHLIGHT_CURRENT_VARIABLE_MSG ="Display.Color for Current Variable Highlight"; + private final static GColor HIGHLIGHT_CURRENT_VARIABLE_COLOR = new GColor("color.bg.decompiler.current.variable"); private final static String HIGHLIGHT_KEYWORD_MSG = "Display.Color for Keywords"; - private final static Color HIGHLIGHT_KEYWORD_DEF = Color.decode("0x0001E6"); - private Color keywordColor; + private final static GColor HIGHLIGHT_KEYWORD_COLOR = new GColor("color.fg.decompiler.keyword"); + private final static String HIGHLIGHT_FUNCTION_MSG = "Display.Color for Function names"; - private final static Color HIGHLIGHT_FUNCTION_DEF = Color.decode("0x0000FF"); - private Color functionColor; + private final static GColor HIGHLIGHT_FUNCTION_COLOR = new GColor("color.fg.decompiler.function.name"); + private final static String HIGHLIGHT_COMMENT_MSG = "Display.Color for Comments"; - private final static Color HIGHLIGHT_COMMENT_DEF = Color.decode("0x9600FF"); - private Color commentColor; + private final static GColor HIGHLIGHT_COMMENT_COLOR = new GColor( "color.fg.decompiler.comment"); + private final static String HIGHLIGHT_VARIABLE_MSG = "Display.Color for Variables"; - private final static Color HIGHLIGHT_VARIABLE_DEF = Color.decode("0x999900"); - private Color variableColor; + private final static GColor HIGHLIGHT_VARIABLE_COLOR = new GColor("color.fg.decompiler.variable"); + private final static String HIGHLIGHT_CONST_MSG = "Display.Color for Constants"; - private final static Color HIGHLIGHT_CONST_DEF = Color.decode("0x008E00"); - private Color constantColor; + private final static GColor HIGHLIGHT_CONST_COLOR = new GColor("color.fg.decompiler.constant"); + private final static String HIGHLIGHT_TYPE_MSG = "Display.Color for Types"; - private final static Color HIGHLIGHT_TYPE_DEF = Color.decode("0x0033CC"); - private Color typeColor; + private final static GColor HIGHLIGHT_TYPE_COLOR = new GColor("color.fg.decompiler.type"); + private final static String HIGHLIGHT_PARAMETER_MSG = "Display.Color for Parameters"; - private final static Color HIGHLIGHT_PARAMETER_DEF = Color.decode("0x9B009B"); - private Color parameterColor; + private final static GColor HIGHLIGHT_PARAMETER_COLOR = new GColor("color.fg.decompiler.parameter"); + private final static String HIGHLIGHT_GLOBAL_MSG = "Display.Color for Globals"; - private final static Color HIGHLIGHT_GLOBAL_DEF = Color.decode("0x009999"); - private Color globalColor; + private final static GColor 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_DEF = Color.decode("0xCC0033"); - private Color specialColor; + private final static GColor 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_DEF = Color.BLACK; - private Color defaultColor; + private final static GColor HIGHLIGHT_DEFAULT_COLOR = new GColor("color.fg.decompiler"); - private static final String CODE_VIEWER_BACKGROUND_COLOR_MSG = "Display.Background Color"; - private static final Color CODE_VIEWER_BACKGROUND_COLOR = Color.WHITE; - private Color codeViewerBackgroundColor; + private static final String SEARCH_HIGHLIGHT_MSG = "Display.Color for Highlighting Find Matches"; + private static final GColor SEARCH_HIGHLIGHT_COLOR = new GColor("color.bg.decompiler.highlights.search"); - private static final String SEARCH_HIGHLIGHT_MSG = - "Display.Color for Highlighting Find Matches"; - private static final Color SEARCH_HIGHLIGHT_DEF = new Color(100, 100, 255); - private Color defaultSearchHighlightColor = SEARCH_HIGHLIGHT_DEF; + + //@formatter:on + + private static final String BACKGROUND_COLOR_MSG = "Display.Background Color"; + private static final String BACKGROUND_COLOR_ID = "color.bg.decompiler"; + private static final GColor BACKGROUND_COLOR = new GColor(BACKGROUND_COLOR_ID); // Color applied to a token to indicate warning/error - private final static Color ERROR_COLOR = new Color(204, 0, 51); // Dark Red + private final static Color ERROR_COLOR = new GColor("color.fg.decompiler.comment"); final static String FONT_MSG = "Display.Font"; - final static Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, 12); - private Font defaultFont; + public final static String DEFAULT_FONT_ID = "font.decompiler"; private final static String CACHED_RESULTS_SIZE_MSG = "Cache Size (Functions)"; private final static int SUGGESTED_CACHED_RESULTS_SIZE = 10; @@ -402,18 +400,6 @@ public class DecompileOptions { commentHeadInclude = COMMENTHEAD_OPTIONDEFAULT; namespaceStrategy = NAMESPACE_OPTIONDEFAULT; integerFormat = INTEGERFORMAT_OPTIONDEFAULT; - 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; displayLineNumbers = LINE_NUMBER_DEF; displayLanguage = ProgramCompilerSpec.DECOMPILER_OUTPUT_DEF; protoEvalModel = "default"; @@ -466,23 +452,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); - 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); + 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); @@ -500,9 +470,6 @@ public class DecompileOptions { PluginTool tool = ownerPlugin.getTool(); Options toolOptions = tool.getOptions(CATEGORY_BROWSER_FIELDS); - middleMouseHighlightColor = - toolOptions.getColor(HIGHLIGHT_COLOR_NAME, HIGHLIGHT_MIDDLE_MOUSE_DEF); - CURSOR_MOUSE_BUTTON_NAMES mouseEvent = toolOptions.getEnum(CURSOR_HIGHLIGHT_BUTTON_NAME, CURSOR_MOUSE_BUTTON_NAMES.MIDDLE); middleMouseHighlightButton = mouseEvent.getMouseEventID(); @@ -619,43 +586,43 @@ public class DecompileOptions { opt.registerOption(INTEGERFORMAT_OPTIONSTRING, INTEGERFORMAT_OPTIONDEFAULT, new HelpLocation(HelpTopics.DECOMPILER, "DisplayIntegerFormat"), INTEGERFORMAT_OPTIONDESCRIPTION); - opt.registerOption(HIGHLIGHT_KEYWORD_MSG, HIGHLIGHT_KEYWORD_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_KEYWORD_MSG, HIGHLIGHT_KEYWORD_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting keywords."); - opt.registerOption(HIGHLIGHT_TYPE_MSG, HIGHLIGHT_TYPE_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_TYPE_MSG, HIGHLIGHT_TYPE_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting types."); - opt.registerOption(HIGHLIGHT_FUNCTION_MSG, HIGHLIGHT_FUNCTION_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_FUNCTION_MSG, HIGHLIGHT_FUNCTION_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting function names."); - opt.registerOption(HIGHLIGHT_COMMENT_MSG, HIGHLIGHT_COMMENT_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_COMMENT_MSG, HIGHLIGHT_COMMENT_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting comments."); - opt.registerOption(HIGHLIGHT_VARIABLE_MSG, HIGHLIGHT_VARIABLE_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_VARIABLE_MSG, HIGHLIGHT_VARIABLE_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting variables."); - opt.registerOption(HIGHLIGHT_CONST_MSG, HIGHLIGHT_CONST_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_CONST_MSG, HIGHLIGHT_CONST_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting constants."); - opt.registerOption(HIGHLIGHT_PARAMETER_MSG, HIGHLIGHT_PARAMETER_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_PARAMETER_MSG, HIGHLIGHT_PARAMETER_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting parameters."); - opt.registerOption(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for highlighting global variables."); - opt.registerOption(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"), "Color used for volatile or other exceptional variables."); - opt.registerOption(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayColorDefault"), "The color used when a specific color is not specified."); - opt.registerOption(CODE_VIEWER_BACKGROUND_COLOR_MSG, CODE_VIEWER_BACKGROUND_COLOR, + opt.registerThemeColorBinding(BACKGROUND_COLOR_MSG, BACKGROUND_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayBackgroundColor"), "The background color of the decompiler window."); - opt.registerOption(FONT_MSG, DEFAULT_FONT, + opt.registerThemeFontBinding(FONT_MSG, DEFAULT_FONT_ID, new HelpLocation(HelpTopics.DECOMPILER, "DisplayFont"), "The font used to render text in the decompiler."); - opt.registerOption(SEARCH_HIGHLIGHT_MSG, SEARCH_HIGHLIGHT_DEF, + opt.registerThemeColorBinding(SEARCH_HIGHLIGHT_MSG, SEARCH_HIGHLIGHT_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayFindHighlight"), "The color used to highlight matches using the Find Dialog."); opt.registerOption(LINE_NUMBER_MSG, LINE_NUMBER_DEF, @@ -672,7 +639,8 @@ public class DecompileOptions { opt.registerOption(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS, new HelpLocation(HelpTopics.DECOMPILER, "GeneralMaxInstruction"), "The maximum number of instructions decompiled in a single function"); - opt.registerOption(HIGHLIGHT_CURRENT_VARIABLE_MSG, HIGHLIGHT_CURRENT_VARIABLE_DEF, + opt.registerThemeColorBinding(HIGHLIGHT_CURRENT_VARIABLE_MSG, + HIGHLIGHT_CURRENT_VARIABLE_COLOR.getId(), new HelpLocation(HelpTopics.DECOMPILER, "DisplayCurrentHighlight"), "Current variable highlight"); opt.registerOption(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE, @@ -813,70 +781,70 @@ public class DecompileOptions { * @return color associated with keyword tokens */ public Color getKeywordColor() { - return keywordColor; + return HIGHLIGHT_KEYWORD_COLOR; } /** * @return color associated with data-type tokens */ public Color getTypeColor() { - return typeColor; + return HIGHLIGHT_TYPE_COLOR; } /** * @return color associated with a function name token */ public Color getFunctionColor() { - return functionColor; + return HIGHLIGHT_FUNCTION_COLOR; } /** * @return color used to display comments */ public Color getCommentColor() { - return commentColor; + return HIGHLIGHT_COMMENT_COLOR; } /** * @return color associated with constant tokens */ public Color getConstantColor() { - return constantColor; + return HIGHLIGHT_CONST_COLOR; } /** * @return color associated with (local) variable tokens */ public Color getVariableColor() { - return variableColor; + return HIGHLIGHT_VARIABLE_COLOR; } /** * @return color associated with parameter tokens */ public Color getParameterColor() { - return parameterColor; + return HIGHLIGHT_PARAMETER_COLOR; } /** * @return color associated with global variable tokens */ public Color getGlobalColor() { - return globalColor; + return HIGHLIGHT_GLOBAL_COLOR; } /** * @return color associated with volatile variables or other special tokens */ public Color getSpecialColor() { - return specialColor; + return HIGHLIGHT_SPECIAL_COLOR; } /** * @return color for generic syntax or other unspecified tokens */ public Color getDefaultColor() { - return defaultColor; + return HIGHLIGHT_DEFAULT_COLOR; } /** @@ -889,29 +857,29 @@ public class DecompileOptions { /** * @return the background color for the decompiler window */ - public Color getCodeViewerBackgroundColor() { - return codeViewerBackgroundColor; + public Color getBackgroundColor() { + return BACKGROUND_COLOR; } /** * @return the color used display the current highlighted variable */ public Color getCurrentVariableHighlightColor() { - return currentVariableHighlightColor; + return HIGHLIGHT_CURRENT_VARIABLE_COLOR; } /** * @return color used to highlight token(s) selected with a middle button clock */ public Color getMiddleMouseHighlightColor() { - return middleMouseHighlightColor; + return GhidraOptions.DEFAULT_HIGHLIGHT_COLOR; } /** * @return color used to highlight search results */ public Color getSearchHighlightColor() { - return defaultSearchHighlightColor; + return SEARCH_HIGHLIGHT_COLOR; } public int getMiddleMouseHighlightButton() { @@ -1011,7 +979,7 @@ public class DecompileOptions { } public Font getDefaultFont() { - return defaultFont; + return Gui.getFont(DEFAULT_FONT_ID); } public int getDefaultTimeout() { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangFieldElement.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangFieldElement.java index 920475991c..7ac8a4ebfe 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangFieldElement.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangFieldElement.java @@ -21,6 +21,7 @@ import java.awt.Graphics; import javax.swing.JComponent; import docking.widgets.fieldpanel.field.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.decompiler.ClangToken; public class ClangFieldElement extends AbstractTextFieldElement { @@ -49,7 +50,7 @@ public class ClangFieldElement extends AbstractTextFieldElement { if (token.isMatchingToken()) { // paint a bounding box around the token - g.setColor(Color.GRAY); + g.setColor(Palette.GRAY); int offset = 1; g.drawRect(x - offset, y - getHeightAbove() - offset, getStringWidth() + (offset * 2), getHeightAbove() + getHeightBelow() + (offset * 2)); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangHighlightController.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangHighlightController.java index bae9a14109..29314cebaf 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangHighlightController.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangHighlightController.java @@ -25,6 +25,7 @@ import org.apache.commons.collections4.map.LazyMap; import docking.widgets.EventTrigger; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GColor; import ghidra.app.decompiler.*; import ghidra.program.model.listing.Function; import ghidra.program.model.pcode.HighFunction; @@ -63,7 +64,8 @@ import util.CollectionUtils; */ public abstract class ClangHighlightController { - public static Color DEFAULT_HIGHLIGHT_COLOR = new Color(255, 255, 0, 128); + public static Color DEFAULT_HIGHLIGHT_COLOR = + new GColor("color.bg.decompiler.highlights.default"); public static ClangHighlightController dummyIfNull(ClangHighlightController c) { if (c == null) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java index a37dadf9c6..86fc41927f 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java @@ -37,6 +37,7 @@ import docking.widgets.fieldpanel.field.FieldElement; import docking.widgets.fieldpanel.listener.*; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexedScrollPane; +import generic.theme.GColor; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.hover.DecompilerHoverService; import ghidra.app.decompiler.component.margin.*; @@ -59,10 +60,11 @@ import ghidra.util.task.SwingUpdateManager; public class DecompilerPanel extends JPanel implements FieldMouseListener, FieldLocationListener, FieldSelectionListener, ClangHighlightListener, LayoutListener { - private final static Color NON_FUNCTION_BACKGROUND_COLOR_DEF = new Color(220, 220, 220); + private final static Color NON_FUNCTION_BACKGROUND_COLOR_DEF = new GColor("color.bg.undefined"); // Default color for specially highlighted tokens - private final static Color SPECIAL_COLOR_DEF = new Color(255, 100, 0, 128); + private final static Color SPECIAL_COLOR_DEF = + new GColor("color.bg.decompiler.highlights.special"); private final DecompilerController controller; private final DecompileOptions options; @@ -116,7 +118,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field layoutController = new ClangLayoutController(options, this, metrics, hlFactory); fieldPanel = new DecompilerFieldPanel(layoutController); - setBackground(options.getCodeViewerBackgroundColor()); + setBackground(options.getBackgroundColor()); scroller = new IndexedScrollPane(fieldPanel); fieldPanel.addFieldSelectionListener(this); @@ -520,7 +522,8 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field return; } - List tokens = DecompilerUtils.getTokensFromView(layoutController.getFields(), address); + List tokens = + DecompilerUtils.getTokensFromView(layoutController.getFields(), address); goToBeginningOfLine(tokens); } @@ -570,7 +573,8 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field return; } - int firstLineNumber = DecompilerUtils.findIndexOfFirstField(tokens, layoutController.getFields()); + int firstLineNumber = + DecompilerUtils.findIndexOfFirstField(tokens, layoutController.getFields()); if (firstLineNumber != -1) { fieldPanel.goTo(BigInteger.valueOf(firstLineNumber), 0, 0, 0, false); } @@ -629,7 +633,8 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field fieldSelection = new FieldSelection(); } else { - List tokens = DecompilerUtils.getTokens(layoutController.getRoot(), selection); + List tokens = + DecompilerUtils.getTokens(layoutController.getRoot(), selection); fieldSelection = DecompilerUtils.getFieldSelection(tokens); } fieldPanel.setSelection(fieldSelection); @@ -1159,7 +1164,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field } public void optionsChanged(DecompileOptions decompilerOptions) { - setBackground(decompilerOptions.getCodeViewerBackgroundColor()); + setBackground(decompilerOptions.getBackgroundColor()); currentVariableHighlightColor = options.getCurrentVariableHighlightColor(); middleMouseHighlightColor = decompilerOptions.getMiddleMouseHighlightColor(); middleMouseHighlightButton = decompilerOptions.getMiddleMouseHighlightButton(); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/HighlightToken.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/HighlightToken.java index 29acf550de..7ed8e5ca58 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/HighlightToken.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/HighlightToken.java @@ -42,6 +42,6 @@ public class HighlightToken { @Override public String toString() { - return token.toString() + "; color=" + color; + return token.toString() + "; highlight=" + color; } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/TokenHighlightColors.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/TokenHighlightColors.java index ad40804a16..50624937ed 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/TokenHighlightColors.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/TokenHighlightColors.java @@ -18,21 +18,27 @@ package ghidra.app.decompiler.component; import java.awt.Color; import java.util.*; +import generic.theme.Gui; + /** * A class to create and store colors related to token names */ public class TokenHighlightColors { - private int minColorSaturation = 100; - private int defaultColorAlpha = 100; private Map colorsByName = new HashMap<>(); private List recentColors = new ArrayList<>(); private Color generateColor() { - return new Color((int) (minColorSaturation + Math.random() * (256 - minColorSaturation)), - (int) (minColorSaturation + Math.random() * (256 - minColorSaturation)), - (int) (minColorSaturation + Math.random() * (256 - minColorSaturation)), - defaultColorAlpha); + + float h = (float) Math.random(); // 0-360 + float s = .25f; // saturation; gray to full color; full color is too harsh for highlights + float b = 1f; // brightness; black to full color + if (Gui.isDarkTheme()) { + s = .5f; // a bit more color against a dark background + b = .5f; // less brightness, as the background is not as bright + } + + return Color.getHSBColor(h, s, b); } public Color getColor(String text) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java index 47617b3d3a..6a0571ca03 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java @@ -21,12 +21,14 @@ import java.math.BigInteger; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.JComponent; import docking.*; import docking.action.*; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.ViewerPosition; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.*; @@ -51,7 +53,6 @@ import ghidra.util.Swing; import ghidra.util.bean.field.AnnotatedTextFieldElement; import ghidra.util.task.SwingUpdateManager; import resources.Icons; -import resources.ResourceManager; import utility.function.Callback; public class DecompilerProvider extends NavigatableComponentProviderAdapter @@ -61,8 +62,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter private static final String OPTIONS_TITLE = "Decompiler"; private static final Icon REFRESH_ICON = Icons.REFRESH_ICON; - private static final ImageIcon C_SOURCE_ICON = - ResourceManager.loadImage("images/decompileFunction.gif"); + private static final Icon C_SOURCE_ICON = new GIcon("icon.decompiler.action.provider"); private DockingAction pcodeGraphAction; private DockingAction astGraphAction; @@ -111,7 +111,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter this.plugin = plugin; this.clipboardProvider = new DecompilerClipboardProvider(plugin, this); - + registerAdjustableFontId(DecompileOptions.DEFAULT_FONT_ID); setConnected(isConnected); decompilerOptions = new DecompileOptions(); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CloneDecompilerAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CloneDecompilerAction.java index 51b8ee0384..864a5bd931 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CloneDecompilerAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/CloneDecompilerAction.java @@ -18,20 +18,20 @@ package ghidra.app.plugin.core.decompile.actions; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.KeyBindingData; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.app.plugin.core.decompile.DecompilerActionContext; import ghidra.app.util.HelpTopics; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class CloneDecompilerAction extends AbstractDecompilerAction { public CloneDecompilerAction() { super("Decompile Clone"); - ImageIcon image = ResourceManager.loadImage("images/camera-photo.png"); + Icon image = new GIcon("icon.decompiler.action.provider.clone"); setToolBarData(new ToolBarData(image, "ZZZ")); setDescription("Create a snapshot (disconnected) copy of this Decompiler window "); setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ToolBarSnapshot")); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java index 2a1461d8a6..94aeca06f1 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ExportToCAction.java @@ -17,11 +17,12 @@ package ghidra.app.plugin.core.decompile.actions; import java.io.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.action.ToolBarData; import docking.widgets.OptionDialog; import docking.widgets.filechooser.GhidraFileChooser; +import generic.theme.GIcon; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.DecompilerPanel; import ghidra.app.plugin.core.decompile.DecompilerActionContext; @@ -30,10 +31,9 @@ import ghidra.framework.preferences.Preferences; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.filechooser.ExtensionFileFilter; -import resources.ResourceManager; public class ExportToCAction extends AbstractDecompilerAction { - private static final ImageIcon EXPORT_ICON = ResourceManager.loadImage("images/page_edit.png"); + private static final Icon EXPORT_ICON = new GIcon("icon.decompiler.action.export"); private static final String LAST_USED_C_FILE = "last.used.decompiler.c.export.file"; public ExportToCAction() { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java index b2b11dce56..d01ba7b102 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java @@ -20,7 +20,6 @@ import static ghidra.service.graph.VertexShape.*; import ghidra.framework.plugintool.PluginTool; import ghidra.service.graph.*; -import ghidra.util.WebColors; /** * {@link GraphDisplayOptions} for {@link PCodeDfgGraphType} @@ -28,6 +27,22 @@ import ghidra.util.WebColors; public class PCodeDfgDisplayOptions extends GraphDisplayOptions { public static final String SHAPE_ATTRIBUTE = "Shape"; + // @formatter:off + private static final String BG_VERTEX_DEFAULT = "color.bg.decompiler.pcode.dfg.vertex.default"; + private static final String BG_VERTEX_SELECTED ="color.bg.decompiler.pcode.dfg.vertex.selected"; + private static final String BG_VERTEX_CONSTANT ="color.bg.decompiler.pcode.dfg.vertex.constant"; + private static final String BG_VERTEX_REGISTER ="color.bg.decompiler.pcode.dfg.vertex.register"; + private static final String BG_VERTEX_UNIQUE ="color.bg.decompiler.pcode.dfg.vertex.unique"; + private static final String BG_VERTEX_PERSISTENT ="color.bg.decompiler.pcode.dfg.vertex.persistent"; + private static final String BG_VERTEX_ADDRESS_TIED ="color.bg.decompiler.pcode.dfg.vertex.address.tied"; + private static final String BG_VERTEX_OP ="color.bg.decompiler.pcode.dfg.vertex.op"; + + private static final String BG_EDGE_DEFAULT ="color.bg.decompiler.pcode.dfg.edge.default"; + private static final String BG_EDGE_SELECTED ="color.bg.decompiler.pcode.dfg.edge.selected"; + private static final String BG_EDGE_WITHIN_BLOCK ="color.bg.decompiler.pcode.dfg.edge.within.block"; + private static final String BG_EDGE_BETWEEN_BLOCKS ="color.bg.decompiler.pcode.dfg.edge.between.blocks"; + // @formatter:on + /** * constructor * @param tool if non-null, will load values from tool options @@ -39,10 +54,10 @@ public class PCodeDfgDisplayOptions extends GraphDisplayOptions { @Override protected void initializeDefaults() { setDefaultVertexShape(ELLIPSE); - setDefaultVertexColor(WebColors.RED); - setDefaultEdgeColor(WebColors.NAVY); - setVertexSelectionColor(WebColors.DEEP_PINK); - setEdgeSelectionColor(WebColors.DEEP_PINK); + setDefaultVertexColor(BG_VERTEX_DEFAULT); + setDefaultEdgeColor(BG_EDGE_DEFAULT); + setVertexSelectionColor(BG_VERTEX_SELECTED); + setEdgeSelectionColor(BG_EDGE_SELECTED); setDefaultLayoutAlgorithmName(LayoutAlgorithmNames.MIN_CROSS_COFFMAN_GRAHAM); setUsesIcons(false); setArrowLength(15); @@ -50,16 +65,18 @@ public class PCodeDfgDisplayOptions extends GraphDisplayOptions { setVertexShapeOverrideAttributeKey(SHAPE_ATTRIBUTE); setMaxNodeCount(1000); - configureVertexType(DEFAULT_VERTEX, VertexShape.ELLIPSE, WebColors.RED); - configureVertexType(CONSTANT, VertexShape.ELLIPSE, WebColors.DARK_GREEN); - configureVertexType(REGISTER, VertexShape.ELLIPSE, WebColors.NAVY); - configureVertexType(UNIQUE, VertexShape.ELLIPSE, WebColors.BLACK); - configureVertexType(PERSISTENT, VertexShape.ELLIPSE, WebColors.DARK_ORANGE); - configureVertexType(ADDRESS_TIED, VertexShape.ELLIPSE, WebColors.ORANGE); - configureVertexType(OP, VertexShape.ELLIPSE, WebColors.RED); + configureVertexType(DEFAULT_VERTEX, VertexShape.ELLIPSE, BG_VERTEX_DEFAULT); + configureVertexType(CONSTANT, VertexShape.ELLIPSE, BG_VERTEX_CONSTANT); + configureVertexType(REGISTER, VertexShape.ELLIPSE, BG_VERTEX_REGISTER); + configureVertexType(UNIQUE, VertexShape.ELLIPSE, BG_VERTEX_UNIQUE); + configureVertexType(PERSISTENT, VertexShape.ELLIPSE, BG_VERTEX_PERSISTENT); + configureVertexType(ADDRESS_TIED, VertexShape.ELLIPSE, BG_VERTEX_ADDRESS_TIED); + configureVertexType(OP, VertexShape.ELLIPSE, BG_VERTEX_OP); - configureEdgeType(DEFAULT_EDGE, WebColors.BLUE); - configureEdgeType(WITHIN_BLOCK, WebColors.BLACK); - configureEdgeType(BETWEEN_BLOCKS, WebColors.RED); + configureEdgeType(DEFAULT_EDGE, BG_EDGE_DEFAULT); + configureEdgeType(WITHIN_BLOCK, BG_EDGE_WITHIN_BLOCK); + configureEdgeType(BETWEEN_BLOCKS, BG_EDGE_BETWEEN_BLOCKS); + + setFont("font.decompiler.pcode.dfg"); } } diff --git a/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/decompiler/component/DecompilerClangTest.java b/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/decompiler/component/DecompilerClangTest.java index 844ce66f58..4c4ca9b293 100644 --- a/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/decompiler/component/DecompilerClangTest.java +++ b/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/decompiler/component/DecompilerClangTest.java @@ -35,6 +35,7 @@ import docking.widgets.dialogs.InputDialog; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.cmd.comments.SetCommentCmd; import ghidra.app.decompiler.*; import ghidra.app.decompiler.DecompileOptions.NamespaceStrategy; @@ -927,7 +928,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { String secondaryHighlightText = token.getText(); assertEquals("_printf", secondaryHighlightText); - Color myColor = Color.PINK; + Color myColor = Palette.PINK; highlightWithColorChooser(myColor); assertAllFieldsSecondaryHighlighted(token, myColor); } @@ -964,13 +965,13 @@ public class DecompilerClangTest extends AbstractDecompilerTest { String secondaryHighlightText = token.getText(); assertEquals("_printf", secondaryHighlightText); - Color myColor = Color.PINK; + Color myColor = Palette.PINK; highlightWithColorChooser(myColor); removeSecondaryHighlight(); Color hlColor2 = highlight(); - assertEquals(myColor, hlColor2); + assertEquals(myColor.getRGB(), hlColor2.getRGB()); } @Test @@ -1130,7 +1131,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1180,7 +1181,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { assertPrimaryHighlights("(\"call_structure_A: %s\\n\",a->name)"); String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1242,7 +1243,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { assertAllFieldsSecondaryHighlighted(secondrayToken, secondaryHlColor); String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1304,7 +1305,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { assertAllFieldsSecondaryHighlighted(secondaryToken, secondaryHlColor); String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1352,7 +1353,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText1 = "_printf"; - Color hlColor1 = Color.PINK; + Color hlColor1 = Palette.PINK; CTokenHighlightMatcher hlMatcher1 = token -> { if (token.getText().contains(hlText1)) { return hlColor1; @@ -1370,7 +1371,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { assertNoFieldsSecondaryHighlighted(hlText1); String hlText2 = "name"; - Color hlColor2 = Color.GREEN; + Color hlColor2 = Palette.GREEN; CTokenHighlightMatcher hlMatcher2 = token -> { if (token.getText().contains(hlText2)) { return hlColor2; @@ -1424,7 +1425,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { assertPrimaryHighlights("(\"call_structure_A: %s\\n\",a->name)"); String hlText = "_printf"; - Color hlColor1 = Color.PINK; + Color hlColor1 = Palette.PINK; CTokenHighlightMatcher hlMatcher1 = token -> { if (token.getText().contains(hlText)) { return hlColor1; @@ -1436,7 +1437,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { DecompilerHighlighter highlighter1 = hlService.createHighlighter(spyMatcher1); highlighter1.applyHighlights(); - Color hlColor2 = Color.GREEN; + Color hlColor2 = Palette.GREEN; CTokenHighlightMatcher hlMatcher2 = token -> { if (token.getText().contains(hlText)) { return hlColor2; @@ -1485,7 +1486,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1532,7 +1533,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1590,7 +1591,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1638,7 +1639,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1688,7 +1689,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1736,7 +1737,7 @@ public class DecompilerClangTest extends AbstractDecompilerTest { decompile("100000d60"); // '_call_structure_A' String hlText = "_printf"; - Color hlColor = Color.PINK; + Color hlColor = Palette.PINK; CTokenHighlightMatcher hlMatcher = token -> { if (token.getText().contains(hlText)) { return hlColor; @@ -1980,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() { @@ -2278,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; } } diff --git a/Ghidra/Features/FileFormats/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/FileFormats/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/FileFormats/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/FileFormats/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/FunctionGraph/certification.manifest b/Ghidra/Features/FunctionGraph/certification.manifest index 67278e5076..05bca5ea1c 100644 --- a/Ghidra/Features/FunctionGraph/certification.manifest +++ b/Ghidra/Features/FunctionGraph/certification.manifest @@ -5,6 +5,7 @@ ##MODULE IP: Tango Icons - Public Domain Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/functiongraph.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END| src/main/help/help/shared/close16.gif||GHIDRA||reviewed||END| @@ -65,8 +66,6 @@ src/main/resources/images/fgpaths.png||GHIDRA||reviewed||END| src/main/resources/images/fgrevblock.png||GHIDRA||reviewed||END| src/main/resources/images/field.header.png||GHIDRA||reviewed|Custom icon|END| src/main/resources/images/fullscreen_view.png||FAMFAMFAM Icons - CC 2.5||||END| -src/main/resources/images/function_graph.png||FAMFAMFAM Icons - CC 2.5||||END| -src/main/resources/images/function_graph_curvey.png||GHIDRA||reviewed|author eric|END| src/main/resources/images/graph_view.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/house.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/id.png||FAMFAMFAM Icons - CC 2.5||||END| diff --git a/Ghidra/Features/FunctionGraph/data/functiongraph.theme.properties b/Ghidra/Features/FunctionGraph/data/functiongraph.theme.properties new file mode 100644 index 0000000000..b563482268 --- /dev/null +++ b/Ghidra/Features/FunctionGraph/data/functiongraph.theme.properties @@ -0,0 +1,79 @@ +[Defaults] + + +color.bg.functiongraph = color.bg + +color.fg.label.picked = color.fg +color.fg.label.non.picked = color.fg.disabled + +color.bg.functiongraph.vertex.group = rgb(226, 255, 155) +color.bg.functiongraph.vertex.entry = color.palette.lightgreen +color.bg.functiongraph.vertex.exit = color.palette.lightred +color.bg.functiongraph.vertex.picked = color.palette.yellow + +color.bg.functiongraph.edge.fall.through = color.flowtype.fall.through +color.bg.functiongraph.edge.fall.through.highlight = rgb(255, 127, 127) +color.bg.functiongraph.edge.jump.conditional = color.flowtype.jump.conditional +color.bg.functiongraph.edge.jump.conditional.highlight = lime +color.bg.functiongraph.edge.jump.unconditional = color.flowtype.jump.unconditional +color.bg.functiongraph.edge.jump.unconditional.highlight = rgb(127, 127, 255) + +color.bg.functiongraph.paint.icon = rgb(189, 221, 252) // gentle pale blue + + +icon.functiongraph.layout.experimental = package_development.png +icon.functiongraph.action.vertex.xrefs = brick_link.png +icon.functiongraph.action.vertex.maximize = fullscreen_view.png +icon.functiongraph.action.vertex.minimize = graph_view.png +icon.functiongraph.action.vertex.group = shape_handles.png +icon.functiongraph.action.vertex.group.add = shape_square_add.png +icon.functiongraph.action.vertex.regroup = edit-redo.png +icon.functiongraph.action.vertex.ungroup = shape_ungroup.png +icon.functiongraph.action.vertex.choose.color = paintbrush.png +icon.functiongraph.action.vertex.choose.color.palette = palette.png +icon.functiongraph.action.vertex.edit.label = id.png +icon.functiongraph.action.vertex.full.screen = fullscreen_view.png +icon.functiongraph.action.vertex.edit.format = field.header.png + +icon.functiongraph.action.viewer.clone = icon.provider.clone +icon.functiongraph.action.viewer.layout = preferences-system.png +icon.functiongraph.action.viewer.vertex.hover.paths.to.vertex = fgin.png +icon.functiongraph.action.viewer.vertex.hover.paths.from.vertex = fgout.png +icon.functiongraph.action.viewer.vertex.hover.paths.from.to.vertex = fginout.png +icon.functiongraph.action.viewer.vertex.hover.paths.all = fgpaths.png +icon.functiongraph.action.viewer.vertex.hover.cycles = fgloop.png +icon.functiongraph.action.viewer.vertex.hover.cycles.all = fgloopall.png +icon.functiongraph.action.viewer.vertex.hover.scoped.flow.forward = fgblock.png +icon.functiongraph.action.viewer.vertex.hover.scoped.flow.reverse = fgrevblock.png +icon.functiongraph.action.viewer.vertex.hover.off = hoverOff.gif + +icon.functiongraph.action.viewer.home = house.png +icon.functiongraph.action.viewer.reset = icon.refresh + +icon.functiongraph.action.provider = function_graph.png +icon.functiongraph.action.provider.satellite = network-wireless-16.png + + +[Dark Defaults] + + +// color.bg.functiongraph = color.bg + +// color.fg.label.picked = color.fg +// color.fg.label.non.picked = color.fg.disabled + +color.bg.functiongraph.vertex.group = rgb(226, 222, 179) // TODO confirm value +// color.bg.functiongraph.vertex.entry = color.palette.lightgreen +// color.bg.functiongraph.vertex.exit = color.palette.lightred +// color.bg.functiongraph.vertex.picked = color.palette.yellow + +// color.bg.functiongraph.edge.fall.through = color.flowtype.fall.through +color.bg.functiongraph.edge.fall.through.highlight = rgb(165, 76, 80) +// color.bg.functiongraph.edge.jump.conditional = color.flowtype.jump.conditional +color.bg.functiongraph.edge.jump.conditional.highlight = rgb(95, 160, 196) +// color.bg.functiongraph.edge.jump.unconditional = color.flowtype.jump.unconditional +color.bg.functiongraph.edge.jump.unconditional.highlight = rgb(140, 162, 88) + + +// TODO dark version color.bg.functiongraph.paint.icon = // TODO + diff --git a/Ghidra/Features/FunctionGraph/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/FunctionGraph/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/FunctionGraph/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/FunctionGraph/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html b/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html index b66dce8c8f..97a6c2207a 100644 --- a/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html +++ b/Ghidra/Features/FunctionGraph/src/main/help/help/topics/FunctionGraphPlugin/Function_Graph.html @@ -33,51 +33,6 @@ "#Function_Graph_Actions">actions that apply to the entire graph.

-

NoteWhat's New

- -
    -
  • - Added the Nested Code Layout. This layout shows the code blocks - in a structure that more closely resembles the flow of C code. -
  • -
  • - Small tweaks (6.0) - -
      -
    • - Detachable Satellite View -
    • -
    • Function signature now included by default
    • - -
    • Added a regroup action to allow for regrouping - vertices after ungrouping.
    • - -
    • Articulated edges will now disappear if the connected vertices are dragged outside of - the original angles.
    • - -
    • - Moved some actions to the context popup menu, - specifically: - -
        -
      • Edit Label
      • - -
      • Fullscreen Mode
      • - -
      • Jump to XRef
      • -
      -
    • -
    -
  • - -
  • Layout Compressing (5.6)
  • - -
  • Keyboard zooming and panning (5.6)
  • - -
  • Vertex Grouping (5.5)
  • -

-
-

Primary View

diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGActionManager.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGActionManager.java index 9aed1f44af..51bfce4980 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGActionManager.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGActionManager.java @@ -19,7 +19,8 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.*; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.KeyStroke; import docking.ActionContext; import docking.DockingUtils; @@ -29,6 +30,7 @@ import docking.menu.MultiStateDockingAction; import docking.widgets.EventTrigger; import docking.widgets.OptionDialog; import edu.uci.ics.jung.graph.Graph; +import generic.theme.GIcon; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.core.functiongraph.action.*; import ghidra.app.plugin.core.functiongraph.graph.FGEdge; @@ -48,8 +50,6 @@ import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.HelpLocation; import ghidra.util.SystemUtilities; -import resources.Icons; -import resources.ResourceManager; class FGActionManager { private static final String EDGE_HOVER_HIGHLIGHT = "EDGE_HOVER_HIGHLIGHT"; @@ -60,10 +60,15 @@ class FGActionManager { private static final String COMPLEX_LAYOUT_NAME = "COMPLEX_LAYOUT_NAME"; private static final String LAYOUT_CLASS_NAME = "LAYOUT_CLASS_NAME"; - private static final ImageIcon EDIT_ICON = ResourceManager.loadImage("images/id.png"); - private static final ImageIcon FULL_SCREEN_ICON = - ResourceManager.loadImage("images/fullscreen_view.png"); - private static final Icon XREFS_ICON = ResourceManager.loadImage("images/brick_link.png"); + //@formatter:off + private static final Icon GROUP_ICON = new GIcon("icon.functiongraph.action.vertex.group"); + private static final Icon GROUP_ADD_ICON = new GIcon("icon.functiongraph.action.vertex.group.add"); + private static final Icon UNGROUP_ICON = new GIcon("icon.functiongraph.action.vertex.ungroup"); + + private static final Icon EDIT_ICON = new GIcon("icon.functiongraph.action.vertex.edit.label"); + private static final Icon FULL_SCREEN_ICON = new GIcon("icon.functiongraph.action.vertex.full.screen"); + private static final Icon XREFS_ICON = new GIcon("icon.functiongraph.action.vertex.full.screen"); + //@formatter:off private PluginTool tool; private FunctionGraphPlugin plugin; @@ -122,7 +127,7 @@ class FGActionManager { // subgroup 3, after the refresh and layout actions chooseFormatsAction.setToolBarData(new ToolBarData( - ResourceManager.loadImage("images/field.header.png"), layoutGroup, "3")); + new GIcon("icon.functiongraph.action.vertex.edit.format"), layoutGroup, "3")); chooseFormatsAction.setHelpLocation( new HelpLocation("FunctionGraphPlugin", "Function_Graph_Action_Format")); @@ -139,7 +144,7 @@ class FGActionManager { } }; homeAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/house.png"), toolBarGroup1)); + new ToolBarData(new GIcon("icon.functiongraph.action.viewer.home"), toolBarGroup1)); homeAction.setHelpLocation( new HelpLocation("FunctionGraphPlugin", "Function_Graph_Action_Home")); @@ -160,7 +165,8 @@ class FGActionManager { return controller.hasResults(); } }; - resetGraphAction.setToolBarData(new ToolBarData(Icons.REFRESH_ICON, layoutGroup, "1")); + resetGraphAction.setToolBarData( + new ToolBarData(new GIcon("icon.functiongraph.action.viewer.reset"), layoutGroup, "1")); resetGraphAction.setDescription("Reloads the graph--All positioning and grouping " + "information is lost"); resetGraphAction.setHelpLocation( @@ -442,7 +448,7 @@ class FGActionManager { } }; menuData = new MenuData(new String[] { "Group Selected Vertices" }, popupMutateGroup2); - menuData.setIcon(FunctionGraphPlugin.GROUP_ICON); + menuData.setIcon(GROUP_ICON); menuData.setMenuSubGroup(Integer.toString(groupingSubgroupOffset++)); groupSelectedVertices.setPopupMenuData(menuData); groupSelectedVertices.setHelpLocation( @@ -501,7 +507,7 @@ class FGActionManager { menuData = new MenuData(new String[] { "Group Selected Vertices - Add to Group" }, popupMutateGroup2); - menuData.setIcon(FunctionGraphPlugin.GROUP_ADD_ICON); + menuData.setIcon(GROUP_ADD_ICON); menuData.setMenuSubGroup(Integer.toString(groupingSubgroupOffset++)); addSelectedVerticesToGroup.setPopupMenuData(menuData); addSelectedVerticesToGroup.setHelpLocation(new HelpLocation("FunctionGraphPlugin", @@ -544,7 +550,7 @@ class FGActionManager { }; menuData = new MenuData(new String[] { "Ungroup Selected Vertices" }, popupMutateGroup2); - menuData.setIcon(FunctionGraphPlugin.UNGROUP_ICON); + menuData.setIcon(UNGROUP_ICON); menuData.setMenuSubGroup(Integer.toString(groupingSubgroupOffset++)); ungroupSelectedVertices.setPopupMenuData(menuData); ungroupSelectedVertices.setHelpLocation( @@ -653,7 +659,7 @@ class FGActionManager { return controller.getGraphedFunction() != null; } }; - ImageIcon image = ResourceManager.loadImage("images/camera-photo.png"); + Icon image = new GIcon("icon.functiongraph.action.viewer.clone"); cloneAction.setToolBarData(new ToolBarData(image, toolbarEndGroup)); cloneAction.setDescription( "Create a snapshot (disconnected) copy of this Function Graph window "); @@ -883,7 +889,7 @@ class FGActionManager { // This icon will display when the action has no icon. This allows actions with no good // icon to be blank in the menu, but to use this icon on the toolbar. - layoutAction.setDefaultIcon(ResourceManager.loadImage("images/preferences-system.png")); + layoutAction.setDefaultIcon(new GIcon("icon.functiongraph.action.viewer.layout")); List> actionStates = loadActionStatesForLayoutProviders(); for (ActionState actionState : actionStates) { @@ -936,14 +942,17 @@ class FGActionManager { } private void addVertexHoverModeAction(String group) { - Icon pathsToVertexIcon = ResourceManager.loadImage("images/fgin.png"); - Icon pathsFromVertexIcon = ResourceManager.loadImage("images/fgout.png"); - Icon pathsFromToVertexIcon = ResourceManager.loadImage("images/fginout.png"); - Icon cyclesIcon = ResourceManager.loadImage("images/fgloop.png"); - Icon pathsIcon = ResourceManager.loadImage("images/fgpaths.png"); - Icon forwardScopedIcon = ResourceManager.loadImage("images/fgblock.png"); - Icon reverseScopedIcon = ResourceManager.loadImage("images/fgrevblock.png"); - Icon nothingIcon = ResourceManager.loadImage("images/hoverOff.gif"); + + //@formatter:off + Icon pathsToVertexIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.to.vertex"); + Icon pathsFromVertexIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.from.vertex"); + Icon pathsFromToVertexIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.from.to.vertex"); + Icon pathsIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.all"); + Icon cyclesIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.cycles"); + Icon forwardScopedIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.scoped.flow.forward"); + Icon reverseScopedIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.scoped.flow.reverse"); + Icon nothingIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.off"); + //@formatter:off HelpLocation pathHelpLocation = new HelpLocation("FunctionGraphPlugin", "Path_Highlight_Actions"); @@ -1011,14 +1020,18 @@ class FGActionManager { } private void addVertexSelectedModeAction(String group) { - Icon pathsToVertexIcon = ResourceManager.loadImage("images/fgin.png"); - Icon pathsFromVertexIcon = ResourceManager.loadImage("images/fgout.png"); - Icon pathsFromToVertexIcon = ResourceManager.loadImage("images/fginout.png"); - Icon cyclesIcon = ResourceManager.loadImage("images/fgloop.png"); - Icon allCyclesIcon = ResourceManager.loadImage("images/fgloopall.png"); - Icon forwardScopedIcon = ResourceManager.loadImage("images/fgblock.png"); - Icon reverseScopedIcon = ResourceManager.loadImage("images/fgrevblock.png"); - Icon nothingIcon = ResourceManager.loadImage("images/hoverOff.gif"); + + //@formatter:off + Icon pathsToVertexIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.to.vertex"); + Icon pathsFromVertexIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.from.vertex"); + Icon pathsFromToVertexIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.paths.from.to.vertex"); + Icon cyclesIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.cycles"); + Icon allCyclesIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.cycles.all"); + Icon forwardScopedIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.scoped.flow.forward"); + Icon reverseScopedIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.scoped.flow.reverse"); + Icon nothingIcon = new GIcon("icon.functiongraph.action.viewer.vertex.hover.off"); + //@formatter:off + HelpLocation pathHelpLocation = new HelpLocation("FunctionGraphPlugin", "Path_Highlight_Actions"); diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGSatelliteUndockedProvider.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGSatelliteUndockedProvider.java index fa82a7a72d..096bc836f1 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGSatelliteUndockedProvider.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FGSatelliteUndockedProvider.java @@ -22,15 +22,15 @@ import javax.swing.Icon; import javax.swing.JComponent; import docking.*; +import generic.theme.GIcon; import ghidra.app.plugin.core.functiongraph.mvc.FGController; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class FGSatelliteUndockedProvider extends ComponentProviderAdapter { static final String NAME = "Function Graph Satellite"; - private static final Icon ICON = ResourceManager.loadImage("images/network-wireless-16.png"); + private static final Icon ICON = new GIcon("icon.functiongraph.action.provider.satellite"); private FGController controller; private JComponent satelliteComponent; diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin.java index d5478cf390..bd0d9c6b73 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/FunctionGraphPlugin.java @@ -17,11 +17,12 @@ package ghidra.app.plugin.core.functiongraph; import java.util.*; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.jdom.Element; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.events.*; @@ -44,7 +45,6 @@ import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.exception.AssertException; -import resources.ResourceManager; //@formatter:off @PluginInfo( @@ -61,14 +61,7 @@ public class FunctionGraphPlugin extends ProgramPlugin implements OptionsChangeL static final String OPTIONS_NAME_PATH = ToolConstants.GRAPH_OPTIONS + Options.DELIMITER + FUNCTION_GRAPH_NAME; - static final ImageIcon ICON = ResourceManager.loadImage("images/function_graph.png"); - - public static final ImageIcon GROUP_ICON = - ResourceManager.loadImage("images/shape_handles.png"); - public static final ImageIcon GROUP_ADD_ICON = - ResourceManager.loadImage("images/shape_square_add.png"); - public static final ImageIcon UNGROUP_ICON = - ResourceManager.loadImage("images/shape_ungroup.png"); + static final Icon ICON = new GIcon("icon.functiongraph.action.provider"); private static final String USER_DEFINED_FORMAT_CONFIG_NAME = "USER_DEFINED_FORMAT_MANAGER"; diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/IndependentColorProvider.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/IndependentColorProvider.java index e6d2f18f69..8e11947bdb 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/IndependentColorProvider.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/IndependentColorProvider.java @@ -24,6 +24,7 @@ import org.jdom.Element; import docking.ComponentPlaceholder; import docking.DockingWindowManager; import docking.options.editor.GhidraColorChooser; +import generic.theme.GColor; import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex; import ghidra.app.plugin.core.functiongraph.mvc.FunctionGraphVertexAttributes; import ghidra.framework.options.SaveState; @@ -111,8 +112,7 @@ class IndependentColorProvider implements FGColorProvider { List colorElements = xmlElement.getChildren("COLOR"); for (Element element : colorElements) { String rgbString = element.getAttributeValue("RGB"); - int rgb = Integer.parseInt(rgbString); - recentColorCache.addColor(new Color(rgb, true)); + recentColorCache.addColor(Color.decode(rgbString)); } } } @@ -138,7 +138,9 @@ class IndependentColorProvider implements FGColorProvider { //================================================================================================== private class RecentColorCache extends LinkedHashMap implements Iterable { private static final int MAX_SIZE = 10; - private Color mostRecentColor = Color.blue; + + // not sure what the default color should be here + private Color mostRecentColor = new GColor("color.bg"); RecentColorCache() { super(16, 0.75f, true); diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/FGComponent.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/FGComponent.java index ba23771b28..251ba6aa38 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/FGComponent.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/FGComponent.java @@ -26,7 +26,7 @@ import edu.uci.ics.jung.visualization.RenderContext; import edu.uci.ics.jung.visualization.picking.PickedState; import edu.uci.ics.jung.visualization.renderers.Renderer; import edu.uci.ics.jung.visualization.util.Caching; -import ghidra.app.plugin.core.functiongraph.graph.jung.renderer.FGEdgePaintTransformer; +import generic.theme.GColor; import ghidra.app.plugin.core.functiongraph.graph.jung.renderer.FGVertexRenderer; import ghidra.app.plugin.core.functiongraph.graph.jung.transformer.FGVertexPickableBackgroundPaintTransformer; import ghidra.app.plugin.core.functiongraph.graph.layout.FGLayout; @@ -36,8 +36,8 @@ import ghidra.graph.viewer.*; import ghidra.graph.viewer.layout.LayoutListener.ChangeType; import ghidra.graph.viewer.layout.LayoutProvider; import ghidra.graph.viewer.layout.VisualGraphLayout; -import ghidra.graph.viewer.options.VisualGraphOptions; import ghidra.graph.viewer.renderer.VisualGraphEdgeLabelRenderer; +import ghidra.graph.viewer.vertex.AbstractVisualVertexRenderer; import ghidra.program.model.listing.Function; import ghidra.program.util.ProgramLocation; import ghidra.util.SystemUtilities; @@ -45,9 +45,12 @@ import ghidra.util.UndefinedFunction; public class FGComponent extends GraphComponent { - private static final Color END_COLOR = new Color(255, 127, 127); - private static final Color START_COLOR = new Color(127, 255, 127); - private static final Color UNDEFINED_FUNCTION_COLOR = new Color(220, 220, 220); + //@formatter:off + private static final Color PICKED_COLOR = new GColor("color.bg.functiongraph.vertex.picked"); + private static final Color START_COLOR = new GColor("color.bg.functiongraph.vertex.entry"); + private static final Color END_COLOR = new GColor("color.bg.functiongraph.vertex.exit"); + private static final Color UNDEFINED_FUNCTION_COLOR = new GColor("color.bg.undefined"); + //@formatter:on /** * A somewhat arbitrary value that is used to signal a 'big' graph, which is one that will @@ -190,23 +193,25 @@ public class FGComponent extends GraphComponent @Override protected FGPrimaryViewer createPrimaryGraphViewer(VisualGraphLayout layout, Dimension viewerSize) { + return new FGPrimaryViewer(this, layout, viewerSize); + } - FGPrimaryViewer viewer = new FGPrimaryViewer(this, layout, viewerSize); + @Override + protected void decoratePrimaryViewer(GraphViewer viewer, + VisualGraphLayout layout) { - RenderContext renderContext = viewer.getRenderContext(); - FGEdgePaintTransformer edgePaintTransformer = - new FGEdgePaintTransformer(getFucntionGraphOptions()); - renderContext.setEdgeDrawPaintTransformer(edgePaintTransformer); - renderContext.setArrowDrawPaintTransformer(edgePaintTransformer); - renderContext.setArrowFillPaintTransformer(edgePaintTransformer); + super.decoratePrimaryViewer(viewer, layout); + // the edge renderer was set by the parent call; get the renderer to add our painter Renderer renderer = viewer.getRenderer(); - renderer.setVertexRenderer(new FGVertexRenderer()); + RenderContext renderContext = viewer.getRenderContext(); // for background colors when we are zoomed to far to render the listing PickedState pickedVertexState = viewer.getPickedVertexState(); - renderContext.setVertexFillPaintTransformer(new FGVertexPickableBackgroundPaintTransformer( - pickedVertexState, Color.YELLOW, START_COLOR, END_COLOR)); + FGVertexRenderer vertexRenderer = new FGVertexRenderer(); + vertexRenderer.setVertexFillPaintTransformer(new FGVertexPickableBackgroundPaintTransformer( + pickedVertexState, PICKED_COLOR, START_COLOR, END_COLOR)); + renderer.setVertexRenderer(vertexRenderer); // edge label rendering com.google.common.base.Function edgeLabelTransformer = e -> e.getLabel(); @@ -215,14 +220,14 @@ public class FGComponent extends GraphComponent // note: this label renderer is the stamp for the label; we use another edge label // renderer inside of the VisualGraphRenderer VisualGraphEdgeLabelRenderer edgeLabelRenderer = - new VisualGraphEdgeLabelRenderer(Color.BLACK); - edgeLabelRenderer.setNonPickedForegroundColor(Color.LIGHT_GRAY); + new VisualGraphEdgeLabelRenderer(new GColor("color.fg.label.picked")); + edgeLabelRenderer.setNonPickedForegroundColor(new GColor("color.fg.label.non.picked")); edgeLabelRenderer.setRotateEdgeLabels(false); renderContext.setEdgeLabelRenderer(edgeLabelRenderer); viewer.setGraphOptions(vgOptions); Color bgColor = vgOptions.getGraphBackgroundColor(); - if (bgColor.equals(VisualGraphOptions.DEFAULT_GRAPH_BACKGROUND_COLOR)) { + if (vgOptions.isDefaultBackgroundColor(bgColor)) { // Give user notice when seeing the graph for a non-function (such as an undefined // function), as this is typical for Ghidra UI widgets. @@ -233,35 +238,33 @@ public class FGComponent extends GraphComponent viewer.setBackground(UNDEFINED_FUNCTION_COLOR); } else { - viewer.setBackground(Color.WHITE); + viewer.setBackground(new GColor("color.bg.functiongraph")); } } - return viewer; } @Override - protected SatelliteGraphViewer createSatelliteGraphViewer( - GraphViewer masterViewer, Dimension viewerSize) { + protected void decorateSatelliteViewer(SatelliteGraphViewer viewer, + VisualGraphLayout layout) { - SatelliteGraphViewer viewer = - super.createSatelliteGraphViewer(masterViewer, viewerSize); + super.decorateSatelliteViewer(viewer, layout); - RenderContext renderContext = viewer.getRenderContext(); + // the edge renderer was set by the parent call; get the renderer to add our painter + Renderer renderer = viewer.getRenderer(); - FGEdgePaintTransformer edgePaintTransformer = - new FGEdgePaintTransformer(getFucntionGraphOptions()); - renderContext.setEdgeDrawPaintTransformer(edgePaintTransformer); - renderContext.setArrowDrawPaintTransformer(edgePaintTransformer); - renderContext.setArrowFillPaintTransformer(edgePaintTransformer); + AbstractVisualVertexRenderer vertexRenderer = + (AbstractVisualVertexRenderer) renderer.getVertexRenderer(); PickedState pickedVertexState = viewer.getPickedVertexState(); + + RenderContext renderContext = viewer.getRenderContext(); renderContext.setVertexFillPaintTransformer(new FGVertexPickableBackgroundPaintTransformer( - pickedVertexState, Color.YELLOW, START_COLOR, END_COLOR)); + pickedVertexState, PICKED_COLOR, START_COLOR, END_COLOR)); + vertexRenderer.setVertexFillPaintTransformer(new FGVertexPickableBackgroundPaintTransformer( + pickedVertexState, PICKED_COLOR, START_COLOR, END_COLOR)); viewer.setGraphOptions(vgOptions); - - return viewer; } @Override @@ -286,7 +289,7 @@ public class FGComponent extends GraphComponent // FG-specific Client Methods //================================================================================================== - public FunctionGraphOptions getFucntionGraphOptions() { + public FunctionGraphOptions getFunctionGraphOptions() { return (FunctionGraphOptions) vgOptions; } diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgePaintTransformer.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgePaintTransformer.java deleted file mode 100644 index 29cb3b36a9..0000000000 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgePaintTransformer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.plugin.core.functiongraph.graph.jung.renderer; - -import java.awt.Color; -import java.awt.Paint; - -import com.google.common.base.Function; - -import ghidra.app.plugin.core.functiongraph.graph.FGEdge; -import ghidra.app.plugin.core.functiongraph.mvc.FunctionGraphOptions; -import ghidra.program.model.symbol.FlowType; - -public class FGEdgePaintTransformer implements Function { - - private FunctionGraphOptions options; - - public FGEdgePaintTransformer(FunctionGraphOptions options) { - this.options = options; - } - - @Override - public Paint apply(FGEdge e) { - FlowType flowType = e.getFlowType(); - Color color = options.getColor(flowType); - return color; - } -} diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgeRenderer.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgeRenderer.java index f46ee6534d..cc77eee231 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgeRenderer.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/renderer/FGEdgeRenderer.java @@ -23,6 +23,7 @@ import ghidra.app.plugin.core.functiongraph.graph.FunctionGraph; import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex; import ghidra.app.plugin.core.functiongraph.mvc.FunctionGraphOptions; import ghidra.graph.viewer.renderer.ArticulatedEdgeRenderer; +import ghidra.program.model.symbol.FlowType; /** * A renderer used by the Function Graph API to provide additional edge coloring, as @@ -31,13 +32,21 @@ import ghidra.graph.viewer.renderer.ArticulatedEdgeRenderer; public class FGEdgeRenderer extends ArticulatedEdgeRenderer { @Override - public Color getBaseColor(Graph g, FGEdge e) { + public Color getDrawColor(Graph g, FGEdge e) { + FunctionGraphOptions options = getOptions(g); + FlowType flowType = e.getFlowType(); + Color color = options.getColor(flowType); + return color; + } + + @Override + public Color getFocusedColor(Graph g, FGEdge e) { FunctionGraphOptions options = getOptions(g); return options.getColor(e.getFlowType()); } @Override - public Color getHighlightColor(Graph g, FGEdge e) { + public Color getSelectedColor(Graph g, FGEdge e) { FunctionGraphOptions options = getOptions(g); return options.getHighlightColor(e.getFlowType()); } diff --git a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/transformer/FGVertexPickableBackgroundPaintTransformer.java b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/transformer/FGVertexPickableBackgroundPaintTransformer.java index 05717b396b..1c180d2c23 100644 --- a/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/transformer/FGVertexPickableBackgroundPaintTransformer.java +++ b/Ghidra/Features/FunctionGraph/src/main/java/ghidra/app/plugin/core/functiongraph/graph/jung/transformer/FGVertexPickableBackgroundPaintTransformer.java @@ -17,13 +17,16 @@ package ghidra.app.plugin.core.functiongraph.graph.jung.transformer; import java.awt.Color; import java.awt.Paint; +import java.util.Objects; import com.google.common.base.Function; import edu.uci.ics.jung.visualization.picking.PickedInfo; +import generic.theme.Gui; import ghidra.app.plugin.core.functiongraph.graph.FGVertexType; import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex; import ghidra.program.util.ProgramSelection; +import ghidra.util.ColorUtils; public class FGVertexPickableBackgroundPaintTransformer implements Function { @@ -31,26 +34,22 @@ public class FGVertexPickableBackgroundPaintTransformer implements Function info, Color pickedColor, Color startColor, Color endColor) { - if (info == null) { - throw new IllegalArgumentException("PickedInfo instance must be non-null"); - } - this.info = info; + this.info = Objects.requireNonNull(info); this.pickedColor = pickedColor; this.entryColor = startColor; this.exitColor = endColor; - this.pickedStartColor = mix(pickedColor, startColor); - this.pickedEndColor = mix(pickedColor, endColor); + this.pickedEntryColor = mix(pickedColor, startColor); + this.pickedExitColor = mix(pickedColor, endColor); } @Override @@ -69,20 +68,31 @@ public class FGVertexPickableBackgroundPaintTransformer implements Function
Function ID
  Next +��Next
@@ -290,14 +290,14 @@ parameter information is stripped. - - + - + - +
  Next +��Next
Function ID Function ID�  Function ID Plug-in�Function ID Plug-in
diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidDebugUtils.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidDebugUtils.java index 4e3b2e2423..e6a27900f4 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidDebugUtils.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidDebugUtils.java @@ -15,7 +15,6 @@ */ package ghidra.feature.fid.debug; -import java.awt.Font; import java.util.*; import javax.swing.*; @@ -29,7 +28,6 @@ import ghidra.util.NumericUtilities; * Utility class to handle some debug functions for the FID database. */ public class FidDebugUtils { - public static final Font MONOSPACED_FONT = new Font("monospaced", Font.PLAIN, 12); /** * Search the FID system for function records by name substring. diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidFunctionDebugPanel.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidFunctionDebugPanel.java index bed86e1b2c..68d6a58835 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidFunctionDebugPanel.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidFunctionDebugPanel.java @@ -21,6 +21,8 @@ import java.awt.event.ActionListener; import javax.swing.*; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults; +import generic.theme.Gui; import ghidra.feature.fid.db.*; import ghidra.feature.fid.service.FidService; import ghidra.program.model.lang.LanguageID; @@ -55,7 +57,7 @@ public class FidFunctionDebugPanel extends JPanel { JButton button = new JButton(text); button.addActionListener(listener); button.setHorizontalAlignment(SwingConstants.LEFT); - button.setFont(FidDebugUtils.MONOSPACED_FONT); + Gui.registerFont(button, GThemeDefaults.Ids.Fonts.MONOSPACED); add(button); } @@ -66,7 +68,7 @@ public class FidFunctionDebugPanel extends JPanel { private void addLabel(String text) { JLabel label = new GDLabel(text); label.setHorizontalAlignment(SwingConstants.LEFT); - label.setFont(FidDebugUtils.MONOSPACED_FONT); + label.setFont(Gui.getFont("font.monospaced")); add(label); } diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchDebugDialog.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchDebugDialog.java index 817ca11cbe..3ba1bb1279 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchDebugDialog.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchDebugDialog.java @@ -21,6 +21,8 @@ import javax.swing.*; import docking.DialogComponentProvider; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Ids.Fonts; +import generic.theme.Gui; import ghidra.feature.fid.db.FidFileManager; import ghidra.feature.fid.db.FidQueryService; import ghidra.feature.fid.plugin.FidPlugin; @@ -75,13 +77,13 @@ public class FidSearchDebugDialog extends DialogComponentProvider { private JLabel getPreparedLabel(String text) { JLabel label = new GDLabel(text, SwingConstants.RIGHT); - label.setFont(FidDebugUtils.MONOSPACED_FONT); + label.setFont(Gui.getFont(Fonts.MONOSPACED)); return label; } private JTextField getPreparedTextField() { JTextField textField = new JTextField(25); - textField.setFont(FidDebugUtils.MONOSPACED_FONT); + textField.setFont(Gui.getFont(Fonts.MONOSPACED)); return textField; } diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchResultFrame.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchResultFrame.java index 2824cb401a..1e246cedc7 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchResultFrame.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/debug/FidSearchResultFrame.java @@ -26,6 +26,8 @@ import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import docking.widgets.table.*; +import generic.theme.GThemeDefaults.Ids.Fonts; +import generic.theme.Gui; import ghidra.feature.fid.db.*; import ghidra.feature.fid.service.FidService; import ghidra.util.Msg; @@ -64,7 +66,7 @@ public class FidSearchResultFrame extends JFrame implements FidQueryCloseListene private void buildFrame() { GTableCellRenderer renderer = new GTableCellRenderer(); - renderer.setFont(FidDebugUtils.MONOSPACED_FONT); + renderer.setFont(Gui.getFont(Fonts.MONOSPACED)); int columnCount = table.getColumnCount(); for (int ii = 0; ii < columnCount; ++ii) { Class columnClass = table.getColumnClass(ii); diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/ActiveFidConfigureDialog.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/ActiveFidConfigureDialog.java index e9530bb460..2f14e305a9 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/ActiveFidConfigureDialog.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/ActiveFidConfigureDialog.java @@ -24,6 +24,7 @@ import javax.swing.*; import docking.DialogComponentProvider; import docking.widgets.checkbox.GCheckBox; +import generic.theme.GThemeDefaults; import ghidra.feature.fid.db.FidFile; import ghidra.util.HelpLocation; import ghidra.util.layout.VerticalLayout; @@ -89,7 +90,7 @@ public class ActiveFidConfigureDialog extends DialogComponentProvider { private Component buildCheckBoxPanel() { JPanel panel = new JPanel(new VerticalLayout(5)); panel.setOpaque(true); - panel.setBackground(Color.WHITE); + panel.setBackground(GThemeDefaults.Colors.BACKGROUND); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); for (FidFile fidFile : fidFiles) { GCheckBox checkbox = new GCheckBox(fidFile.getName(), fidFile.isActive()); diff --git a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/PopulateFidDialog.java b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/PopulateFidDialog.java index 9ea0309e4e..5fdb212694 100644 --- a/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/PopulateFidDialog.java +++ b/Ghidra/Features/FunctionID/src/main/java/ghidra/feature/fid/plugin/PopulateFidDialog.java @@ -15,7 +15,8 @@ */ package ghidra.feature.fid.plugin; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Component; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -279,10 +280,7 @@ public class PopulateFidDialog extends DialogComponentProvider { } private JButton createBrowseButton() { - JButton browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE); - Font font = browseButton.getFont(); - browseButton.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); - return browseButton; + return ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE); } private static class LibraryChoice { diff --git a/Ghidra/Features/GraphFunctionCalls/certification.manifest b/Ghidra/Features/GraphFunctionCalls/certification.manifest index f6a0d9a87d..90d6cbdf19 100644 --- a/Ghidra/Features/GraphFunctionCalls/certification.manifest +++ b/Ghidra/Features/GraphFunctionCalls/certification.manifest @@ -1,6 +1,7 @@ ##VERSION: 2.0 ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||||END| +data/functioncallgraph.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||||END| src/main/help/help/shared/close16.gif||GHIDRA||||END| diff --git a/Ghidra/Features/GraphFunctionCalls/data/functioncallgraph.theme.properties b/Ghidra/Features/GraphFunctionCalls/data/functioncallgraph.theme.properties new file mode 100644 index 0000000000..ff7fa7a791 --- /dev/null +++ b/Ghidra/Features/GraphFunctionCalls/data/functioncallgraph.theme.properties @@ -0,0 +1,29 @@ +[Defaults] + +color.bg.fcg.vertex.default = rgb(110, 197, 174) // chill green +color.bg.fcg.vertex.toobig = color.palette.lightgray + +color.bg.fcg.edge.primary.direct = rgb(143, 197, 143) // light pale green +color.bg.fcg.edge.primary.direct.selected = rgb(68, 171, 96) // lighter green +color.bg.fcg.edge.primary.indirect = rgb(233, 233, 233) // lightGray +color.bg.fcg.edge.primary.indirect.selected = rgb(201, 195, 195) + +// the satellite gets too cluttered, so wash out the edges +color.bg.fcg.edge.satellite.direct = rgba(0,0,0,0.1) // 'washed out black' +color.bg.fcg.edge.satellite.indirect = rgba(125, 125, 125, 25) // 'washed out gray' + +icon.fcg.layout.bow.tie = color_swatch.png + + +[Dark Defaults] + +// TODO dark colors +// TODO color.bg.fcg.vertex.default = rgb(110, 197, 174) // chill green +// TODO color.bg.fcg.vertex.toobig = color.palette.lightGray + +// TODO color.bg.fcg.edge.primary.direct = rgb(143, 197, 143) // lightGreen +// TODO color.bg.fcg.edge.primary.indirect = rgb(233, 233, 233) // lightGray + +// the satellite gets too cluttered, so wash out the edges +// TODO color.bg.fcg.edge.satellite.direct = rgba(0,0,0,0.1) // 'washed out black' +// TODO color.bg.fcg.edge.satellite.indirect = rgba(125, 125, 125, 25) // 'washed out gray' \ No newline at end of file diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/GraphFunctionCalls/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/GraphFunctionCalls/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java index 2f8a1e73ef..e69ca9448c 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java +++ b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java @@ -28,6 +28,9 @@ import javax.swing.border.LineBorder; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GDLabel; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; +import generic.theme.Gui; import ghidra.graph.viewer.vertex.AbstractVisualVertex; import ghidra.graph.viewer.vertex.VertexShapeProvider; import ghidra.program.model.address.Address; @@ -41,9 +44,10 @@ import resources.ResourceManager; */ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvider { - // TODO to be made an option in an upcoming ticket - public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new Color(110, 197, 174); - private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = Color.LIGHT_GRAY; + //@formatter:off + public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new GColor("color.bg.fcg.vertex.default"); + private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = new GColor("color.bg.fcg.vertex.toobig"); + //@formatter:on public static final Icon NOT_ALLOWED_ICON = Icons.ERROR_ICON; private static final Icon EXPAND_ICON = @@ -52,9 +56,9 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid ResourceManager.getScaledIcon(Icons.COLLAPSE_ALL_ICON, 10, 10); // higher numbered layers go on top - private static final Integer VERTEX_SHAPE_LAYER = new Integer(100); - private static final Integer TOGGLE_BUTTON_LAYER = new Integer(200); - private static final Integer LABEL_LAYER = new Integer(300); + private static final Integer VERTEX_SHAPE_LAYER = 100; + private static final Integer TOGGLE_BUTTON_LAYER = 200; + private static final Integer LABEL_LAYER = 300; private static final int GAP = 2; private static final int VERTEX_SHAPE_SIZE = 50; @@ -128,8 +132,8 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid Color vertexShapeColor = getVertexShapeColor(); Color lightColor = vertexShapeColor; - Color darkColor = vertexShapeColor.darker(); - Color darkestColor = darkColor.darker(); + Color darkColor = Gui.darker(vertexShapeColor); + Color darkestColor = Gui.darker(darkColor); int offset = 5 * level.getDistance(); int half = VERTEX_SHAPE_SIZE / 2; int start = 0; @@ -156,7 +160,7 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid // calculate the needed size layeredPane = new JLayeredPane(); - Border border = createDebugBorder(new LineBorder(Color.YELLOW.darker(), 1)); + Border border = createDebugBorder(new LineBorder(Palette.GOLD, 1)); layeredPane.setBorder(border); updateLayeredPaneSize(); @@ -246,7 +250,7 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid compactShape = (Double) vertexShape.clone(); vertexImageLabel.setIcon(new ImageIcon(image)); - Border border = createDebugBorder(new LineBorder(Color.PINK, 1)); + Border border = createDebugBorder(new LineBorder(Palette.PINK, 1)); vertexImageLabel.setBorder(border); } @@ -295,7 +299,7 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid private void addNameLabel() { - Border border = createDebugBorder(new LineBorder(Color.GREEN, 1)); + Border border = createDebugBorder(new LineBorder(Palette.GREEN, 1)); nameLabel.setBorder(border); // assume the vertex label has been bounded @@ -312,8 +316,8 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid private void addToggleButtons() { // hide the button background - toggleInsButton.setBackground(new Color(255, 255, 255, 0)); - toggleOutsButton.setBackground(new Color(255, 255, 255, 0)); + toggleInsButton.setBackground(Palette.NO_COLOR); + toggleOutsButton.setBackground(Palette.NO_COLOR); Rectangle parentBounds = vertexImageLabel.getBounds(); Dimension size = toggleInsButton.getPreferredSize(); @@ -546,7 +550,7 @@ public class FcgVertex extends AbstractVisualVertex implements VertexShapeProvid /** * Sets whether this vertex has any outgoing references * - * @param hasIncoming true if this vertex has any incoming references + * @param hasOutgoing true if this vertex has any outgoing references */ public void setHasOutgoingReferences(boolean hasOutgoing) { diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java index 3d5985820a..ad87a802e2 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java +++ b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java @@ -18,11 +18,11 @@ package functioncalls.graph.layout; import javax.swing.Icon; import functioncalls.graph.*; +import generic.theme.GIcon; import ghidra.graph.viewer.layout.AbstractLayoutProvider; import ghidra.graph.viewer.layout.VisualGraphLayout; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; /** * A layout provider for the {@link BowTieLayout} @@ -32,7 +32,7 @@ public class BowTieLayoutProvider public static final String NAME = "Bow Tie Layout"; - private static final Icon DEFAULT_ICON = ResourceManager.loadImage("images/color_swatch.png"); + private static final Icon DEFAULT_ICON = new GIcon("icon.fcg.layout.bow.tie"); @Override public VisualGraphLayout getLayout(FunctionCallGraph graph, diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java index 7b09ef621d..428aa3555e 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java +++ b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java @@ -16,18 +16,17 @@ package functioncalls.graph.renderer; import java.awt.Color; -import java.awt.Paint; import com.google.common.base.Function; import functioncalls.graph.FcgEdge; +import ghidra.util.ColorUtils; /** * Generates colors for a given {@link FcgEdge} */ -public class FcgEdgePaintTransformer implements Function { +public class FcgEdgePaintTransformer implements Function { - // private static final Paint LESS_IMPORTANT_COLOR = new Color(125, 125, 125, 75); private Color directColor; private Color indirectColor; @@ -46,13 +45,13 @@ public class FcgEdgePaintTransformer implements Function { alphad[0] = c; for (int i = 1; i < 10; i++) { double newAlpha = 255 - (i * 25.5); - alphad[i] = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int) newAlpha); + alphad[i] = ColorUtils.withAlpha(c, (int) newAlpha); } return alphad; } @Override - public Paint apply(FcgEdge e) { + public Color apply(FcgEdge e) { if (e.isDirectEdge()) { return getDirectEdgeColor(e); } diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java index b39e333a70..a1a516bffc 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java +++ b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java @@ -15,15 +15,17 @@ */ package functioncalls.graph.view; -import java.awt.Color; - -import edu.uci.ics.jung.visualization.RenderContext; +import edu.uci.ics.jung.visualization.renderers.Renderer; import functioncalls.graph.*; import functioncalls.graph.renderer.FcgEdgePaintTransformer; import functioncalls.graph.renderer.FcgVertexPaintTransformer; import functioncalls.plugin.FunctionCallGraphPlugin; +import generic.theme.GColor; import ghidra.graph.viewer.*; +import ghidra.graph.viewer.edge.VisualEdgeRenderer; import ghidra.graph.viewer.layout.VisualGraphLayout; +import ghidra.graph.viewer.renderer.VisualVertexSatelliteRenderer; +import ghidra.graph.viewer.vertex.VisualVertexRenderer; /** * A graph component for the {@link FunctionCallGraphPlugin} @@ -33,23 +35,20 @@ public class FcgComponent extends GraphComponent renderContext = viewer.getRenderContext(); - renderContext.setVertexFillPaintTransformer(vertexPaintTransformer); - - // Note: setting the fill for the edges has the effect of drawing a filled-in circle - // instead of just the outer edge. - // renderContext.setEdgeFillPaintTransformer(edgePaintTransformer); - renderContext.setEdgeDrawPaintTransformer(edgePaintTransformer); - renderContext.setArrowFillPaintTransformer(edgePaintTransformer); - renderContext.setArrowDrawPaintTransformer(edgePaintTransformer); + Renderer renderer = viewer.getRenderer(); + VisualVertexRenderer vertexRenderer = + (VisualVertexRenderer) renderer.getVertexRenderer(); + vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer); + VisualEdgeRenderer edgeRenderer = + (VisualEdgeRenderer) renderer.getEdgeRenderer(); + edgeRenderer.setDrawColorTransformer(edgePaintTransformer); + edgeRenderer.setSelectedColorTransformer(selectedEdgePaintTransformer); } @Override @@ -83,12 +81,14 @@ public class FcgComponent extends GraphComponent renderContext = viewer.getRenderContext(); - renderContext.setVertexFillPaintTransformer(vertexPaintTransformer); - //renderContext.setEdgeFillPaintTransformer(satelliteEdgePaintTransformer); - renderContext.setEdgeDrawPaintTransformer(satelliteEdgePaintTransformer); - renderContext.setArrowFillPaintTransformer(satelliteEdgePaintTransformer); - renderContext.setArrowDrawPaintTransformer(satelliteEdgePaintTransformer); + Renderer renderer = viewer.getRenderer(); + VisualVertexSatelliteRenderer vertexRenderer = + (VisualVertexSatelliteRenderer) renderer.getVertexRenderer(); + vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer); + + VisualEdgeRenderer edgeRenderer = + (VisualEdgeRenderer) renderer.getEdgeRenderer(); + edgeRenderer.setDrawColorTransformer(satelliteEdgePaintTransformer); } @Override diff --git a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/plugin/FunctionCallGraphPlugin.java b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/plugin/FunctionCallGraphPlugin.java index b35dea5d95..3e95ee994e 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/plugin/FunctionCallGraphPlugin.java +++ b/Ghidra/Features/GraphFunctionCalls/src/main/java/functioncalls/plugin/FunctionCallGraphPlugin.java @@ -146,9 +146,6 @@ public class FunctionCallGraphPlugin extends ProgramPlugin implements OptionsCha } }; -// TODO create icon from scratch: bow-tie -// ImageIcon icon = ResourceManager.loadImage("images/applications-development.png"); -// showProviderAction.setToolBarData(new ToolBarData(icon, "View")); tool.addAction(showProviderAction); } diff --git a/Ghidra/Features/GraphFunctionCalls/src/screen/java/help/screenshot/FunctionCallGraphPluginScreenShots.java b/Ghidra/Features/GraphFunctionCalls/src/screen/java/help/screenshot/FunctionCallGraphPluginScreenShots.java index ea448159ba..3750614fd2 100644 --- a/Ghidra/Features/GraphFunctionCalls/src/screen/java/help/screenshot/FunctionCallGraphPluginScreenShots.java +++ b/Ghidra/Features/GraphFunctionCalls/src/screen/java/help/screenshot/FunctionCallGraphPluginScreenShots.java @@ -116,7 +116,7 @@ public class FunctionCallGraphPluginScreenShots extends GhidraScreenShotGenerato area.width += (2 * offset); area.height += (2 * offset); - // drawRectangle(Color.ORANGE, area, 5); + // drawRectangle(Palette.ORANGE, area, 5); crop(area); } diff --git a/Ghidra/Features/GraphServices/certification.manifest b/Ghidra/Features/GraphServices/certification.manifest index 5e1c86fb2f..60b91eadd8 100644 --- a/Ghidra/Features/GraphServices/certification.manifest +++ b/Ghidra/Features/GraphServices/certification.manifest @@ -8,6 +8,7 @@ ##MODULE IP: Tango Icons - Public Domain Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/graphservices.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||||END| src/main/help/help/shared/note.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| diff --git a/Ghidra/Features/GraphServices/data/graphservices.theme.properties b/Ghidra/Features/GraphServices/data/graphservices.theme.properties new file mode 100644 index 0000000000..8597c26296 --- /dev/null +++ b/Ghidra/Features/GraphServices/data/graphservices.theme.properties @@ -0,0 +1,3 @@ +[Defaults] + +color.bg.graph = color.bg \ No newline at end of file diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/AttributeFilters.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/AttributeFilters.java index 8112de9a9c..5c41fb824f 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/AttributeFilters.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/AttributeFilters.java @@ -30,6 +30,7 @@ import javax.swing.event.EventListenerList; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; +import generic.theme.GThemeDefaults.Colors; import ghidra.service.graph.Attributed; /** @@ -60,8 +61,7 @@ public class AttributeFilters implements ItemSelectable { /** * a {@link Function} to allow custom coloring of the individual toolkit button foreground */ - private Function paintFunction = v -> Color.black; - + private Function paintFunction = v -> Colors.FOREGROUND; /** * @param excluded ignored keys diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java index 21263deb25..ad1dedf0e0 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java @@ -52,6 +52,8 @@ import docking.menu.MultiStateDockingAction; import docking.options.editor.OptionsDialog; import docking.widgets.EventTrigger; import docking.widgets.OptionDialog; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import generic.util.WindowUtilities; import ghidra.framework.options.Options; import ghidra.framework.options.ToolOptions; @@ -78,6 +80,8 @@ public class DefaultGraphDisplay implements GraphDisplay { private static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000); private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000); + private static Color BACKGROUND_COLOR = new GColor("color.bg.graph"); + // layout algorithm categories static final String MIN_CROSS = "Hierarchical MinCross"; static final String VERT_MIN_CROSS = "Vertical Hierarchical MinCross"; @@ -187,8 +191,7 @@ public class DefaultGraphDisplay implements GraphDisplay { if (graphDisplayProvider.getDefaultSatelliteState()) { viewer.getComponent().add(satelliteViewer.getComponent()); } - layoutTransitionManager = - new LayoutTransitionManager(viewer, this::isRoot, graphRenderer); + layoutTransitionManager = new LayoutTransitionManager(viewer, this::isRoot, graphRenderer); viewer.getComponent().addComponentListener(new ComponentAdapter() { @Override @@ -203,9 +206,9 @@ public class DefaultGraphDisplay implements GraphDisplay { } }); - viewer.setInitialDimensionFunction(InitialDimensionFunction - .builder(viewer.getRenderContext().getVertexBoundsFunction()) - .build()); + viewer.setInitialDimensionFunction( + InitialDimensionFunction.builder(viewer.getRenderContext().getVertexBoundsFunction()) + .build()); createToolbarActions(); createPopupActions(); connectSelectionStateListeners(); @@ -260,9 +263,8 @@ public class DefaultGraphDisplay implements GraphDisplay { } }; - MutableTransformer transformer = viewer.getRenderContext() - .getMultiLayerTransformer() - .getTransformer(VIEW); + MutableTransformer transformer = + viewer.getRenderContext().getMultiLayerTransformer().getTransformer(VIEW); MagnifyShapeTransformer shapeTransformer = MagnifyShapeTransformer.builder(lens) // this lens' delegate is the viewer's VIEW layer, abandoned above @@ -283,23 +285,21 @@ public class DefaultGraphDisplay implements GraphDisplay { viewer.removePostRenderPaintable(singleSelectedVertexPaintable); // for highlighting of multiple selected vertices - this.multiSelectedVertexPaintable = - MultiSelectedVertexPaintable.builder(viewer) - .selectionStrokeMin(15.f) - .selectionPaint(getSelectedVertexColor()) - .useBounds(true) - .useOval(true) - .highlightScale(1.15) - .fillHighlight(false) - .build(); + this.multiSelectedVertexPaintable = MultiSelectedVertexPaintable.builder(viewer) + .selectionStrokeMin(15.f) + .selectionPaint(getSelectedVertexColor()) + .useBounds(true) + .useOval(true) + .highlightScale(1.15) + .fillHighlight(false) + .build(); // manages highlight painting of a single selected vertex - this.singleSelectedVertexPaintable = - SingleSelectedVertexPaintable.builder(viewer) - .selectionStrokeMin(4.f) - .selectionPaint(getSelectedVertexColor()) - .selectedVertexFunction(vs -> this.focusedVertex) - .build(); + this.singleSelectedVertexPaintable = SingleSelectedVertexPaintable.builder(viewer) + .selectionStrokeMin(4.f) + .selectionPaint(getSelectedVertexColor()) + .selectedVertexFunction(vs -> this.focusedVertex) + .build(); // draws the selection highlights viewer.addPreRenderPaintable(multiSelectedVertexPaintable); @@ -352,8 +352,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .buildAndInstallLocal(componentProvider); // create an icon button to reset the view transformations to identity (scaled to layout) - new ActionBuilder("Reset View", ACTION_OWNER) - .description("Fit Graph to Window") + new ActionBuilder("Reset View", ACTION_OWNER).description("Fit Graph to Window") .toolBarIcon(DefaultDisplayGraphIcons.FIT_TO_WINDOW) .onAction(context -> centerAndScale()) .buildAndInstallLocal(componentProvider); @@ -363,8 +362,8 @@ public class DefaultGraphDisplay implements GraphDisplay { ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", ACTION_OWNER) .description("Show View Magnifier") .toolBarIcon(DefaultDisplayGraphIcons.VIEW_MAGNIFIER_ICON) - .onAction(context -> magnifyViewSupport.activate( - ((AbstractButton) context.getSourceObject()).isSelected())) + .onAction(context -> magnifyViewSupport + .activate(((AbstractButton) context.getSourceObject()).isSelected())) .build(); magnifyViewSupport.addItemListener( itemEvent -> lensToggle.setSelected(itemEvent.getStateChange() == ItemEvent.SELECTED)); @@ -388,40 +387,35 @@ public class DefaultGraphDisplay implements GraphDisplay { } private void createPopupActions() { - new ActionBuilder("Select Vertex", ACTION_OWNER) - .popupMenuPath("Select Vertex") + new ActionBuilder("Select Vertex", ACTION_OWNER).popupMenuPath("Select Vertex") .popupMenuGroup("selection", "1") .withContext(VertexGraphActionContext.class) .enabledWhen(c -> !isSelected(c.getClickedVertex())) .onAction(c -> viewer.getSelectedVertexState().select(c.getClickedVertex())) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Deselect Vertex", ACTION_OWNER) - .popupMenuPath("Deselect Vertex") + new ActionBuilder("Deselect Vertex", ACTION_OWNER).popupMenuPath("Deselect Vertex") .popupMenuGroup("selection", "2") .withContext(VertexGraphActionContext.class) .enabledWhen(c -> isSelected(c.getClickedVertex())) .onAction(c -> viewer.getSelectedVertexState().deselect(c.getClickedVertex())) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Select Edge", ACTION_OWNER) - .popupMenuPath("Select Edge") + new ActionBuilder("Select Edge", ACTION_OWNER).popupMenuPath("Select Edge") .popupMenuGroup("selection", "1") .withContext(EdgeGraphActionContext.class) .enabledWhen(c -> !isSelected(c.getClickedEdge())) .onAction(c -> selectEdge(c.getClickedEdge())) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Deselect Edge", ACTION_OWNER) - .popupMenuPath("Deselect Edge") + new ActionBuilder("Deselect Edge", ACTION_OWNER).popupMenuPath("Deselect Edge") .popupMenuGroup("selection", "2") .withContext(EdgeGraphActionContext.class) .enabledWhen(c -> isSelected(c.getClickedEdge())) .onAction(c -> deselectEdge(c.getClickedEdge())) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Edge Source", ACTION_OWNER) - .popupMenuPath("Go To Edge Source") + new ActionBuilder("Edge Source", ACTION_OWNER).popupMenuPath("Go To Edge Source") .popupMenuGroup("Go To") .withContext(EdgeGraphActionContext.class) .onAction(c -> { @@ -430,8 +424,7 @@ public class DefaultGraphDisplay implements GraphDisplay { }) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Edge Target", ACTION_OWNER) - .popupMenuPath("Go To Edge Target") + new ActionBuilder("Edge Target", ACTION_OWNER).popupMenuPath("Go To Edge Target") .popupMenuGroup("Go To") .withContext(EdgeGraphActionContext.class) .onAction(c -> { @@ -440,12 +433,12 @@ public class DefaultGraphDisplay implements GraphDisplay { }) .buildAndInstallLocal(componentProvider); - hideSelectedAction = new ToggleActionBuilder("Hide Selected", ACTION_OWNER) - .popupMenuPath("Hide Selected") - .popupMenuGroup("z", "1") - .description("Toggles whether or not to show selected vertices and edges") - .onAction(c -> manageVertexDisplay()) - .buildAndInstallLocal(componentProvider); + hideSelectedAction = + new ToggleActionBuilder("Hide Selected", ACTION_OWNER).popupMenuPath("Hide Selected") + .popupMenuGroup("z", "1") + .description("Toggles whether or not to show selected vertices and edges") + .onAction(c -> manageVertexDisplay()) + .buildAndInstallLocal(componentProvider); hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", ACTION_OWNER) .popupMenuPath("Hide Unselected") @@ -454,8 +447,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .onAction(c -> manageVertexDisplay()) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Invert Selection", ACTION_OWNER) - .popupMenuPath("Invert Selection") + new ActionBuilder("Invert Selection", ACTION_OWNER).popupMenuPath("Invert Selection") .popupMenuGroup("z", "3") .description("Inverts the current selection") .onAction(c -> invertSelection()) @@ -493,8 +485,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .onAction(c -> growSelection(getAllComponentVerticesFromSelected())) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Clear Selection", ACTION_OWNER) - .popupMenuPath("Clear Selection") + new ActionBuilder("Clear Selection", ACTION_OWNER).popupMenuPath("Clear Selection") .popupMenuGroup("z", "5") .keyBinding("escape") .enabledWhen(c -> hasSelection()) @@ -516,8 +507,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .onAction(c -> groupSelectedVertices()) .buildAndInstallLocal(componentProvider); - new ActionBuilder("Expand Selected", ACTION_OWNER) - .popupMenuPath("Expand Selected Vertices") + new ActionBuilder("Expand Selected", ACTION_OWNER).popupMenuPath("Expand Selected Vertices") .popupMenuGroup("zz", "6") .description("Expands all selected collapsed vertices into their previous form") .onAction(c -> ungroupSelectedVertices()) @@ -579,8 +569,8 @@ public class DefaultGraphDisplay implements GraphDisplay { private void askToNameGroupVertex(AttributedVertex vertex) { String name = vertex.getName(); - String userName = OptionDialog.showInputMultilineDialog(null, "Enter Group Vertex Text", - "Text", name); + String userName = + OptionDialog.showInputMultilineDialog(null, "Enter Group Vertex Text", "Text", name); updateVertexName(vertex, userName != null ? userName : name); } @@ -602,8 +592,7 @@ public class DefaultGraphDisplay implements GraphDisplay { } private boolean hasSelection() { - return !(viewer.getSelectedVertices().isEmpty() && - viewer.getSelectedEdges().isEmpty()); + return !(viewer.getSelectedVertices().isEmpty() && viewer.getSelectedEdges().isEmpty()); } private boolean isSelected(AttributedVertex v) { @@ -648,15 +637,11 @@ public class DefaultGraphDisplay implements GraphDisplay { // select all the edges that connect the supplied vertices private void selectEdgesConnecting(Collection vertices) { - Set edges = graph.edgeSet() - .stream() - .filter( - e -> { - AttributedVertex source = graph.getEdgeSource(e); - AttributedVertex target = graph.getEdgeTarget(e); - return vertices.contains(source) && vertices.contains(target); - }) - .collect(Collectors.toSet()); + Set edges = graph.edgeSet().stream().filter(e -> { + AttributedVertex source = graph.getEdgeSource(e); + AttributedVertex target = graph.getEdgeTarget(e); + return vertices.contains(source) && vertices.contains(target); + }).collect(Collectors.toSet()); viewer.getSelectedEdgeState().select(edges); } @@ -813,12 +798,9 @@ public class DefaultGraphDisplay implements GraphDisplay { private SatelliteVisualizationViewer createSatelliteViewer( VisualizationViewer parentViewer) { Dimension viewerSize = parentViewer.getSize(); - Dimension satelliteSize = new Dimension( - viewerSize.width / 4, viewerSize.height / 4); + Dimension satelliteSize = new Dimension(viewerSize.width / 4, viewerSize.height / 4); final SatelliteVisualizationViewer satellite = - SatelliteVisualizationViewer.builder(parentViewer) - .viewSize(satelliteSize) - .build(); + SatelliteVisualizationViewer.builder(parentViewer).viewSize(satelliteSize).build(); // // JUNGRAPHT CHANGE 3 @@ -1044,7 +1026,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .elements(vertices) .maxFactor(.05) .buttonSupplier(JRadioButton::new) - .paintFunction(v -> Color.BLACK) + .paintFunction(v -> Colors.FOREGROUND) .build(); vertexFilters.addItemListener(item -> { @@ -1062,7 +1044,7 @@ public class DefaultGraphDisplay implements GraphDisplay { .elements(edges) .maxFactor(.01) .buttonSupplier(JRadioButton::new) - .paintFunction(e -> Color.BLACK) + .paintFunction(e -> Colors.FOREGROUND) .build(); edgeFilters.addItemListener(item -> { @@ -1124,10 +1106,8 @@ public class DefaultGraphDisplay implements GraphDisplay { componentProvider.setTitle(title); int count = graph.getVertexCount(); if (count > options.getMaxNodeCount()) { - Msg.showWarn(this, null, "Graph Not Rendered - Too many nodes!", - "Exceeded limit of " + options.getMaxNodeCount() + " nodes.\n\n Graph contained " + - count + - " nodes!"); + Msg.showWarn(this, null, "Graph Not Rendered - Too many nodes!", "Exceeded limit of " + + options.getMaxNodeCount() + " nodes.\n\n Graph contained " + count + " nodes!"); graph = new AttributedGraph("Aborted", graph.getGraphType(), "Too Many Nodes"); graph.addVertex("1", "Graph Aborted"); } @@ -1293,7 +1273,7 @@ public class DefaultGraphDisplay implements GraphDisplay { graphRenderer.initializeViewer(vv); vv.getComponent().requestFocus(); - vv.setBackground(Color.WHITE); + vv.setBackground(BACKGROUND_COLOR); MouseListener[] mouseListeners = vv.getComponent().getMouseListeners(); for (MouseListener mouseListener : mouseListeners) { vv.getComponent().removeMouseListener(mouseListener); @@ -1334,8 +1314,8 @@ public class DefaultGraphDisplay implements GraphDisplay { public void addAction(DockingActionIf action) { if (containsAction(action)) { - Msg.warn(this, "Action with same name and owner already exixts in graph: " + - action.getFullName()); + Msg.warn(this, + "Action with same name and owner already exixts in graph: " + action.getFullName()); return; } @@ -1387,20 +1367,17 @@ public class DefaultGraphDisplay implements GraphDisplay { MutableSelectedState selectedVertexState = viewer.getSelectedVertexState(); if (hideSelected && hideUnselected) { - viewer.getRenderContext() - .setVertexIncludePredicate(v -> false); + viewer.getRenderContext().setVertexIncludePredicate(v -> false); } else if (hideSelected) { viewer.getRenderContext() .setVertexIncludePredicate(Predicate.not(selectedVertexState::isSelected)); } else if (hideUnselected) { - viewer.getRenderContext() - .setVertexIncludePredicate(selectedVertexState::isSelected); + viewer.getRenderContext().setVertexIncludePredicate(selectedVertexState::isSelected); } else { - viewer.getRenderContext() - .setVertexIncludePredicate(v -> true); + viewer.getRenderContext().setVertexIncludePredicate(v -> true); } viewer.repaint(); } @@ -1467,8 +1444,7 @@ public class DefaultGraphDisplay implements GraphDisplay { @Override public AttributedVertex getVertex(MouseEvent event) { - LayoutModel layoutModel = - vv.getVisualizationModel().getLayoutModel(); + LayoutModel layoutModel = vv.getVisualizationModel().getLayoutModel(); Point2D p = vv.getTransformSupport().inverseTransform(vv, event.getPoint()); AttributedVertex vertex = vv.getPickSupport().getVertex(layoutModel, p.getX(), p.getY()); @@ -1477,8 +1453,7 @@ public class DefaultGraphDisplay implements GraphDisplay { @Override public AttributedEdge getEdge(MouseEvent event) { - LayoutModel layoutModel = - vv.getVisualizationModel().getLayoutModel(); + LayoutModel layoutModel = vv.getVisualizationModel().getLayoutModel(); Point2D p = vv.getTransformSupport().inverseTransform(vv, event.getPoint()); AttributedEdge edge = vv.getPickSupport().getEdge(layoutModel, p.getX(), p.getY()); return edge; diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java index a4bf465f4b..5cee638e1d 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java @@ -37,6 +37,7 @@ import org.jungrapht.visualization.renderers.Renderer; import org.jungrapht.visualization.renderers.Renderer.VertexLabel.Position; import org.jungrapht.visualization.util.RectangleUtils; +import generic.theme.GThemeDefaults.Colors; import generic.util.image.ImageUtils; import ghidra.service.graph.*; import ghidra.util.HTMLUtilities; @@ -78,8 +79,8 @@ public class DefaultGraphRenderer implements GraphRenderer { this.options = options; renderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); label = new JLabel(); - label.setForeground(Color.black); - label.setBackground(Color.white); + label.setForeground(Colors.FOREGROUND); + label.setBackground(Colors.BACKGROUND); label.setOpaque(false); Border marginBorder = BorderFactory.createEmptyBorder(labelBorderSize, 2 * labelBorderSize, labelBorderSize, 2 * labelBorderSize); @@ -163,7 +164,7 @@ public class DefaultGraphRenderer implements GraphRenderer { } renderContext.setVertexFontFunction(this::getFont); - renderContext.setVertexLabelRenderer(new JLabelVertexLabelRenderer(Color.black)); + renderContext.setVertexLabelRenderer(new JLabelVertexLabelRenderer(Colors.FOREGROUND)); renderContext.setVertexDrawPaintFunction(this::getVertexColor); renderContext.setVertexFillPaintFunction(this::getVertexColor); renderContext.setVertexStrokeFunction(n -> new BasicStroke(3.0f)); @@ -290,7 +291,7 @@ public class DefaultGraphRenderer implements GraphRenderer { // shapes are centered at the origin, so translate the graphics to compensate graphics.translate(-bounds.x + strokeThickness, -bounds.y + strokeThickness); - graphics.setPaint(Color.WHITE); + graphics.setPaint(Colors.BACKGROUND); graphics.fill(scaledShape); graphics.setPaint(vertexColor); graphics.setStroke(new BasicStroke(strokeThickness)); @@ -304,7 +305,7 @@ public class DefaultGraphRenderer implements GraphRenderer { int yOffset = (int) ((iconHeight - label.getHeight()) * labelOffsetRatio); graphics.translate(xOffset, yOffset); - graphics.setPaint(Color.black); + graphics.setPaint(Colors.FOREGROUND); label.paint(graphics); graphics.setTransform(graphicsTransform); // restore the original transform diff --git a/Ghidra/Features/PDB/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/PDB/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/PDB/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/PDB/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java index 92db3e6e08..2052a80b00 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/LoadPdbDialog.java @@ -41,6 +41,9 @@ import docking.widgets.label.GIconLabel; import docking.widgets.label.GLabel; import docking.widgets.textfield.HexOrDecimalInput; import docking.widgets.textfield.HintTextField; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.util.bin.format.pdb.PdbParser; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbIdentifiers; import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorControl; @@ -56,7 +59,6 @@ import ghidra.util.task.*; import pdb.PdbPlugin; import pdb.symbolserver.*; import resources.Icons; -import resources.ResourceManager; /** * A dialog that allows the user to pick or search for a Pdb file for a program. @@ -64,10 +66,8 @@ import resources.ResourceManager; public class LoadPdbDialog extends DialogComponentProvider { private static final String LAST_PDBFILE_PREFERENCE_KEY = "Pdb.LastFile"; - static final Icon MATCH_OK_ICON = - ResourceManager.loadImage("images/checkmark_green.gif", 16, 16); - static final Icon MATCH_BAD_ICON = - ResourceManager.loadImage("images/emblem-important.png", 16, 16); + static final Icon MATCH_OK_ICON = new GIcon("icon.checkmark.green"); + static final Icon MATCH_BAD_ICON = Icons.ERROR_ICON; public static final GhidraFileFilter PDB_FILES_FILTER = ExtensionFileFilter.forExtensions("Microsoft Program Databases", "pdb", "pd_", "pdb.xml"); @@ -172,7 +172,7 @@ public class LoadPdbDialog extends DialogComponentProvider { protected void dialogShown() { cancelButton.requestFocusInWindow(); - if ( getCurrentSymbolFileInfo() != null ) { + if (getCurrentSymbolFileInfo() != null) { searchForPdbs(false); } } @@ -377,7 +377,7 @@ public class LoadPdbDialog extends DialogComponentProvider { programNameTextField.setEditable(false); programNameTextField.setText(program.getName()); - pdbPathTextField = new BetterNonEditableTextField(20, "Missing", Color.red); + pdbPathTextField = new BetterNonEditableTextField(20, "Missing", Colors.ERROR); pdbPathTextField.setEditable(false); pdbPathTextField.setText(programSymbolFileInfo.getPath()); pdbPathTextField.getDocument().addDocumentListener(docListener); @@ -399,7 +399,7 @@ public class LoadPdbDialog extends DialogComponentProvider { new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, SymbolFilePanel.SEARCH_OPTIONS_HELP_ANCHOR)); - pdbUniqueIdTextField = new BetterNonEditableTextField(36, "Missing", Color.red); + pdbUniqueIdTextField = new BetterNonEditableTextField(36, "Missing", Colors.ERROR); pdbUniqueIdTextField.setEditable(false); pdbUniqueIdTextField.setText(programSymbolFileInfo.getUniqifierString()); pdbUniqueIdTextField.setToolTipText( @@ -889,10 +889,9 @@ public class LoadPdbDialog extends DialogComponentProvider { Container parent = getParent(); if (parent != null && !isEditable()) { Color bg = parent.getBackground(); - // mint a new Color object to avoid it being - // ignored because the parent handed us a DerivedColor - // instance - return new Color(bg.getRGB()); + // mint a new Color object to avoid it being ignored because the parent handed us a + // DerivedColor instance + return ColorUtils.getColor(bg.getRGB()); } return super.getBackground(); } @@ -909,7 +908,7 @@ public class LoadPdbDialog extends DialogComponentProvider { } Graphics2D g2 = (Graphics2D) g; - g2.setColor(hintColor != null ? hintColor : Color.LIGHT_GRAY); + g2.setColor(hintColor != null ? hintColor : Messages.HINT); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Dimension size = getSize(); @@ -931,10 +930,9 @@ public class LoadPdbDialog extends DialogComponentProvider { Container parent = getParent(); if (parent != null && !isEditable()) { Color bg = parent.getBackground(); - // mint a new Color object to avoid it being - // ignored because the parent handed us a DerivedColor - // instance - return new Color(bg.getRGB()); + // mint a new Color object to avoid it being ignored because the parent handed us a + // DerivedColor instance + return ColorUtils.getColor(bg.getRGB()); } return super.getBackground(); } diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java index c060524041..559065001e 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolFilePanel.java @@ -27,6 +27,7 @@ import docking.DockingWindowManager; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GHtmlLabel; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors; import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTable; import pdb.PdbPlugin; @@ -40,6 +41,7 @@ class SymbolFilePanel extends JPanel { interface SearchCallback { void searchForPdbs(boolean allowRemote); } + static final String SEARCH_OPTIONS_HELP_ANCHOR = "PDB_Search_Search_Options"; private SymbolFileTableModel tableModel; private GhidraTable table; @@ -117,7 +119,8 @@ class SymbolFilePanel extends JPanel { private JPanel buildWelcomePanel() { welcomePanel = new JPanel(); welcomePanel.add(new GHtmlLabel( - "

Configuration must be set first!")); + "
Configuration must be set first!")); welcomePanel.setPreferredSize(tablePanel.getPreferredSize()); return welcomePanel; diff --git a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java index 423f6e0325..712a6340e1 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/symbolserver/ui/SymbolServerPanel.java @@ -36,6 +36,7 @@ import docking.widgets.label.GHtmlLabel; import docking.widgets.label.GLabel; import docking.widgets.table.GTable; import docking.widgets.textfield.HintTextField; +import generic.theme.GThemeDefaults.Colors; import ghidra.framework.preferences.Preferences; import ghidra.util.*; import ghidra.util.layout.PairLayout; @@ -107,13 +108,11 @@ class SymbolServerPanel extends JPanel { JPanel buttonPanel = buildButtonPanel(); JScrollPane tableScrollPane = buildTable(); defaultConfigNotice = new JPanel(); - defaultConfigNotice.add( - new GHtmlLabel( - "

" + - "Missing / invalid configuration.

" + - "Using default search location:
" + - "Program's Import Location
", - SwingConstants.CENTER)); + defaultConfigNotice.add(new GHtmlLabel( + "

" + "Missing / invalid configuration.

" + + "Using default search location:
" + "Program's Import Location
", + SwingConstants.CENTER)); defaultConfigNotice.setPreferredSize(tableScrollPane.getPreferredSize()); additionalSearchLocationsPanel = new JPanel(); @@ -199,55 +198,47 @@ class SymbolServerPanel extends JPanel { } private JPanel buildButtonPanel() { - refreshSearchLocationsStatusButton = createImageButton(Icons.REFRESH_ICON, "Refresh Status", - ButtonPanelFactory.ARROW_SIZE); + refreshSearchLocationsStatusButton = + createImageButton(Icons.REFRESH_ICON, "Refresh Status", ButtonPanelFactory.ARROW_SIZE); refreshSearchLocationsStatusButton.addActionListener(e -> refreshSearchLocationStatus()); DockingWindowManager.getHelpService() - .registerHelp(refreshSearchLocationsStatusButton, - new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, - "SymbolServerConfig Refresh Status")); + .registerHelp(refreshSearchLocationsStatusButton, new HelpLocation( + PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Refresh Status")); moveLocationUpButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_UP_TYPE); moveLocationUpButton.addActionListener(e -> moveLocation(-1)); moveLocationUpButton.setToolTipText("Move location up"); DockingWindowManager.getHelpService() - .registerHelp(moveLocationUpButton, - new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, - "SymbolServerConfig MoveUpDown")); + .registerHelp(moveLocationUpButton, new HelpLocation( + PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig MoveUpDown")); moveLocationDownButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_DOWN_TYPE); moveLocationDownButton.addActionListener(e -> moveLocation(1)); moveLocationDownButton.setToolTipText("Move location down"); DockingWindowManager.getHelpService() - .registerHelp(moveLocationDownButton, - new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, - "SymbolServerConfig MoveUpDown")); + .registerHelp(moveLocationDownButton, new HelpLocation( + PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig MoveUpDown")); - deleteLocationButton = createImageButton(Icons.DELETE_ICON, "Delete", - ButtonPanelFactory.ARROW_SIZE); + deleteLocationButton = + createImageButton(Icons.DELETE_ICON, "Delete", ButtonPanelFactory.ARROW_SIZE); deleteLocationButton.addActionListener(e -> deleteLocation()); DockingWindowManager.getHelpService() .registerHelp(deleteLocationButton, - new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, - "SymbolServerConfig Delete")); + new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Delete")); - addLocationButton = createImageButton(Icons.ADD_ICON, "Add", - ButtonPanelFactory.ARROW_SIZE); + addLocationButton = createImageButton(Icons.ADD_ICON, "Add", ButtonPanelFactory.ARROW_SIZE); addLocationButton.addActionListener(e -> addLocation()); DockingWindowManager.getHelpService() .registerHelp(addLocationButton, - new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, - "SymbolServerConfig Add")); + new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Add")); - saveSearchLocationsButton = - ButtonPanelFactory.createImageButton(Icons.get("images/disk.png"), - "Save Configuration", ButtonPanelFactory.ARROW_SIZE); + saveSearchLocationsButton = ButtonPanelFactory.createImageButton( + Icons.get("images/disk.png"), "Save Configuration", ButtonPanelFactory.ARROW_SIZE); saveSearchLocationsButton.addActionListener(e -> saveConfig()); DockingWindowManager.getHelpService() .registerHelp(saveSearchLocationsButton, - new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, - "SymbolServerConfig Save")); + new HelpLocation(PdbPlugin.PDB_PLUGIN_HELP_TOPIC, "SymbolServerConfig Save")); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); @@ -325,8 +316,7 @@ class SymbolServerPanel extends JPanel { } if (allowGUIPrompt && isEmptyDirectory(symbolStorageDir)) { - if (OptionDialog.showYesNoDialog(this, - "Initialize Symbol Storage Directory?", + if (OptionDialog.showYesNoDialog(this, "Initialize Symbol Storage Directory?", "Initialize new directory as Microsoft symbol storage directory?") == OptionDialog.YES_OPTION) { try { LocalSymbolStore.create(symbolStorageDir, @@ -407,8 +397,8 @@ class SymbolServerPanel extends JPanel { String[] envParts = envString.split("[*;]"); List results = new ArrayList<>(); Set locationStringDeduplicationSet = new HashSet<>(); - for (int i = 0; i < envParts.length; i++) { - String locationString = envParts[i].trim(); + for (String envPart : envParts) { + String locationString = envPart.trim(); if (!locationString.isBlank() && !locationString.equalsIgnoreCase("srv") && !locationStringDeduplicationSet.contains(locationString)) { results.add(locationString); @@ -495,8 +485,8 @@ class SymbolServerPanel extends JPanel { } private void addDirectoryLocation() { - File dir = FilePromptDialog.chooseDirectory("Enter Path", "Symbol Storage Location: ", - null); + File dir = + FilePromptDialog.chooseDirectory("Enter Path", "Symbol Storage Location: ", null); if (dir == null) { return; } @@ -574,7 +564,7 @@ class SymbolServerPanel extends JPanel { return false; } - private static JButton createImageButton(ImageIcon buttonIcon, String alternateText, + private static JButton createImageButton(Icon buttonIcon, String alternateText, Dimension preferredSize) { JButton button = ButtonPanelFactory.createButton(""); @@ -584,7 +574,7 @@ class SymbolServerPanel extends JPanel { return button; } - + static StatusText getSymbolServerWarnings(List symbolServers) { Map warningsByLocation = new HashMap<>(); for (WellKnownSymbolServerLocation ssloc : knownSymbolServers) { @@ -592,8 +582,7 @@ class SymbolServerPanel extends JPanel { warningsByLocation.put(ssloc.getLocation(), ssloc.getWarning()); } } - String warning = symbolServers - .stream() + String warning = symbolServers.stream() .map(symbolServer -> warningsByLocation.get(symbolServer.getName())) .filter(Objects::nonNull) .distinct() diff --git a/Ghidra/Features/ProgramDiff/certification.manifest b/Ghidra/Features/ProgramDiff/certification.manifest index 94046642d7..cc80bd6c37 100644 --- a/Ghidra/Features/ProgramDiff/certification.manifest +++ b/Ghidra/Features/ProgramDiff/certification.manifest @@ -6,6 +6,7 @@ ##MODULE IP: Oxygen Icons - LGPL 3.0 ##MODULE IP: Tango Icons - Public Domain Module.manifest||GHIDRA||||END| +data/programdiff.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||reviewed||END| src/main/help/help/shared/close16.gif||GHIDRA||reviewed||END| diff --git a/Ghidra/Features/ProgramDiff/data/programdiff.theme.properties b/Ghidra/Features/ProgramDiff/data/programdiff.theme.properties new file mode 100644 index 0000000000..26beada9ae --- /dev/null +++ b/Ghidra/Features/ProgramDiff/data/programdiff.theme.properties @@ -0,0 +1,16 @@ +[Defaults] + +color.bg.programdiff.highlight = moccasin + +icon.plugin.programdiff.apply = pencil16.png +icon.plugin.programdiff.apply.next = pencil_arrow16.png +icon.plugin.programdiff.ignore = eraser_arrow16.png +icon.plugin.programdiff.get.diffs = Diff16.png +icon.plugin.programdiff.select.by.program = DiffSelect16.png +icon.plugin.programdiff.open.close.program = table_relationship.png +icon.plugin.programdiff.settings = settings16.gif +icon.plugin.programdiff.cursor.location = cursor_arrow.gif + +[Dark Defaults] + +color.bg.programdiff.highlight = darkRed diff --git a/Ghidra/Features/ProgramDiff/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/ProgramDiff/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/ProgramDiff/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/ProgramDiff/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffActionManager.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffActionManager.java index 63c481b60b..3d96eb7732 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffActionManager.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffActionManager.java @@ -18,19 +18,20 @@ package ghidra.app.plugin.core.diff; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; import docking.widgets.OptionDialog; +import generic.theme.GIcon; import ghidra.app.plugin.core.codebrowser.OtherPanelContext; import ghidra.app.services.CodeViewerService; import ghidra.app.util.HelpTopics; import ghidra.program.model.listing.Program; import ghidra.util.HTMLUtilities; import ghidra.util.HelpLocation; -import resources.ResourceManager; +import resources.Icons; /** * Creates the actions for the program diff plugin. @@ -41,7 +42,6 @@ class DiffActionManager { private static final String GET_DIFF_GROUP = "GetDiff"; private static final String DIFF_INFO_GROUP = "DiffInfo"; private static final String DIFF_NAVIGATE_GROUP = "DiffNavigate"; - private static final String TOGGLE_VIEW_ICON_NAME = "images/table_relationship.png"; private static final String GROUP = "Diff"; private ProgramDiffPlugin plugin; private CodeViewerService codeViewerService; @@ -251,7 +251,7 @@ class DiffActionManager { plugin.applyDiff(); } }; - ImageIcon icon = ResourceManager.loadImage("images/pencil16.png"); + Icon icon = new GIcon("icon.plugin.programdiff.apply"); applyDiffsAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_F3, 0)); applyDiffsAction.setPopupMenuData( new MenuData(new String[] { "Apply Selection" }, icon, GROUP)); @@ -265,7 +265,7 @@ class DiffActionManager { plugin.applyDiffAndGoNext(); } }; - icon = ResourceManager.loadImage("images/pencil_arrow16.png"); + icon = new GIcon("icon.plugin.programdiff.apply.next"); String[] applyDiffsPath = { "Apply Selection and Goto Next Difference" }; applyDiffsNextAction.setPopupMenuData(new MenuData(applyDiffsPath, icon, GROUP)); applyDiffsNextAction.setKeyBindingData( @@ -281,7 +281,7 @@ class DiffActionManager { plugin.ignoreDiff(); } }; - icon = ResourceManager.loadImage("images/eraser_arrow16.png"); + icon = new GIcon("icon.plugin.programdiff.ignore"); ignoreDiffsAction.setPopupMenuData(new MenuData( new String[] { "Ignore Selection and Goto Next Difference" }, icon, GROUP)); ignoreDiffsAction.setDescription( @@ -294,9 +294,9 @@ class DiffActionManager { plugin.nextDiff(); } }; - icon = ResourceManager.loadImage("images/down.png"); + icon = Icons.DOWN_ICON; nextDiffAction.setKeyBindingData( - new KeyBindingData('N', InputEvent.CTRL_MASK | InputEvent.ALT_MASK)); + new KeyBindingData('N', InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK)); nextDiffAction.setPopupMenuData( new MenuData(new String[] { "Next Difference" }, icon, DIFF_NAVIGATE_GROUP)); nextDiffAction.setToolBarData(new ToolBarData(icon, DIFF_NAVIGATE_GROUP)); @@ -308,9 +308,9 @@ class DiffActionManager { plugin.previousDiff(); } }; - icon = ResourceManager.loadImage("images/up.png"); + icon = Icons.UP_ICON; previousDiffAction.setKeyBindingData( - new KeyBindingData('P', InputEvent.CTRL_MASK | InputEvent.ALT_MASK)); + new KeyBindingData('P', InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK)); previousDiffAction.setPopupMenuData( new MenuData(new String[] { "Previous Difference" }, icon, DIFF_NAVIGATE_GROUP)); previousDiffAction.setToolBarData(new ToolBarData(icon, DIFF_NAVIGATE_GROUP)); @@ -322,7 +322,7 @@ class DiffActionManager { plugin.showDiffDetails(); } }; - icon = ResourceManager.loadImage("images/xmag.png"); + icon = new GIcon("icon.search"); diffDetailsAction.setKeyBindingData(new KeyBindingData(KeyEvent.VK_F5, 0)); diffDetailsAction.setPopupMenuData( new MenuData(new String[] { "Location Details..." }, icon, DIFF_INFO_GROUP)); @@ -349,7 +349,7 @@ class DiffActionManager { plugin.diff(); } }; - icon = ResourceManager.loadImage("images/Diff16.png"); + icon = new GIcon("icon.plugin.programdiff.get.diffs"); getDiffsAction.setPopupMenuData( new MenuData(new String[] { "Get Differences..." }, icon, GET_DIFF_GROUP)); getDiffsAction.setToolBarData(new ToolBarData(icon, GET_DIFF_GROUP)); @@ -372,7 +372,7 @@ class DiffActionManager { plugin.setP1SelectionOnP2(); } }; - icon = ResourceManager.loadImage("images/DiffSelect16.png"); + icon = new GIcon("icon.plugin.programdiff.select.by.program"); p1SelectToP2Action.setDescription( "Select Program 2 highlights using selection in Program 1."); p1SelectToP2Action.setToolBarData(new ToolBarData(icon, SELECT_GROUP)); @@ -434,10 +434,10 @@ class DiffActionManager { return true; } }; - icon = ResourceManager.loadImage(TOGGLE_VIEW_ICON_NAME); + icon = new GIcon("icon.plugin.programdiff.open.close.program"); openCloseProgram2Action.setEnabled(false); openCloseProgram2Action.setKeyBindingData( - new KeyBindingData('C', InputEvent.CTRL_MASK | InputEvent.ALT_MASK)); + new KeyBindingData('C', InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK)); openCloseProgram2Action.setToolBarData(new ToolBarData(icon, "zzz")); openCloseProgram2Action.setHelpLocation( new HelpLocation(HelpTopics.DIFF, OPEN_CLOSE_PROGRAM2_ACTION)); diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffApplySettingsProvider.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffApplySettingsProvider.java index dd6ec26035..510009c51d 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffApplySettingsProvider.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffApplySettingsProvider.java @@ -28,12 +28,12 @@ import docking.WindowPosition; import docking.widgets.VariableHeightPanel; import docking.widgets.combobox.GComboBox; import docking.widgets.label.GDLabel; +import generic.theme.GIcon; import ghidra.app.plugin.core.diff.DiffApplySettingsOptionManager.*; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.Plugin; import ghidra.program.util.ProgramMergeFilter; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * The DiffSettingsDialog is used to change the types of differences currently @@ -43,7 +43,7 @@ import resources.ResourceManager; public class DiffApplySettingsProvider extends ComponentProviderAdapter { public static final String APPLY_FILTER_CHANGED_ACTION = "Apply Filter Changed"; - public static final ImageIcon ICON = ResourceManager.loadImage("images/settings16.gif"); + public static final Icon ICON = new GIcon("icon.plugin.programdiff.settings"); public static final String TITLE = "Diff Apply Settings"; private ProgramDiffPlugin plugin; @@ -106,8 +106,9 @@ public class DiffApplySettingsProvider extends ComponentProviderAdapter { } public void addActions() { - plugin.getTool().addLocalAction(this, - new SaveApplySettingsAction(this, plugin.applySettingsMgr)); + plugin.getTool() + .addLocalAction(this, + new SaveApplySettingsAction(this, plugin.applySettingsMgr)); plugin.getTool().addLocalAction(this, new DiffIgnoreAllAction(this)); plugin.getTool().addLocalAction(this, new DiffReplaceAllAction(this)); plugin.getTool().addLocalAction(this, new DiffMergeAllAction(this)); @@ -351,10 +352,6 @@ public class DiffApplySettingsProvider extends ComponentProviderAdapter { listenerList.remove(listener); } - /** - * Return true if at least one of the checkboxes for the filter - * has been selected. - */ boolean hasApplySelection() { return ((applyProgramContext | applyBytes | applyCodeUnits | applyReferences | applyPlateComments | applyPreComments | applyEolComments | applyRepeatableComments | @@ -366,8 +363,7 @@ public class DiffApplySettingsProvider extends ComponentProviderAdapter { if (adjustingApplyFilter) { return; } - for (int i = 0; i < listenerList.size(); i++) { - ActionListener listener = listenerList.get(i); + for (ActionListener listener : listenerList) { listener.actionPerformed(new ActionEvent(this, 0, APPLY_FILTER_CHANGED_ACTION)); } } @@ -383,9 +379,6 @@ public class DiffApplySettingsProvider extends ComponentProviderAdapter { return applyPanel; } - /** - * Gets the plugin associated with this provider. - */ Plugin getPlugin() { return plugin; } diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffDetailsProvider.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffDetailsProvider.java index 4450d1687f..8042e9a026 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffDetailsProvider.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffDetailsProvider.java @@ -29,6 +29,9 @@ import docking.WindowPosition; import docking.action.DockingAction; import docking.action.ToolBarData; import docking.widgets.checkbox.GCheckBox; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Ids.Fonts; +import generic.theme.Gui; import ghidra.app.util.HelpTopics; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.Plugin; @@ -40,7 +43,6 @@ import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.task.SwingUpdateManager; import resources.Icons; -import resources.ResourceManager; /** * The DiffDetailsProvider is used to view the differences for an address or @@ -52,8 +54,8 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { public static final String FILTER_DIFFS_CHECK_BOX = "Filter Diffs Check Box"; public static final String DIFF_DETAILS_TEXT_AREA = "Diff Details Text Area"; public static final String DIFF_DETAILS_PANEL = "Diff Location Details Panel"; - public static final ImageIcon ICON = ResourceManager.loadImage("images/xmag.png"); - public static final ImageIcon REFRESH_ICON = Icons.REFRESH_ICON; + public static final Icon ICON = new GIcon("icon.search"); + public static final Icon REFRESH_ICON = Icons.REFRESH_ICON; public static final String TITLE = "Diff Details"; private ProgramDiffPlugin plugin; @@ -72,9 +74,6 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { private SwingUpdateManager updateManager; private ProgramLocation currentLocation; - /** - * @param plugin - */ public DiffDetailsProvider(ProgramDiffPlugin plugin) { super(plugin.getTool(), "Diff Location Details", plugin.getName()); setTitle(TITLE); @@ -91,17 +90,11 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { setUpRefreshDetailsUpdateManager(); } - /** - * @param selected - */ public void setAutoUpdate(boolean selected) { autoUpdateCB.setSelected(selected); autoUpdate = selected; } - /** - * @param selected - */ public void setFilterDiffs(boolean selected) { filterDiffsCB.setSelected(selected); filterDiffs = selected; @@ -121,8 +114,8 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { refreshDetailsAction.setEnabled(true); refreshDetailsAction.setToolBarData(new ToolBarData(REFRESH_ICON, "Diff")); - refreshDetailsAction.setHelpLocation( - new HelpLocation(HelpTopics.DIFF, "Refresh Diff Details")); + refreshDetailsAction + .setHelpLocation(new HelpLocation(HelpTopics.DIFF, "Refresh Diff Details")); plugin.getTool().addLocalAction(this, refreshDetailsAction); // plugin.getTool().addLocalAction(this, new DiffIgnoreAllAction(this)); } @@ -159,9 +152,6 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { } - /** - * @param p1Location - */ protected void locationChanged(ProgramLocation p1Location) { if (isDisplayed && autoUpdate) { refreshDetails(p1Location); @@ -300,13 +290,12 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { } private JScrollPane createDetailsPane() { - Font font = new Font("Monospaced", Font.PLAIN, 12); textPane = new JTextPane(); doc = textPane.getStyledDocument(); textPane.setName(DIFF_DETAILS_TEXT_AREA); textPane.setEditable(false); textPane.setMargin(new Insets(5, 5, 5, 5)); - textPane.setFont(font); + Gui.registerFont(textPane, Fonts.MONOSPACED); textPane.setOpaque(true); textPane.setCaretPosition(0); JScrollPane scrolledDetails = new JScrollPane(textPane); @@ -321,8 +310,7 @@ public class DiffDetailsProvider extends ComponentProviderAdapter { @Override public void componentHidden() { - for (int i = 0; i < listenerList.size(); i++) { - ActionListener listener = listenerList.get(i); + for (ActionListener listener : listenerList) { listener.actionPerformed(new ActionEvent(this, 0, DIFF_DETAILS_HIDDEN_ACTION)); } isDisplayed = false; diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java index 77fc090912..770f47d818 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java @@ -32,6 +32,8 @@ import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.listener.FieldMouseListener; import docking.widgets.fieldpanel.support.FieldLocation; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.CorePluginPackage; import ghidra.app.events.*; @@ -62,7 +64,6 @@ import ghidra.util.exception.VersionException; import ghidra.util.task.*; import help.Help; import help.HelpService; -import resources.ResourceManager; /** * Plugin that shows the differences between two programs, and allows the user to apply differences @@ -91,12 +92,13 @@ public class ProgramDiffPlugin extends ProgramPlugin implements ProgramLocationListener, ProgramSelectionListener, DiffControllerListener, DiffService, OptionsChangeListener, DomainObjectListener { - private ImageIcon CURSOR_LOC_ICON = ResourceManager.loadImage("images/cursor_arrow.gif"); + private static final Icon CURSOR_LOC_ICON = + new GIcon("icon.plugin.programdiff.cursor.location"); private static final String SELECTION_GROUP = "Selection Colors"; private static final String DIFF_HIGHLIGHT_COLOR_NAME = SELECTION_GROUP + Options.DELIMITER + "Difference Color"; - private Color diffHighlightColor = new Color(255, 230, 180); // light orange - private Color cursorHighlightColor; + private GColor diffHighlightColor = new GColor("color.bg.programdiff.highlight"); + private Color cursorHighlightColor = GhidraOptions.DEFAULT_CURSOR_LINE_COLOR; protected static final HelpService help = Help.getHelpService(); private GoToService goToService; @@ -374,11 +376,9 @@ public class ProgramDiffPlugin extends ProgramPlugin boolean diffHighlightChanged = false; if (options.getName().equals(GhidraOptions.CATEGORY_BROWSER_FIELDS)) { if (optionsName.equals(DIFF_HIGHLIGHT_COLOR_NAME)) { - diffHighlightColor = ((Color) newValue); diffHighlightChanged = true; } else if (optionsName.equals(GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR)) { - cursorHighlightColor = (Color) newValue; if (p2CursorMarkers != null) { p2CursorMarkers.setMarkerColor(cursorHighlightColor); } @@ -395,7 +395,6 @@ public class ProgramDiffPlugin extends ProgramPlugin } if (diffHighlightChanged) { - diffHighlightColor = ((Color) newValue); MarkerSet diffMarkers = getDiffMarkers(); diffMarkers.setMarkerColor(diffHighlightColor); @@ -1396,14 +1395,11 @@ public class ProgramDiffPlugin extends ProgramPlugin private void setupOptions() { String OPTIONS_TITLE = GhidraOptions.CATEGORY_BROWSER_FIELDS; ToolOptions opt = tool.getOptions(OPTIONS_TITLE); - opt.registerOption(DIFF_HIGHLIGHT_COLOR_NAME, diffHighlightColor, + opt.registerThemeColorBinding(DIFF_HIGHLIGHT_COLOR_NAME, diffHighlightColor.getId(), new HelpLocation("CodeBrowserPlugin", "Browser_Fields"), "Color used to highlight differences between two programs."); - Color c = opt.getColor(DIFF_HIGHLIGHT_COLOR_NAME, diffHighlightColor); - diffHighlightColor = c; opt.addOptionsChangeListener(this); - cursorHighlightColor = opt.getColor(GhidraOptions.HIGHLIGHT_CURSOR_LINE_COLOR, null); isHighlightCursorLine = opt.getBoolean(GhidraOptions.HIGHLIGHT_CURSOR_LINE, false); } diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/SaveApplySettingsAction.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/SaveApplySettingsAction.java index f32674487a..c9ade4e2b2 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/SaveApplySettingsAction.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/SaveApplySettingsAction.java @@ -22,7 +22,7 @@ import docking.action.DockingAction; import docking.action.ToolBarData; import ghidra.app.util.HelpTopics; import ghidra.util.HelpLocation; -import resources.ResourceManager; +import resources.Icons; /** * Action to save the current Diff Apply Settings as the new defaults to be used when new Diffs are started. @@ -45,7 +45,7 @@ class SaveApplySettingsAction extends DockingAction { super(ACTION_NAME, settingsProvider.getPlugin().getName()); this.settingsProvider = settingsProvider; this.settingsOptionMgr = settingsOptionMgr; - setToolBarData(new ToolBarData(ResourceManager.loadImage("images/disk.png"), GROUP_NAME)); + setToolBarData(new ToolBarData(Icons.SAVE_ICON, GROUP_NAME)); setEnabled(true); setDescription(DESCRIPTION); setHelpLocation(new HelpLocation(HelpTopics.DIFF, ACTION_NAME)); @@ -61,8 +61,10 @@ class SaveApplySettingsAction extends DockingAction { @Override public void actionPerformed(ActionContext context) { settingsOptionMgr.saveDefaultApplyFilter(settingsProvider.getApplyFilter()); - settingsProvider.getPlugin().getTool().setStatusInfo( - "Diff Apply Settings have been saved to the tool as the new defaults."); + settingsProvider.getPlugin() + .getTool() + .setStatusInfo( + "Diff Apply Settings have been saved to the tool as the new defaults."); } } diff --git a/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java b/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java index 95d9bbbf56..ac7f16fff2 100644 --- a/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java +++ b/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DiffTestAdapter.java @@ -33,6 +33,7 @@ import docking.action.ToggleDockingAction; import docking.tool.ToolConstants; import docking.widgets.fieldpanel.FieldPanel; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.app.events.ProgramLocationPluginEvent; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.marker.MarkerManagerPlugin; @@ -271,10 +272,10 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest { builder.setIntProperty("10018ff", "Space", 1); builder.setIntProperty("100248c", "Space", 1); - builder.setObjectProperty("100248c", "testColor", new SaveableColor(Color.CYAN)); - builder.setObjectProperty("10039dd", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Color.RED)); + builder.setObjectProperty("100248c", "testColor", new SaveableColor(Palette.CYAN)); + builder.setObjectProperty("10039dd", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Palette.RED)); AbstractGenericTest.setInstanceField("recordChanges", builder.getProgram(), Boolean.TRUE); @@ -450,10 +451,10 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest { builder.setIntProperty("1002428", "Space", 1); builder.setIntProperty("100248c", "Space", 1); - builder.setObjectProperty("100248c", "testColor", new SaveableColor(Color.WHITE)); - builder.setObjectProperty("10039f1", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Color.BLACK)); - builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Color.GREEN)); + builder.setObjectProperty("100248c", "testColor", new SaveableColor(Palette.WHITE)); + builder.setObjectProperty("10039f1", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039f8", "testColor", new SaveableColor(Palette.BLACK)); + builder.setObjectProperty("10039fe", "testColor", new SaveableColor(Palette.GREEN)); AbstractGenericTest.setInstanceField("recordChanges", builder.getProgram(), Boolean.TRUE); diff --git a/Ghidra/Features/Python/certification.manifest b/Ghidra/Features/Python/certification.manifest index bbb9356524..412c40104c 100644 --- a/Ghidra/Features/Python/certification.manifest +++ b/Ghidra/Features/Python/certification.manifest @@ -2,6 +2,7 @@ ##MODULE IP: Jython License ##MODULE IP: LGPL 2.1 Module.manifest||GHIDRA||||END| +data/python.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/topics/Python/images/erase16.png||GHIDRA||||END| src/main/help/help/topics/Python/interpreter.html||GHIDRA||||END| diff --git a/Ghidra/Features/Python/data/python.theme.properties b/Ghidra/Features/Python/data/python.theme.properties new file mode 100644 index 0000000000..52757dc295 --- /dev/null +++ b/Ghidra/Features/Python/data/python.theme.properties @@ -0,0 +1,19 @@ + +[Defaults] + +color.fg.plugin.python.syntax.class = blue +color.fg.plugin.python.syntax.code = darkgreen +color.fg.plugin.python.syntax.function = green +color.fg.plugin.python.syntax.instance = purple +color.fg.plugin.python.syntax.map = steelblue +color.fg.plugin.python.syntax.method = teal +color.fg.plugin.python.syntax.null = red +color.fg.plugin.python.syntax.number = darkgray +color.fg.plugin.python.syntax.package = darkred +color.fg.plugin.python.syntax.sequence = rgb(128, 96, 64) +color.fg.plugin.python.syntax.special = darkgreen + +icon.plugin.python = python.png + +[Dark Defaults] + diff --git a/Ghidra/Features/Python/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/Python/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/Python/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/Python/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/Python/src/main/java/ghidra/python/PythonCodeCompletionFactory.java b/Ghidra/Features/Python/src/main/java/ghidra/python/PythonCodeCompletionFactory.java index 5e254f8efc..6943b2cbd2 100644 --- a/Ghidra/Features/Python/src/main/java/ghidra/python/PythonCodeCompletionFactory.java +++ b/Ghidra/Features/Python/src/main/java/ghidra/python/PythonCodeCompletionFactory.java @@ -25,6 +25,7 @@ import org.python.core.PyInstance; import org.python.core.PyObject; import docking.widgets.label.GDLabel; +import generic.theme.GColor; import ghidra.app.plugin.core.console.CodeCompletion; import ghidra.framework.options.Options; import ghidra.util.Msg; @@ -57,19 +58,21 @@ public class PythonCodeCompletionFactory { private final static boolean INCLUDE_TYPES_DEFAULT = true; private static boolean includeTypes = INCLUDE_TYPES_DEFAULT; - public static final Color NULL_COLOR = new Color(255, 0, 0); - public static final Color FUNCTION_COLOR = new Color(0, 128, 0); - public static final Color PACKAGE_COLOR = new Color(128, 0, 0); - public static final Color CLASS_COLOR = new Color(0, 0, 255); - public static final Color METHOD_COLOR = new Color(0, 128, 128); + //@formatter:off + public static final Color NULL_COLOR = new GColor("color.fg.plugin.python.syntax.null"); + public static final Color FUNCTION_COLOR = new GColor("color.fg.plugin.python.syntax.function"); + public static final Color PACKAGE_COLOR = new GColor("color.fg.plugin.python.syntax.package"); + public static final Color CLASS_COLOR = new GColor("color.fg.plugin.python.syntax.class"); + public static final Color METHOD_COLOR = new GColor("color.fg.plugin.python.syntax.method"); /* anonymous code chunks */ - public static final Color CODE_COLOR = new Color(0, 64, 0); - public static final Color INSTANCE_COLOR = new Color(128, 0, 128); - public static final Color SEQUENCE_COLOR = new Color(128, 96, 64); - public static final Color MAP_COLOR = new Color(64, 96, 128); - public static final Color NUMBER_COLOR = new Color(64, 64, 64); + public static final Color CODE_COLOR = new GColor("color.fg.plugin.python.syntax.code"); + public static final Color INSTANCE_COLOR = new GColor("color.fg.plugin.python.syntax.instance"); + public static final Color SEQUENCE_COLOR = new GColor("color.fg.plugin.python.syntax.sequence"); + public static final Color MAP_COLOR = new GColor("color.fg.plugin.python.syntax.map"); + public static final Color NUMBER_COLOR = new GColor("color.fg.plugin.python.syntax.number"); /* for weird Jython-specific stuff */ - public static final Color SPECIAL_COLOR = new Color(64, 96, 64); + public static final Color SPECIAL_COLOR = new GColor("color.fg.plugin.python.syntax.special"); + //@formatter:on static { /* Order matters! This is the order in which classes are checked for diff --git a/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java b/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java index 0dcbe75b7c..c0da0b8734 100644 --- a/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java +++ b/Ghidra/Features/Python/src/main/java/ghidra/python/PythonPlugin.java @@ -19,7 +19,7 @@ import java.awt.event.KeyEvent; import java.io.*; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import org.python.core.PySystemState; @@ -27,6 +27,7 @@ import docking.ActionContext; import docking.DockingUtils; import docking.action.*; import generic.jar.ResourceFile; +import generic.theme.GIcon; import ghidra.app.CorePluginPackage; import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.ProgramPlugin; @@ -40,7 +41,7 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.util.HelpLocation; import ghidra.util.task.*; -import resources.ResourceManager; +import resources.Icons; /** * This plugin provides the interactive Python interpreter. @@ -59,8 +60,6 @@ import resources.ResourceManager; public class PythonPlugin extends ProgramPlugin implements InterpreterConnection, OptionsChangeListener { - private final static int INPUT_THREAD_SHUTDOWN_TIMEOUT_MS = 1000; - private InterpreterConsole console; private GhidraPythonInterpreter interpreter; private PythonScript interactiveScript; @@ -72,6 +71,9 @@ public class PythonPlugin extends ProgramPlugin private final static String INCLUDE_BUILTINS_DESCRIPTION = "Whether or not to include Python's built-in functions and properties in the pop-up code completion window."; private final static boolean INCLUDE_BUILTINS_DEFAULT = true; + + private static final Icon ICON = new GIcon("icon.plugin.python"); + private boolean includeBuiltins = INCLUDE_BUILTINS_DEFAULT; /** @@ -134,7 +136,7 @@ public class PythonPlugin extends ProgramPlugin * Creates various actions for the plugin. */ private void createActions() { - + // Interrupt Interpreter DockingAction interruptAction = new DockingAction("Interrupt Interpreter", getName()) { @Override @@ -144,7 +146,7 @@ public class PythonPlugin extends ProgramPlugin }; interruptAction.setDescription("Interrupt Interpreter"); interruptAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/dialog-cancel.png"), null)); + new ToolBarData(Icons.NOT_ALLOWED_ICON, null)); interruptAction.setEnabled(true); interruptAction.setKeyBindingData( new KeyBindingData(KeyEvent.VK_I, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); @@ -160,7 +162,7 @@ public class PythonPlugin extends ProgramPlugin }; resetAction.setDescription("Reset Interpreter"); resetAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/reload3.png"), null)); + new ToolBarData(Icons.REFRESH_ICON, null)); resetAction.setEnabled(true); resetAction.setKeyBindingData( new KeyBindingData(KeyEvent.VK_D, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); @@ -345,8 +347,8 @@ public class PythonPlugin extends ProgramPlugin } @Override - public ImageIcon getIcon() { - return ResourceManager.loadImage("images/python.png"); + public Icon getIcon() { + return ICON; } /** diff --git a/Ghidra/Features/SourceCodeLookup/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/SourceCodeLookup/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/SourceCodeLookup/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/SourceCodeLookup/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/VersionTracking/certification.manifest b/Ghidra/Features/VersionTracking/certification.manifest index 1c3c497aa1..927370bc2b 100644 --- a/Ghidra/Features/VersionTracking/certification.manifest +++ b/Ghidra/Features/VersionTracking/certification.manifest @@ -5,6 +5,7 @@ ##MODULE IP: Tango Icons - Public Domain Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||reviewed||END| +data/version.tracking.theme.properties||GHIDRA||||END| src/main/docs/VTClasses.png||GHIDRA||reviewed||END| src/main/docs/VTGuiImpl.png||GHIDRA||reviewed||END| src/main/help/help/TOC_Source.xml||GHIDRA||reviewed||END| diff --git a/Ghidra/Features/VersionTracking/data/version.tracking.theme.properties b/Ghidra/Features/VersionTracking/data/version.tracking.theme.properties new file mode 100644 index 0000000000..345e342482 --- /dev/null +++ b/Ghidra/Features/VersionTracking/data/version.tracking.theme.properties @@ -0,0 +1,164 @@ +[Defaults] + +color.fg.version.tracking.tooltip = gray + +color.bg.version.tracking.dual.listing.highlight.markup.applied = rgb(150, 220, 150) // green +color.bg.version.tracking.dual.listing.highlight.markup.unapplied = rgb(255, 170, 85) // orange +color.bg.version.tracking.dual.listing.highlight.markup.ignored = gainsboro // gray +color.bg.version.tracking.dual.listing.highlight.markup.rejected = rgb(250, 200, 200) // pink +color.bg.version.tracking.dual.listing.highlight.markup.failed = rgb(255, 80, 80) // red +color.bg.version.tracking.dual.listing.highlight.markup.no.address = rgb(205, 185, 220) // purple +color.bg.version.tracking.dual.listing.highlight.markup.same = rgb(175, 225, 255) // light blue +color.bg.version.tracking.dual.listing.highlight.markup.conflict = rgb(255, 225, 105) // gold + +color.bg.version.tracking.filter.formatted.field.error = rgb(218, 217, 206) // grayish +color.bg.version.tracking.filter.formatted.field.editing = rgb(243, 242, 131) // yellowish + +color.bg.version.tracking.match.table.locked.out = whitesmoke +color.bg.version.tracking.match.table.markup.status.applied = rgb(0, 180, 0) // green +color.bg.version.tracking.match.table.markup.status.rejected = red +color.bg.version.tracking.match.table.markup.status.dont.care = royalblue +color.bg.version.tracking.match.table.markup.status.dont.know = orange +color.bg.version.tracking.match.table.markup.status.tooltip.unexamined = black +color.fg.version.tracking.match.table.error = color.fg.error + +color.fg.version.tracking.markup.items.table.error = color.fg.error +color.fg.version.tracking.markup.items.table.user.defined.address = cyan +color.fg.version.tracking.markup.items.table.user.defined.address.selected = lightseagreen + +color.bg.version.tracking.related.matches.table.good = green +color.bg.version.tracking.related.matches.table.medium = yellow +color.bg.version.tracking.related.matches.table.bad = red + +color.fg.version.tracking.function.match.local.info = green + +icon.version.tracking.session.content.type = start-here_16.png +icon.version.tracking.package = start-here_16.png + +icon.version.tracking.provider.function = functions.gif +icon.version.tracking.provider.implied.match = application_view_detail.png +icon.version.tracking.provider.markup = application_view_detail.png +icon.version.tracking.provider.one.to.many = text_list_bullets.png +icon.version.tracking.provider.related.matches = user-online.png + +icon.version.tracking.unfiltered = lightbulb_off.png +icon.version.tracking.filtered = lightbulb.png +icon.version.tracking.replaced = sync_enabled.png +icon.version.tracking.unignored = EMPTY_ICON{dialog-cancel.png[size(13,13)][move(3,4)]}{undo.png[move(0,-4)]} + +icon.version.tracking.accept.match = flag.png +icon.version.tracking.add = Plus.png +icon.version.tracking.substract = list-remove.png +icon.version.tracking.replace = sync_enabled.png +icon.version.tracking.auto = wizard.png + +icon.version.tracking.action.clear.match = undo-apply.png +icon.version.tracking.action.create.implied.match = flag.png +icon.version.tracking.action.create.manual.match = Plus.png +icon.version.tracking.action.create.and.accept.manual.match = flag.png +icon.version.tracking.action.create.accept.and.apply.manual.match = checkmark_green.gif +icon.version.tracking.action.create.selection = text_align_justify.png +icon.version.tracking.action.create.session = start-here_16.png +icon.version.tracking.action.choose.tag = tag_blue.png +icon.version.tracking.action.edit.all.tags = tag_blue_edit.png +icon.version.tracking.action.accept.match = icon.version.tracking.accept.match +icon.version.tracking.action.add.to.session = Plus.png +icon.version.tracking.action.save.session = disk.png +icon.version.tracking.action.match.reject = dialog-cancel.png +icon.version.tracking.action.match.remove = edit-delete.png +icon.version.tracking.action.match.select.existing = text_align_justify.png +icon.version.tracking.action.match.tag.remove = tag_blue_delete.png +icon.version.tracking.action.markup.reset = undo-apply.png +icon.version.tracking.action.match.one.to.many = text_align_justify.png +icon.version.tracking.action.show.listings = application_tile_horizontal.png +icon.version.tracking.action.show.settings = settings16.gif +icon.version.tracking.action.edit.markup.address = edit-rename.png + + +icon.version.tracking.tag.status.new = tag_blue_add.png +icon.version.tracking.tag.status.deleted = tag_blue_delete.png +icon.version.tracking.tag.status.existing = tag_blue.png +icon.version.tracking.tag.button.undo = undo-apply.png + +icon.version.tracking.filter.status.changed = bullet_black.png +icon.version.tracking.filter.status.invalid = no_small.png +icon.version.tracking.filter.status.applied = bullet_green.png + +icon.version.tracking.markup.status.applied = checkmark_green.gif +icon.version.tracking.markup.status.rejected = dialog-cancel.png +icon.version.tracking.markup.status.dont.care = asterisk_orange.png +icon.version.tracking.markup.status.dont.know = unknown.gif +icon.version.tracking.markup.status.failed = edit-delete.png +icon.version.tracking.markup.status.conflict = cache.png + +icon.version.tracking.filter = view-filter.png +icon.version.tracking.empty = EmptyIcon16.gif + +icon.version.tracking.function.filter.all = function.png +icon.version.tracking.function.filter.unmatched = filter_matched.png + + +icon.version.tracking.match.table.status.accepted.some.unexamined = flag.png {bullet_error.png[move(10,8)]} +icon.version.tracking.match.table.status.accepted.error = flag.png {edit-delete.png[size(8,8)][move(10,8)]} +icon.version.tracking.match.table.status.accepted.fully.applied = flag.png {checkmark_green.gif[size(8,8)][move(10,8)]} +icon.version.tracking.match.table.status.accepted.fully.considered = flag.png {checkmark_yellow.gif[size(8,8)][move(10,8)]} +icon.version.tracking.match.table.status.rejected = dialog-cancel.png +icon.version.tracking.match.table.status.blocked = kgpg.png + +icon.version.tracking.match.table.markup.status.disabled = ledgreen.png[size(8,8)][disabled] +icon.version.tracking.match.table.markup.status.not.applied = ledorange.png[size(8,8)][move(0,4)] +icon.version.tracking.match.table.markup.status.applied = ledgreen.png[size(8,8)][move(9,4)] +icon.version.tracking.match.table.markup.status.rejected = ledpurple.png[size(8,8)][move(18,4)] +icon.version.tracking.match.table.markup.status.ignored = ledblue.png[size(8,8)][move(27,4)] +icon.version.tracking.match.table.markup.status.error = ledred.png[size(8,8)][move(36,4)] + +icon.version.tracking.related.match.target = user-online.png +icon.version.tracking.related.match.caller = go-down.png +icon.version.tracking.related.match.callee = go-next.png +icon.version.tracking.related.match.unrelated = user-busy.png +icon.version.tracking.related.match.accepted = accept.png +icon.version.tracking.related.match.available = media-playback-stop.png +icon.version.tracking.related.match.locked.out = edit-delete.png + +icon.version.tracking.match.table.selection.track.row = table_gear.png +icon.version.tracking.match.table.selection.track.match = table_go.png +icon.version.tracking.match.table.selection.track.none = table_delete.png + +icon.version.tracking.table.renderer.multiple.symbols = application_view_detail.png + +icon.version.tracking.new.session.swap = doubleArrowUpDown.png +icon.version.tracking.new.session.info = information.png +icon.version.tracking.correlator.status.already.run = flag-green.png + + +[Dark Defaults] + + +color.bg.version.tracking.dual.listing.highlight.markup.applied = rgb(150, 220, 150) // green +color.bg.version.tracking.dual.listing.highlight.markup.unapplied = rgb(255, 170, 85) // orange +color.bg.version.tracking.dual.listing.highlight.markup.ignored = rgb(220, 220, 220) // gray +color.bg.version.tracking.dual.listing.highlight.markup.rejected = rgb(250, 200, 200) // pink +color.bg.version.tracking.dual.listing.highlight.markup.failed = rgb(255, 80, 80) // red +color.bg.version.tracking.dual.listing.highlight.markup.no.address = rgb(205, 185, 220) // purple +color.bg.version.tracking.dual.listing.highlight.markup.same = rgb(175, 225, 255) // light blue +color.bg.version.tracking.dual.listing.highlight.markup.conflict = rgb(255, 225, 105) // gold + +color.bg.version.tracking.filter.formatted.field.error = rgb(218, 217, 206) // grayish +color.bg.version.tracking.filter.formatted.field.editing = rgb(243, 242, 131) // yellowish + +color.bg.version.tracking.match.table.locked.out = whitesmoke +color.bg.version.tracking.match.table.markup.status.applied = rgb(0, 180, 0) // green +color.bg.version.tracking.match.table.markup.status.rejected = red +color.bg.version.tracking.match.table.markup.status.dont.care = royalblue +color.bg.version.tracking.match.table.markup.status.dont.know = orange +color.fg.version.tracking.match.table.error = color.fg.error + +color.fg.version.tracking.markup.items.table.error = color.fg.error +color.fg.version.tracking.markup.items.table.user.defined.address = cyan +color.fg.version.tracking.markup.items.table.user.defined.address.selected = lightseagreen + +color.bg.version.tracking.related.matches.table.good = green +color.bg.version.tracking.related.matches.table.medium = yellow +color.bg.version.tracking.related.matches.table.bad = red + +color.fg.version.tracking.function.match.local.info = green \ No newline at end of file diff --git a/Ghidra/Features/VersionTracking/src/main/help/help/shared/Frontpage.css b/Ghidra/Features/VersionTracking/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Features/VersionTracking/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Features/VersionTracking/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java index 513ce83b4b..ef12f97735 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java @@ -18,11 +18,11 @@ package ghidra.feature.vt.api.impl; import java.io.IOException; import javax.swing.Icon; -import javax.swing.ImageIcon; import db.DBHandle; import db.OpenMode; import db.buffers.BufferFile; +import generic.theme.GIcon; import ghidra.feature.vt.api.db.VTSessionDB; import ghidra.framework.data.*; import ghidra.framework.model.ChangeSet; @@ -33,11 +33,9 @@ import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; import ghidra.util.task.TaskMonitor; -import resources.ResourceManager; public class VTSessionContentHandler extends DBContentHandler { - private static ImageIcon ICON = ResourceManager - .getScaledIcon(ResourceManager.loadImage("images/start-here_16.png"), 16, 16); + private static Icon ICON = new GIcon("icon.version.tracking.session.content.type"); public final static String CONTENT_TYPE = "VersionTracking"; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AcceptMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AcceptMatchAction.java index 00d8139af2..9527b8cf65 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AcceptMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AcceptMatchAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,14 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -24,15 +31,6 @@ import ghidra.feature.vt.gui.provider.onetomany.VTMatchOneToManyContext; import ghidra.feature.vt.gui.task.AcceptMatchTask; import ghidra.util.HelpLocation; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - public class AcceptMatchAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.EDIT_MENU_GROUP; @@ -43,7 +41,7 @@ public class AcceptMatchAction extends DockingAction { super("Accept", VTPlugin.OWNER); this.controller = controller; - Icon icon = ResourceManager.loadImage("images/flag.png"); + Icon icon = new GIcon("icon.version.tracking.action.accept.match"); setToolBarData(new ToolBarData(icon, MENU_GROUP)); setPopupMenuData(new MenuData(new String[] { "Accept" }, icon, MENU_GROUP)); setEnabled(false); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AddToVersionTrackingSessionAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AddToVersionTrackingSessionAction.java index 6f02ce2f38..64ee1c57dd 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AddToVersionTrackingSessionAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AddToVersionTrackingSessionAction.java @@ -15,18 +15,17 @@ */ package ghidra.feature.vt.gui.actions; -import ghidra.feature.vt.gui.plugin.VTController; -import ghidra.feature.vt.gui.plugin.VTPlugin; -import ghidra.feature.vt.gui.wizard.VTAddToSessionWizardManager; -import ghidra.util.HelpLocation; - import javax.swing.Icon; -import resources.ResourceManager; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; import docking.wizard.WizardManager; +import generic.theme.GIcon; +import ghidra.feature.vt.gui.plugin.VTController; +import ghidra.feature.vt.gui.plugin.VTPlugin; +import ghidra.feature.vt.gui.wizard.VTAddToSessionWizardManager; +import ghidra.util.HelpLocation; public class AddToVersionTrackingSessionAction extends DockingAction { @@ -37,13 +36,8 @@ public class AddToVersionTrackingSessionAction extends DockingAction { super("Add To Session", VTPlugin.OWNER); this.controller = controller; String[] menuPath = { ToolConstants.MENU_FILE, "Add to Session..." }; - Icon plusIcon = ResourceManager.loadImage("images/Plus.png"); - + Icon plusIcon = new GIcon("icon.version.tracking.action.add.to.session"); setMenuBarData(new MenuData(menuPath, plusIcon, "AAA")); - -// Icon baseNewIcon = ResourceManager.loadImage("images/start-here_16.png"); -// MultiIcon addToIcon = new MultiIcon(baseNewIcon, false); -// addToIcon.addIcon(plusIcon); setToolBarData(new ToolBarData(plusIcon, "View")); setDescription("Add additional correlations to the current version tracking session"); setHelpLocation(new HelpLocation("VersionTrackingPlugin", "Add_To_Session")); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ApplyMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ApplyMatchAction.java index b6d9b918cb..48531b562e 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ApplyMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ApplyMatchAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +15,19 @@ */ package ghidra.feature.vt.gui.actions; -import ghidra.feature.vt.api.main.VTMatch; -import ghidra.feature.vt.gui.plugin.VTController; -import ghidra.feature.vt.gui.plugin.VTPlugin; -import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; -import ghidra.feature.vt.gui.task.ApplyMatchTask; -import ghidra.util.HelpLocation; - import java.util.List; import javax.swing.Icon; -import resources.ResourceManager; import docking.ActionContext; import docking.action.*; +import ghidra.feature.vt.api.main.VTMatch; +import ghidra.feature.vt.gui.plugin.VTController; +import ghidra.feature.vt.gui.plugin.VTPlugin; +import ghidra.feature.vt.gui.provider.markuptable.MarkupStatusIcons; +import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; +import ghidra.feature.vt.gui.task.ApplyMatchTask; +import ghidra.util.HelpLocation; public class ApplyMatchAction extends DockingAction { @@ -42,7 +40,7 @@ public class ApplyMatchAction extends DockingAction { super(NAME, VTPlugin.OWNER); this.controller = controller; - Icon icon = ResourceManager.loadImage("images/checkmark_green.gif"); + Icon icon = MarkupStatusIcons.APPLIED_ICON; setToolBarData(new ToolBarData(icon, MENU_GROUP)); setPopupMenuData(new MenuData(new String[] { NAME }, icon, MENU_GROUP)); setEnabled(false); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingAction.java index 6906cf6e7b..6a9651cbfe 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingAction.java @@ -20,19 +20,19 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.util.HTMLUtilities; import ghidra.util.HelpLocation; import ghidra.util.task.TaskLauncher; -import resources.ResourceManager; /** * This action runs the {@link AutoVersionTrackingTask} */ public class AutoVersionTrackingAction extends DockingAction { - public static Icon AUTO_VT_ICON = ResourceManager.loadImage("images/wizard.png"); + public static Icon AUTO_VT_ICON = new GIcon("icon.version.tracking.auto"); private final VTController controller; public AutoVersionTrackingAction(VTController controller) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ChooseMatchTagAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ChooseMatchTagAction.java index 0beb435c0b..3a796e2898 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ChooseMatchTagAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ChooseMatchTagAction.java @@ -24,18 +24,18 @@ import javax.swing.*; import docking.ActionContext; import docking.DialogComponentProvider; import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.*; import ghidra.feature.vt.gui.editors.MatchTagComboBox; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class ChooseMatchTagAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.TAG_MENU_GROUP; - private static final Icon EDIT_TAG_ICON = ResourceManager.loadImage("images/tag_blue.png"); + private static final Icon EDIT_TAG_ICON = new GIcon("icon.version.tracking.action.choose.tag"); private static final String ACTION_NAME = "Choose Match Tag"; private final VTController controller; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ClearMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ClearMatchAction.java index 5fe2a61213..5c2105d7ee 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ClearMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ClearMatchAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,14 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -24,19 +31,10 @@ import ghidra.feature.vt.gui.provider.onetomany.VTMatchOneToManyContext; import ghidra.feature.vt.gui.task.ClearMatchTask; import ghidra.util.HelpLocation; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - public class ClearMatchAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.UNEDIT_MENU_GROUP; - private static final Icon ICON = ResourceManager.loadImage("images/undo-apply.png"); + private static final Icon ICON = new GIcon("icon.version.tracking.action.clear.match"); private final VTController controller; public ClearMatchAction(VTController controller) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateImpliedMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateImpliedMatchAction.java index e57d71fc76..9bb9d73856 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateImpliedMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateImpliedMatchAction.java @@ -17,10 +17,11 @@ package ghidra.feature.vt.gui.actions; import java.util.List; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -30,7 +31,6 @@ import ghidra.feature.vt.gui.task.*; import ghidra.util.HelpLocation; import ghidra.util.task.Task; import ghidra.util.task.TaskListener; -import resources.ResourceManager; public class CreateImpliedMatchAction extends DockingAction { @@ -43,7 +43,7 @@ public class CreateImpliedMatchAction extends DockingAction { this.controller = controller; this.provider = provider; - ImageIcon icon = ResourceManager.loadImage("images/flag.png"); + Icon icon = new GIcon("icon.version.tracking.action.create.implied.match"); setToolBarData(new ToolBarData(icon, "1")); setPopupMenuData(new MenuData(new String[] { "Accept Implied Match" }, icon, "1")); setHelpLocation(new HelpLocation("VersionTrackingPlugin", "Accept_Implied_Match")); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAction.java index 4353ac7f90..e00fbb5916 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAction.java @@ -15,6 +15,12 @@ */ package ghidra.feature.vt.gui.actions; +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.MenuData; +import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -25,19 +31,13 @@ import ghidra.util.HelpLocation; import ghidra.util.task.Task; import ghidra.util.task.TaskListener; -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - /** * Action that creates a manual match for the currently selected source and destination functions * in the function association tables. */ public class CreateManualMatchAction extends AbstractCreateManualMatchAction { - public static final Icon ICON = ResourceManager.loadImage("images/Plus.png"); + public static final Icon ICON = new GIcon("icon.version.tracking.action.create.manual.match"); /** * Creates a manual match action. diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAction.java index ca1655f3d6..9a6cec4144 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAction.java @@ -15,6 +15,12 @@ */ package ghidra.feature.vt.gui.actions; +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.MenuData; +import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.functionassociation.FunctionAssociationContext; @@ -24,19 +30,14 @@ import ghidra.util.HelpLocation; import ghidra.util.task.Task; import ghidra.util.task.TaskListener; -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - /** * Action that creates a manual match for the currently selected source and destination functions * in the function association tables and then accepts the match. */ public class CreateManualMatchAndAcceptAction extends AbstractCreateManualMatchAction { - public static final Icon ICON = ResourceManager.loadImage("images/flag.png"); + public static final Icon ICON = + new GIcon("icon.version.tracking.action.create.and.accept.manual.match"); /** * Creates a manual match action that also does an accept of that match. @@ -48,7 +49,8 @@ public class CreateManualMatchAndAcceptAction extends AbstractCreateManualMatchA setToolBarData(new ToolBarData(ICON, MENU_GROUP)); setPopupMenuData(new MenuData(new String[] { "Create And Accept Manual Match" }, ICON)); setEnabled(false); - setHelpLocation(new HelpLocation("VersionTrackingPlugin", "Create_And_Accept_Manual_Match")); + setHelpLocation( + new HelpLocation("VersionTrackingPlugin", "Create_And_Accept_Manual_Match")); } @Override diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAndApplyAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAndApplyAction.java index 5804aff3f5..baa117c068 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAndApplyAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateManualMatchAndAcceptAndApplyAction.java @@ -15,6 +15,12 @@ */ package ghidra.feature.vt.gui.actions; +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.MenuData; +import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.functionassociation.FunctionAssociationContext; @@ -24,19 +30,14 @@ import ghidra.util.HelpLocation; import ghidra.util.task.Task; import ghidra.util.task.TaskListener; -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - /** * Action that creates a manual match for the currently selected source and destination functions * in the function association tables and then applies the match. */ public class CreateManualMatchAndAcceptAndApplyAction extends AbstractCreateManualMatchAction { - public static final Icon ICON = ResourceManager.loadImage("images/checkmark_green.gif"); + public static final Icon ICON = + new GIcon("icon.version.tracking.action.create.accept.and.apply.manual.match"); /** * Creates a manual match action that also does an apply of that match. diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateSelectionAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateSelectionAction.java index dad1804b93..73be37bffd 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateSelectionAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateSelectionAction.java @@ -21,6 +21,7 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTAssociation; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.gui.plugin.VTController; @@ -29,12 +30,11 @@ import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class CreateSelectionAction extends DockingAction { public static final String NAME = "Create Match Table Selection"; private static final String MENU_GROUP = "Selection"; - private static final Icon ICON = ResourceManager.loadImage("images/text_align_justify.png"); + private static final Icon ICON = new GIcon("icon.version.tracking.action.create.selection"); private final VTController controller; public CreateSelectionAction(VTController controller) { @@ -44,7 +44,8 @@ public class CreateSelectionAction extends DockingAction { setPopupMenuData(new MenuData(new String[] { "Make Selections" }, ICON, MENU_GROUP)); setEnabled(false); setHelpLocation(new HelpLocation("VersionTrackingPlugin", "Make Selections")); - setDescription("Makes selections in both the source and destination tools for the selected matches."); + setDescription( + "Makes selections in both the source and destination tools for the selected matches."); } @Override diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateVersionTrackingSessionAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateVersionTrackingSessionAction.java index 2e56d1553c..b31b823e4c 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateVersionTrackingSessionAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/CreateVersionTrackingSessionAction.java @@ -15,22 +15,21 @@ */ package ghidra.feature.vt.gui.actions; -import ghidra.feature.vt.gui.plugin.VTController; -import ghidra.feature.vt.gui.plugin.VTPlugin; -import ghidra.feature.vt.gui.wizard.VTNewSessionWizardManager; -import ghidra.util.HelpLocation; - import javax.swing.Icon; -import resources.ResourceManager; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; import docking.widgets.OptionDialog; import docking.wizard.WizardManager; +import generic.theme.GIcon; +import ghidra.feature.vt.gui.plugin.VTController; +import ghidra.feature.vt.gui.plugin.VTPlugin; +import ghidra.feature.vt.gui.wizard.VTNewSessionWizardManager; +import ghidra.util.HelpLocation; public class CreateVersionTrackingSessionAction extends DockingAction { - public static Icon NEW_ICON = ResourceManager.loadImage("images/start-here_16.png"); + public static Icon NEW_ICON = new GIcon("icon.version.tracking.action.create.session"); private final VTController controller; public CreateVersionTrackingSessionAction(VTController controller) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditAllTagsAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditAllTagsAction.java index b89305b931..e22adc3c5d 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditAllTagsAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditAllTagsAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +15,22 @@ */ package ghidra.feature.vt.gui.actions; +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.gui.editors.TagEditorDialog; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; import ghidra.util.HelpLocation; -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - public class EditAllTagsAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.TAG_MENU_GROUP; - private static final Icon EDIT_TAG_ICON = ResourceManager.loadImage("images/tag_blue_edit.png"); + private static final Icon EDIT_TAG_ICON = + new GIcon("icon.version.tracking.action.edit.all.tags"); private static final String ACTION_NAME = "Edit VTMatch Tags"; private final VTController controller; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditMarkupAddressAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditMarkupAddressAction.java index ab9ebc31af..e07b112ad6 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditMarkupAddressAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/EditMarkupAddressAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,15 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.*; + +import docking.ActionContext; +import docking.DialogComponentProvider; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMarkupItem; import ghidra.feature.vt.api.main.VTMarkupItemDestinationAddressEditStatus; import ghidra.feature.vt.gui.editors.*; @@ -28,21 +36,11 @@ import ghidra.program.model.listing.Program; import ghidra.util.*; import ghidra.util.exception.InvalidInputException; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.*; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.DialogComponentProvider; -import docking.action.*; - public class EditMarkupAddressAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.ADDRESS_EDIT_MENU_GROUP; private static final Icon EDIT_ADDRESS_ICON = - ResourceManager.loadImage("images/edit-rename.png"); + new GIcon("icon.version.tracking.action.edit.markup.address"); private static final String ACTION_NAME = "Edit Markup Destination Address"; final VTController controller; @@ -55,7 +53,8 @@ public class EditMarkupAddressAction extends DockingAction { setToolBarData(new ToolBarData(EDIT_ADDRESS_ICON, MENU_GROUP)); } MenuData menuData = - new MenuData(new String[] { "Edit Destination Address" }, EDIT_ADDRESS_ICON, MENU_GROUP); + new MenuData(new String[] { "Edit Destination Address" }, EDIT_ADDRESS_ICON, + MENU_GROUP); setPopupMenuData(menuData); setEnabled(false); setHelpLocation(new HelpLocation("VersionTrackingPlugin", diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/HelpAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/HelpAction.java index ee2ed7903b..c935c00de9 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/HelpAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/HelpAction.java @@ -27,11 +27,12 @@ import ghidra.util.HelpLocation; import ghidra.util.Msg; import help.Help; import help.HelpService; +import resources.Icons; import resources.ResourceManager; public class HelpAction extends DockingAction { - private static Icon ICON = ResourceManager.loadImage("images/help-browser.png"); + private static Icon ICON = Icons.HELP_ICON; public HelpAction() { super("Version Tracking Help Action", VTPlugin.OWNER); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/MatchTableSelectionAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/MatchTableSelectionAction.java index 14749bd31b..35e405ce44 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/MatchTableSelectionAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/MatchTableSelectionAction.java @@ -23,10 +23,10 @@ import docking.action.ToolBarData; import docking.menu.ActionState; import docking.menu.MultiStateDockingAction; import docking.widgets.EventTrigger; +import generic.theme.GIcon; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.matchtable.VTMatchTableProvider; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class MatchTableSelectionAction extends MultiStateDockingAction { @@ -49,9 +49,12 @@ public class MatchTableSelectionAction new HelpLocation("VersionTrackingPlugin", "Match_Table_Selection"); setHelpLocation(helpLocation); - Icon noSelectionTrackingIcon = ResourceManager.loadImage("images/table_delete.png"); - Icon trackMatchSelectionIcon = ResourceManager.loadImage("images/table_go.png"); - Icon trackRowIndexSelectionIcon = ResourceManager.loadImage("images/table_gear.png"); + Icon noSelectionTrackingIcon = + new GIcon("icon.version.tracking.match.table.selection.track.none"); + Icon trackMatchSelectionIcon = + new GIcon("icon.version.tracking.match.table.selection.track.match"); + Icon trackRowIndexSelectionIcon = + new GIcon("icon.version.tracking.match.table.selection.track.row"); ActionState trackSelectedIndexActionState = new ActionState<>("Track Selected Index", diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RedoAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RedoAction.java index 5a6b422f7e..3e56e4e832 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RedoAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RedoAction.java @@ -23,12 +23,12 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.feature.vt.api.db.VTSessionDB; import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.util.*; -import resources.ResourceManager; public class RedoAction extends DockingAction { private final VTController controller; @@ -39,7 +39,7 @@ public class RedoAction extends DockingAction { setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Redo")); String[] menuPath = { ToolConstants.MENU_EDIT, "&Redo" }; String group = "ZZUndo"; - Icon icon = ResourceManager.loadImage("images/redo.png"); + Icon icon = new GIcon("icon.redo"); MenuData menuData = new MenuData(menuPath, icon, group); menuData.setMenuSubGroup("2Redo"); // make this appear below the undo menu item setMenuBarData(menuData); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RejectMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RejectMatchAction.java index dad1e1cc4e..c04619dd94 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RejectMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RejectMatchAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,13 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.List; + +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.gui.plugin.VTController; @@ -24,18 +30,10 @@ import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; import ghidra.feature.vt.gui.task.RejectMatchTask; import ghidra.util.HelpLocation; -import java.util.List; - -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - public class RejectMatchAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.EDIT_MENU_GROUP; - private static final Icon ICON = ResourceManager.loadImage("images/dialog-cancel.png"); + private static final Icon ICON = new GIcon("icon.version.tracking.action.match.reject"); private final VTController controller; public RejectMatchAction(VTController controller) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchAction.java index 760fa1b9d9..77483d07d7 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,14 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.List; + +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.DockingAction; +import docking.action.MenuData; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.gui.plugin.VTController; @@ -24,19 +31,10 @@ import ghidra.feature.vt.gui.provider.matchtable.VTMatchContext; import ghidra.feature.vt.gui.task.RemoveMatchTask; import ghidra.util.HelpLocation; -import java.util.List; - -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.DockingAction; -import docking.action.MenuData; - public class RemoveMatchAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.UNEDIT_MENU_GROUP; - private static final Icon ICON = ResourceManager.loadImage("images/edit-delete.png"); + private static final Icon ICON = new GIcon("icon.version.tracking.action.match.remove"); private final VTController controller; public RemoveMatchAction(VTController controller) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchTagAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchTagAction.java index ed63f3ca24..92318bf62a 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchTagAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/RemoveMatchTagAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,16 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.List; + +import javax.swing.Icon; +import javax.swing.JComponent; + +import docking.ActionContext; +import docking.ComponentProvider; +import docking.action.*; +import docking.widgets.OptionDialog; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.api.main.VTMatchTag; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -24,22 +33,11 @@ import ghidra.feature.vt.gui.task.ClearMatchTagTask; import ghidra.util.HelpLocation; import ghidra.util.task.TaskLauncher; -import java.util.List; - -import javax.swing.Icon; -import javax.swing.JComponent; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.ComponentProvider; -import docking.action.*; -import docking.widgets.OptionDialog; - public class RemoveMatchTagAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.TAG_MENU_GROUP; private static final Icon EDIT_TAG_ICON = - ResourceManager.loadImage("images/tag_blue_delete.png"); + new GIcon("icon.version.tracking.action.match.tag.remove"); private static final String ACTION_NAME = "Remove VTMatch Tags"; private int tagCount = 0; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceDefaultMarkupItemAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceDefaultMarkupItemAction.java index 09e1e1eb79..ff6203ba7a 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceDefaultMarkupItemAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceDefaultMarkupItemAction.java @@ -18,10 +18,10 @@ package ghidra.feature.vt.gui.actions; import static ghidra.feature.vt.gui.util.VTOptionDefines.*; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.action.MenuData; import docking.action.ToolBarData; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMarkupItemApplyActionType; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -40,7 +40,7 @@ public class ReplaceDefaultMarkupItemAction extends AbstractMarkupItemAction { super(controller, "Apply (Replace Default Only)"); Icon replacedIcon = VTPlugin.REPLACED_ICON; - ImageIcon warningIcon = ResourceManager.loadImage("images/warning.png"); + Icon warningIcon = new GIcon("icon.warning"); warningIcon = ResourceManager.getScaledIcon(warningIcon, 12, 12); int warningIconWidth = warningIcon.getIconWidth(); int warningIconHeight = warningIcon.getIconHeight(); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceFirstMarkupItemAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceFirstMarkupItemAction.java index 0303cfde1c..cd32f9a58c 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceFirstMarkupItemAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ReplaceFirstMarkupItemAction.java @@ -15,10 +15,9 @@ */ package ghidra.feature.vt.gui.actions; -import static ghidra.feature.vt.gui.util.VTOptionDefines.DATA_MATCH_DATA_TYPE; +import static ghidra.feature.vt.gui.util.VTOptionDefines.*; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.action.MenuData; import docking.action.ToolBarData; @@ -28,9 +27,6 @@ import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.util.VTMatchApplyChoices.ReplaceDataChoices; import ghidra.framework.options.ToolOptions; import ghidra.util.HelpLocation; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.TranslateIcon; /** * Action that replaces Data for a version tracking data match, but only if no defined data @@ -54,22 +50,9 @@ public class ReplaceFirstMarkupItemAction extends AbstractMarkupItemAction { super(controller, "Apply (Replace First Only)"); Icon replacedIcon = VTPlugin.REPLACED_ICON; - ImageIcon warningIcon = ResourceManager.loadImage("images/warning_obj.png"); - warningIcon = ResourceManager.getScaledIcon(warningIcon, 12, 12); - MultiIcon multiIcon = new MultiIcon(replacedIcon, false); - int refreshIconWidth = replacedIcon.getIconWidth(); - int refreshIconHeight = replacedIcon.getIconHeight(); - int warningIconWidth = warningIcon.getIconWidth(); - int warningIconHeight = warningIcon.getIconHeight(); - - int x = refreshIconWidth - warningIconWidth; - int y = refreshIconHeight - warningIconHeight; - - TranslateIcon translateIcon = new TranslateIcon(warningIcon, x, y); - multiIcon.addIcon(translateIcon); if (addToToolbar) { - setToolBarData(new ToolBarData(multiIcon, MENU_GROUP)); + setToolBarData(new ToolBarData(replacedIcon, MENU_GROUP)); } MenuData menuData = new MenuData(new String[] { "Apply (Replace First Only)" }, replacedIcon, MENU_GROUP); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ResetMarkupItemAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ResetMarkupItemAction.java index 9c5889a31d..9e95518f77 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ResetMarkupItemAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/ResetMarkupItemAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,13 @@ */ package ghidra.feature.vt.gui.actions; +import java.util.List; + +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.*; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; @@ -26,17 +32,9 @@ import ghidra.util.HelpLocation; import ghidra.util.task.Task; import ghidra.util.task.TaskListener; -import java.util.List; - -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - public class ResetMarkupItemAction extends DockingAction { - public static final Icon RESET_ICON = ResourceManager.loadImage("images/undo-apply.png"); + public static final Icon RESET_ICON = new GIcon("icon.version.tracking.action.markup.reset"); private static final String MENU_GROUP = VTPlugin.UNEDIT_MENU_GROUP; final VTController controller; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SaveVersionTrackingSessionAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SaveVersionTrackingSessionAction.java index 227f831f45..84bd93597f 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SaveVersionTrackingSessionAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SaveVersionTrackingSessionAction.java @@ -15,13 +15,14 @@ */ package ghidra.feature.vt.gui.actions; -import static ghidra.feature.vt.gui.plugin.VTPlugin.VT_MAIN_MENU_GROUP; +import static ghidra.feature.vt.gui.plugin.VTPlugin.*; import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.feature.vt.api.db.VTSessionDB; import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.gui.plugin.VTController; @@ -31,11 +32,10 @@ import ghidra.framework.model.DomainFile; import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import ghidra.util.task.TaskLauncher; -import resources.ResourceManager; public class SaveVersionTrackingSessionAction extends DockingAction { - static final Icon ICON = ResourceManager.loadImage("images/disk.png"); + static final Icon ICON = new GIcon("icon.version.tracking.action.save.session"); private final VTController controller; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SelectExistingMatchAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SelectExistingMatchAction.java index de612ee9fd..c60586094d 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SelectExistingMatchAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SelectExistingMatchAction.java @@ -19,12 +19,12 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.functionassociation.FunctionAssociationContext; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * Action that selects the function match, if it exists, for the currently selected source and @@ -32,7 +32,8 @@ import resources.ResourceManager; */ public class SelectExistingMatchAction extends DockingAction { - private static final Icon ICON = ResourceManager.loadImage("images/text_align_justify.png"); + private static final Icon ICON = + new GIcon("icon.version.tracking.action.match.select.existing"); private static final String MENU_GROUP = "Create"; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SetVTMatchFromOneToManyAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SetVTMatchFromOneToManyAction.java index 82703c20ee..0a2aa62dac 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SetVTMatchFromOneToManyAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/SetVTMatchFromOneToManyAction.java @@ -21,18 +21,18 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTMatch; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.provider.onetomany.VTMatchOneToManyContext; import ghidra.util.HelpLocation; -import resources.ResourceManager; public class SetVTMatchFromOneToManyAction extends DockingAction { private static final String MENU_GROUP = VTPlugin.VT_MAIN_MENU_GROUP; public static final Icon SET_MATCH_ICON = - ResourceManager.loadImage("images/text_align_justify.png"); + new GIcon("icon.version.tracking.action.match.one.to.many"); final VTController controller; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/UndoAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/UndoAction.java index 600c3cd30f..b234c78b20 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/UndoAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/UndoAction.java @@ -23,11 +23,11 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.feature.vt.api.db.VTSessionDB; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.util.*; -import resources.ResourceManager; public class UndoAction extends DockingAction { private final VTController controller; @@ -38,7 +38,7 @@ public class UndoAction extends DockingAction { setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Undo")); String[] menuPath = { ToolConstants.MENU_EDIT, "&Undo" }; String group = "ZZUndo"; - Icon icon = ResourceManager.loadImage("images/undo.png"); + Icon icon = new GIcon("icon.undo"); MenuData menuData = new MenuData(menuPath, icon, group); menuData.setMenuSubGroup("1Undo"); // make this appear above the redo menu item setMenuBarData(menuData); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/duallisting/VTDualListingHighlightProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/duallisting/VTDualListingHighlightProvider.java index f144b618a1..07a21479b5 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/duallisting/VTDualListingHighlightProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/duallisting/VTDualListingHighlightProvider.java @@ -15,6 +15,11 @@ */ package ghidra.feature.vt.gui.duallisting; +import java.awt.Color; +import java.util.*; + +import docking.widgets.fieldpanel.support.Highlight; +import generic.theme.GColor; import ghidra.app.plugin.core.codebrowser.ListingHighlightProvider; import ghidra.app.util.HighlightProvider; import ghidra.app.util.viewer.field.*; @@ -32,24 +37,27 @@ import ghidra.program.model.listing.*; import ghidra.util.Msg; import ghidra.util.exception.AssertException; -import java.awt.Color; -import java.util.*; - -import docking.widgets.fieldpanel.support.Highlight; - public class VTDualListingHighlightProvider implements HighlightProvider { - private static Color APPLIED_MARKUP_COLOR = new Color(150, 220, 150); // green - private static Color UNAPPLIED_MARKUP_COLOR = new Color(255, 170, 85); // orange - private static Color IGNORED_MARKUP_COLOR = new Color(220, 220, 220); // gray - private static Color REJECTED_MARKUP_COLOR = new Color(250, 200, 200); // pink - private static Color FAILED_MARKUP_COLOR = new Color(255, 80, 80); // red - private static Color NO_ADDRESS_MARKUP_COLOR = new Color(205, 185, 220); // purple - private static Color SAME_MARKUP_COLOR = new Color(175, 225, 255); // light blue - private static Color CONFLICT_MARKUP_COLOR = new Color(255, 225, 105); // gold + private static Color APPLIED_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.applied"); + private static Color UNAPPLIED_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.unapplied"); + private static Color IGNORED_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.ignored"); + private static Color REJECTED_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.rejected"); + private static Color FAILED_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.failed"); + private static Color NO_ADDRESS_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.no.address"); + private static Color SAME_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.same"); + private static Color CONFLICT_MARKUP_COLOR = + new GColor("color.bg.version.tracking.dual.listing.highlight.markup.conflict"); private HashMap> map = - new HashMap>(); + new HashMap<>(); private final VTController controller; private ListingPanel listingPanel; private ListingHighlightProvider listingHighlighter; @@ -112,7 +120,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { HashMap typeMap = map.get(address); if (typeMap == null) { - typeMap = new HashMap(); + typeMap = new HashMap<>(); map.put(address, typeMap); } @@ -203,7 +211,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { cursorTextOffset, highlights); } - List highlightList = new ArrayList(); + List highlightList = new ArrayList<>(); for (Highlight highlight : highlights) { highlightList.add(highlight); @@ -274,7 +282,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { } return highlightColor; } - + /** * Creates a darker shade of the color passed-in, based on the given amount. * @@ -285,22 +293,22 @@ public class VTDualListingHighlightProvider implements HighlightProvider { * * @param color the color to shade * @param amount number between 0..1 (the smaller the number, the darker the shade) - * @return + * @return the new color */ private static Color shade(Color color, double amount) { if (color != null) { - + int r = color.getRed(); int g = color.getGreen(); int b = color.getBlue(); - + double newR = (r * amount); double newG = (g * amount); double newB = (b * amount); - - return new Color((int)newR, (int)newG, (int)newB); + + return new Color((int) newR, (int) newG, (int) newB); } - + return null; } @@ -315,7 +323,8 @@ public class VTDualListingHighlightProvider implements HighlightProvider { if (markupItem != null) { VTMarkupItemStatus status = markupItem.getStatus(); StringStringable value = - (StringStringable) ((isSource || markupItem.canUnapply()) ? markupItem.getSourceValue() + (StringStringable) ((isSource || markupItem.canUnapply()) + ? markupItem.getSourceValue() : markupItem.getOriginalDestinationValue()); String comment = value.getString(); if (comment != null) { @@ -418,7 +427,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { CodeUnit codeUnit = (CodeUnit) obj; address = codeUnit.getMinAddress(); } - ArrayList highlightList = new ArrayList(); + ArrayList highlightList = new ArrayList<>(); HashMap typeMap = map.get(address); if (typeMap != null) { VTMarkupItem markupItem = typeMap.get(RepeatableCommentMarkupType.INSTANCE); @@ -429,7 +438,8 @@ public class VTDualListingHighlightProvider implements HighlightProvider { return highlightList.toArray(new Highlight[highlightList.size()]); } - private Highlight[] getFunctionSignatureHighlights(String text, Object obj, int cursorTextOffset) { + private Highlight[] getFunctionSignatureHighlights(String text, Object obj, + int cursorTextOffset) { Function function = null; if (obj instanceof Function) { function = (Function) obj; @@ -445,7 +455,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { Address address = function.getEntryPoint(); HashMap typeMap = map.get(address); if (typeMap != null) { - ArrayList highlightList = new ArrayList(); + ArrayList highlightList = new ArrayList<>(); // // Check if the text is in the Return Type // addFunctionHighlight(FunctionReturnTypeMarkupType.INSTANCE, text, cursorTextOffset, @@ -485,7 +495,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { Address address = function.getEntryPoint(); HashMap typeMap = map.get(address); if (typeMap != null) { - ArrayList highlightList = new ArrayList(); + ArrayList highlightList = new ArrayList<>(); VTMarkupItem markupItem = typeMap.get(FunctionSignatureMarkupType.INSTANCE); if (markupItem == null) { @@ -544,7 +554,8 @@ public class VTDualListingHighlightProvider implements HighlightProvider { if (startIndex >= 0) { int endIndex = startIndex + displayString.length() - 1; Color highlightColor = - getMarkupBackgroundColor(cursorTextOffset, markupItem, startIndex, endIndex); + getMarkupBackgroundColor(cursorTextOffset, markupItem, startIndex, + endIndex); Highlight highlight = new Highlight(startIndex, endIndex, highlightColor); highlightList.add(highlight); } @@ -557,7 +568,8 @@ public class VTDualListingHighlightProvider implements HighlightProvider { VTMarkupItem markupItem = typeMap.get(FunctionNameMarkupType.INSTANCE); if (markupItem != null) { FunctionNameStringable value = - (isSource || markupItem.canUnapply()) ? (FunctionNameStringable) markupItem.getSourceValue() + (isSource || markupItem.canUnapply()) + ? (FunctionNameStringable) markupItem.getSourceValue() : (FunctionNameStringable) markupItem.getOriginalDestinationValue(); if (value != null) { int parameterStart = text.indexOf("("); @@ -569,7 +581,8 @@ public class VTDualListingHighlightProvider implements HighlightProvider { if (startIndex >= 0) { int endIndex = startIndex + name.length() - 1; Color highlightColor = - getMarkupBackgroundColor(cursorTextOffset, markupItem, startIndex, endIndex); + getMarkupBackgroundColor(cursorTextOffset, markupItem, startIndex, + endIndex); Highlight highlight = new Highlight(startIndex, endIndex, highlightColor); highlightList.add(highlight); } @@ -832,7 +845,7 @@ public class VTDualListingHighlightProvider implements HighlightProvider { if (storageAddress == null) { return new Highlight[0]; } - ArrayList highlightList = new ArrayList(); + ArrayList highlightList = new ArrayList<>(); HashMap typeMap = map.get(storageAddress); if (typeMap != null) { VTMarkupItem markupItem = typeMap.get(markupType); @@ -914,16 +927,18 @@ public class VTDualListingHighlightProvider implements HighlightProvider { if (typeMap != null) { VTMarkupItem markupItem = typeMap.get(LabelMarkupType.INSTANCE); if (markupItem != null) { - ArrayList highlightList = new ArrayList(); + ArrayList highlightList = new ArrayList<>(); MultipleSymbolStringable value = - (MultipleSymbolStringable) ((isSource || markupItem.canUnapply()) ? markupItem.getSourceValue() + (MultipleSymbolStringable) ((isSource || markupItem.canUnapply()) + ? markupItem.getSourceValue() : markupItem.getOriginalDestinationValue()); if (value != null) { // Highlight the entire labels field. int startIndex = 0; int endIndex = text.length() - 1; Color highlightColor = - getMarkupBackgroundColor(cursorTextOffset, markupItem, startIndex, endIndex); + getMarkupBackgroundColor(cursorTextOffset, markupItem, startIndex, + endIndex); Highlight highlight = new Highlight(startIndex, endIndex, highlightColor); highlightList.add(highlight); return highlightList.toArray(new Highlight[highlightList.size()]); @@ -942,9 +957,10 @@ public class VTDualListingHighlightProvider implements HighlightProvider { if (typeMap != null) { VTMarkupItem markupItem = typeMap.get(DataTypeMarkupType.INSTANCE); if (markupItem != null) { - ArrayList highlightList = new ArrayList(); + ArrayList highlightList = new ArrayList<>(); DataTypeStringable value = - (DataTypeStringable) ((isSource || markupItem.canUnapply()) ? markupItem.getSourceValue() + (DataTypeStringable) ((isSource || markupItem.canUnapply()) + ? markupItem.getSourceValue() : markupItem.getOriginalDestinationValue()); if (value != null) { Program sourceProgram = diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/editors/TagEditorRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/editors/TagEditorRenderer.java index 870f93b6f3..6626309f97 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/editors/TagEditorRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/editors/TagEditorRenderer.java @@ -15,7 +15,7 @@ */ package ghidra.feature.vt.gui.editors; -import static ghidra.feature.vt.gui.editors.TagEditorDialog.TagState.Action.ADD; +import static ghidra.feature.vt.gui.editors.TagEditorDialog.TagState.Action.*; import java.awt.*; import java.awt.event.MouseAdapter; @@ -25,18 +25,19 @@ import javax.swing.*; import docking.widgets.label.GDLabel; import docking.widgets.list.GListCellRenderer; +import generic.theme.GIcon; import ghidra.feature.vt.gui.editors.TagEditorDialog.TagState; import ghidra.feature.vt.gui.editors.TagEditorDialog.TagStateListModel; import ghidra.util.exception.AssertException; -import resources.ResourceManager; public class TagEditorRenderer extends GListCellRenderer { - private static final Icon NEW_TAG_ICON = ResourceManager.loadImage("images/tag_blue_add.png"); + private static final Icon NEW_TAG_ICON = new GIcon("icon.version.tracking.tag.status.new"); private static final Icon DELETED_TAG_ICON = - ResourceManager.loadImage("images/tag_blue_delete.png"); - private static final Icon EXISTING_TAG_ICON = ResourceManager.loadImage("images/tag_blue.png"); - private static final Icon UNDO_ICON = ResourceManager.loadImage("images/undo-apply.png"); + new GIcon("icon.version.tracking.tag.status.deleted"); + private static final Icon EXISTING_TAG_ICON = + new GIcon("icon.version.tracking.tag.status.existing"); + private static final Icon UNDO_ICON = new GIcon("icon.version.tracking.tag.button.undo"); private final JList list; private final TagStateListModel listModel; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AbstractAddressRangeFilter.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AbstractAddressRangeFilter.java index 5474428836..ea095b9100 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AbstractAddressRangeFilter.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/AbstractAddressRangeFilter.java @@ -30,11 +30,14 @@ import docking.widgets.combobox.GhidraComboBox; import docking.widgets.label.GDLabel; import docking.widgets.label.GHtmlLabel; import docking.widgets.textfield.HexIntegerFormatter; +import generic.theme.GColor; import ghidra.feature.vt.api.main.VTAssociation; import ghidra.feature.vt.gui.provider.matchtable.NumberRangeProducer; import ghidra.feature.vt.gui.provider.matchtable.NumberRangeSubFilterChecker; import ghidra.framework.options.SaveState; import ghidra.program.model.address.Address; +import ghidra.util.ColorUtils; +import ghidra.util.WebColors; public abstract class AbstractAddressRangeFilter extends AncillaryFilter implements NumberRangeSubFilterChecker, NumberRangeProducer { @@ -46,6 +49,8 @@ public abstract class AbstractAddressRangeFilter extends AncillaryFilter private static final String UPPER_RANGE_SELECTED_VALUE_KEY = "upper.range.selected.value.key"; private static final String IS_ENABLED_VALUE_KEY = "is.enabled.value.key"; + private static final Color FG_TOOLTIP_DEFAULT = new GColor("color.fg.version.tracking.tooltip"); + private static final Integer BASE_COMPONENT_LAYER = 1; private static final Integer HOVER_COMPONENT_LAYER = 2; private static final Integer DISABLED_COMPONENT_LAYER = 3; @@ -118,8 +123,10 @@ public abstract class AbstractAddressRangeFilter extends AncillaryFilter // // Lower Score Panel // + String fgColor = WebColors.toString(FG_TOOLTIP_DEFAULT); lowerRangePanel = new JPanel(new GridLayout(2, 1)); - JLabel lowLabel = new GHtmlLabel("low"); + JLabel lowLabel = + new GHtmlLabel("low"); lowLabel.setHorizontalAlignment(SwingConstants.CENTER); lowLabel.setVerticalAlignment(SwingConstants.BOTTOM); lowerRangePanel.add(lowLabel); @@ -138,7 +145,8 @@ public abstract class AbstractAddressRangeFilter extends AncillaryFilter // Upper Score Panel // upperRangePanel = new JPanel(new GridLayout(2, 1)); - JLabel upperLabel = new GHtmlLabel("high"); + JLabel upperLabel = + new GHtmlLabel("high"); upperLabel.setHorizontalAlignment(SwingConstants.CENTER); upperLabel.setVerticalAlignment(SwingConstants.BOTTOM); upperRangePanel.add(upperLabel); @@ -201,7 +209,7 @@ public abstract class AbstractAddressRangeFilter extends AncillaryFilter @Override protected void paintComponent(Graphics g) { Color bg = getBackground(); - Color disabledColor = new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), 100); + Color disabledColor = ColorUtils.withAlpha(bg, 100); g.setColor(disabledColor); g.fillRect(0, 0, getWidth(), getHeight()); } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/Filter.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/Filter.java index 732f53ddf9..32c3b177b3 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/Filter.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/Filter.java @@ -22,9 +22,9 @@ import java.util.Set; import javax.swing.Icon; import javax.swing.JComponent; +import generic.theme.GIcon; import ghidra.framework.options.SaveState; import ghidra.util.exception.AssertException; -import resources.ResourceManager; /** * An interface to allow clients to provide a mechanism for filtering objects and to notify @@ -74,10 +74,11 @@ public abstract class Filter { public enum FilterEditingStatus { NONE("", null), - DIRTY("Filter contents have changed, but are not yet applied", ResourceManager.loadImage( - "images/bullet_black.png")), - ERROR("Filter contents are not valid", ResourceManager.loadImage("images/no_small.png")), - APPLIED("Filter applied", ResourceManager.loadImage("images/bullet_green.png")); + DIRTY("Filter contents have changed, but are not yet applied", new GIcon( + "icon.version.tracking.filter.status.changed")), + ERROR("Filter contents are not valid", new GIcon( + "icon.version.tracking.filter.status.invalid")), + APPLIED("Filter applied", new GIcon("icon.version.tracking.filter.status.applied")); private final String description; private final Icon icon; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/FilterFormattedTextField.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/FilterFormattedTextField.java index bdcf2965dd..499bf810bd 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/FilterFormattedTextField.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/filters/FilterFormattedTextField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +15,10 @@ */ package ghidra.feature.vt.gui.filters; -import static ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus.APPLIED; -import static ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus.NONE; -import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus; -import ghidra.util.SystemUtilities; +import static ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus.*; import java.awt.Color; import java.awt.event.FocusEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.text.ParseException; import java.util.HashSet; import java.util.Set; @@ -33,12 +27,18 @@ import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -public class FilterFormattedTextField extends JFormattedTextField { - private static final Color ERROR_BACKGROUND_COLOR = new Color(218, 217, 206); - private static final String TEXT_FIELD_BACKGROUND_COLOR_KEY = "TextField.background"; - protected static final Color EDITING_BACKGROUND_COLOR = new Color(243, 242, 131); +import generic.theme.GColor; +import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus; +import ghidra.util.SystemUtilities; - private Set listeners = new HashSet(); +public class FilterFormattedTextField extends JFormattedTextField { + private static final Color ERROR_BACKGROUND_COLOR = + new GColor("color.bg.version.tracking.filter.formatted.field.error"); + protected static final Color EDITING_BACKGROUND_COLOR = + new GColor("color.bg.version.tracking.filter.formatted.field.editing"); + private static final String TEXT_FIELD_BACKGROUND_COLOR_KEY = "TextField.background"; + + private Set listeners = new HashSet<>(); private FilterEditingStatus currentStatus = NONE; private final Object defaultValue; @@ -57,24 +57,23 @@ public class FilterFormattedTextField extends JFormattedTextField { this.currentStatus = NONE; getDocument().addDocumentListener(new DocumentListener() { + @Override public void removeUpdate(DocumentEvent e) { updateText(); } + @Override public void insertUpdate(DocumentEvent e) { updateText(); } + @Override public void changedUpdate(DocumentEvent e) { updateText(); } }); - addPropertyChangeListener("value", new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - editingFinished(); - } - }); + addPropertyChangeListener("value", evt -> editingFinished()); } public void disableFocusEventProcessing() { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java index 320e025640..62c1a94e02 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTPlugin.java @@ -19,11 +19,13 @@ import java.net.URL; import java.util.List; import java.util.Set; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.JFrame; import docking.action.DockingActionIf; import docking.tool.ToolConstants; import docking.wizard.WizardManager; +import generic.theme.GIcon; import ghidra.GhidraOptions; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.colorizer.ColorizingService; @@ -48,9 +50,7 @@ import ghidra.program.util.ProgramLocation; import ghidra.util.*; import help.Help; import help.HelpService; -import resources.MultiIcon; import resources.ResourceManager; -import resources.icons.*; //@formatter:off @PluginInfo( @@ -80,25 +80,10 @@ public class VTPlugin extends Plugin { public static final String UNEDIT_MENU_GROUP = "A_VT_UnEdit"; public static final String VT_SETTINGS_MENU_GROUP = "ZZ_VT_SETTINGS"; - public static final Icon UNFILTERED_ICON = - ResourceManager.loadImage("images/lightbulb_off.png"); - public static final Icon FILTERED_ICON = ResourceManager.loadImage("images/lightbulb.png"); - public static final Icon REPLACED_ICON = ResourceManager.loadImage("images/sync_enabled.png"); - public static final Icon UNIGNORED_ICON = new IconWrapper() { - @Override - protected Icon createIcon() { - MultiIcon icon = new MultiIcon(new EmptyIcon(16, 16)); - ImageIcon cancelIcon = ResourceManager.loadImage("images/dialog-cancel.png"); - ScaledImageIcon scaledCancelIcon = - new ScaledImageIcon(cancelIcon, 13, 13); - TranslateIcon translatedCancelIcon = new TranslateIcon(scaledCancelIcon, 3, 4); - ImageIcon undoIcon = ResourceManager.loadImage("images/undo.png"); - TranslateIcon translatedUndoIcon = new TranslateIcon(undoIcon, 0, -4); - icon.addIcon(translatedUndoIcon); - icon.addIcon(translatedCancelIcon); - return icon; - } - }; + public static final Icon UNFILTERED_ICON = new GIcon("icon.version.tracking.unfiltered"); + public static final Icon FILTERED_ICON = new GIcon("icon.version.tracking.filtered"); + public static final Icon REPLACED_ICON = new GIcon("icon.version.tracking.replaced"); + public static final Icon UNIGNORED_ICON = new GIcon("icon.version.tracking.unignored"); private VTController controller; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VersionTrackingPluginPackage.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VersionTrackingPluginPackage.java index 5c145b0f1e..7007883487 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VersionTrackingPluginPackage.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VersionTrackingPluginPackage.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +15,18 @@ */ package ghidra.feature.vt.gui.plugin; -import ghidra.framework.plugintool.util.PluginPackage; - import javax.swing.Icon; -import resources.ResourceManager; +import generic.theme.GIcon; +import ghidra.framework.plugintool.util.PluginPackage; public class VersionTrackingPluginPackage extends PluginPackage { public static final String NAME = "Version Tracking"; - public static final Icon ICON = ResourceManager.loadImage("images/start-here.png"); - + public static final Icon ICON = new GIcon("icon.version.tracking.package"); + public VersionTrackingPluginPackage() { - super(NAME, ICON, - "These plugins provide feature for performing version tracking between programs." ); + super(NAME, ICON, + "These plugins provide feature for performing version tracking between programs."); } } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java index a05c432e0f..535fc4160c 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java @@ -37,6 +37,8 @@ import docking.widgets.EventTrigger; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.label.GDLabel; import docking.widgets.table.threaded.ThreadedTableModel; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.app.plugin.core.functioncompare.FunctionComparisonPanel; import ghidra.app.services.GoToService; import ghidra.app.util.viewer.listingpanel.ListingCodeComparisonPanel; @@ -60,7 +62,6 @@ import ghidra.util.HelpLocation; import ghidra.util.SystemUtilities; import ghidra.util.table.*; import resources.Icons; -import resources.ResourceManager; /** * Provider for the version tracking function association table. @@ -70,15 +71,16 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter private static final String FILTER_SETTINGS_KEY = "FUNCTION_FILTER_SETTINGS"; private static final String BASE_TITLE = "Version Tracking Functions"; - private static final ImageIcon PROVIDER_ICON = - ResourceManager.loadImage("images/functions.gif"); + private static final Icon PROVIDER_ICON = new GIcon("icon.version.tracking.provider.function"); private static final String SOURCE_TITLE = "Source"; private static final String DESTINATION_TITLE = "Destination"; private static final String NO_SESSION = "None"; private static final Icon SHOW_LISTINGS_ICON = - ResourceManager.loadImage("images/application_tile_horizontal.png"); + new GIcon("icon.version.tracking.action.show.listings"); private static final String SHOW_COMPARE_ACTION_GROUP = "A9_ShowCompare"; // "A9_" forces to right of other dual view actions in toolbar. + private static final Color FG_ERROR = new GColor("color.fg.error"); + private GhidraTable sourceFunctionsTable; private GhidraTable destinationFunctionsTable; private VTFunctionAssociationTableModel sourceFunctionsModel; @@ -155,13 +157,13 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter filterAction.setHelpLocation(new HelpLocation("VersionTrackingPlugin", "Functions_Filter")); - Icon allFunctionsIcon = ResourceManager.loadImage("images/function.png"); + Icon allFunctionsIcon = new GIcon("icon.version.tracking.function.filter.all"); ActionState allFunctionsActionState = new ActionState<>("Show All Functions", allFunctionsIcon, SHOW_ALL); allFunctionsActionState.setHelpLocation( new HelpLocation("VersionTrackingPlugin", "Show_All_Functions")); - Icon unmatchedIcon = ResourceManager.loadImage("images/filter_matched.png"); + Icon unmatchedIcon = new GIcon("icon.version.tracking.function.filter.unmatched"); ActionState unmatchedOnlyActionState = new ActionState<>("Show Only Unmatched Functions", unmatchedIcon, SHOW_UNMATCHED); unmatchedOnlyActionState.setHelpLocation( @@ -358,7 +360,7 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter JPanel statusPanel = new JPanel(new BorderLayout()); statusLabel = new GDLabel(NO_ERROR_MESSAGE); statusLabel.setHorizontalAlignment(SwingConstants.CENTER); - statusLabel.setForeground(Color.RED.darker()); + statusLabel.setForeground(FG_ERROR); statusLabel.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java index a2c0625018..51ee6a9699 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java @@ -30,6 +30,7 @@ import docking.action.*; import docking.widgets.table.GTable; import docking.widgets.table.RowObjectTableModel; import docking.widgets.table.threaded.GThreadedTablePanel; +import generic.theme.GIcon; import ghidra.feature.vt.api.db.DeletedMatch; import ghidra.feature.vt.api.impl.VTChangeManager; import ghidra.feature.vt.api.impl.VersionTrackingChangeRecord; @@ -47,7 +48,6 @@ import ghidra.util.HelpLocation; import ghidra.util.table.GhidraTableFilterPanel; import ghidra.util.table.GhidraThreadedTablePanel; import resources.Icons; -import resources.ResourceManager; public class VTImpliedMatchesTableProvider extends ComponentProviderAdapter implements VTControllerListener { @@ -70,7 +70,7 @@ public class VTImpliedMatchesTableProvider extends ComponentProviderAdapter this.controller = controller; controller.addListener(this); setWindowGroup(VTPlugin.WINDOW_GROUP); - setIcon(ResourceManager.loadImage("images/application_view_detail.png")); + setIcon(new GIcon("icon.version.tracking.provider.implied.match")); setDefaultWindowPosition(WindowPosition.BOTTOM); setIntraGroupPosition(WindowPosition.STACK); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/MarkupItemStatusRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/MarkupItemStatusRenderer.java index 6f310bb115..64dbd4909d 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/MarkupItemStatusRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/MarkupItemStatusRenderer.java @@ -100,7 +100,7 @@ public class MarkupItemStatusRenderer extends AbstractGhidraColumnRenderer> allFilters = new ArrayList<>(); private final VTController controller; @@ -336,7 +344,7 @@ public class VTMarkupItemsTableModel extends AddressBasedTableModel { - private static ImageIcon DISABLED_ICON = - ResourceManager.getDisabledIcon(ResourceManager.loadImage("images/ledgreen.png"), 50); - private static final ImageIcon APPLIED_BASE_ICON = - ResourceManager.loadImage("images/ledgreen.png", 8, 8); - private static final ImageIcon REJECTED_BASE_ICON = - ResourceManager.loadImage("images/ledpurple.png", 8, 8); - private static final ImageIcon NOT_APPLIED_BASE_ICON = - ResourceManager.loadImage("images/ledorange.png", 8, 8); - private static final ImageIcon IGNORED_BASE_ICON = - ResourceManager.loadImage("images/ledblue.png", 8, 8); - private static final ImageIcon ERROR_BASE_ICON = - ResourceManager.loadImage("images/ledred.png", 8, 8); + private static final Color FG_TOOLTIP_DEFAULT = new GColor("color.fg.version.tracking.tooltip"); + private static final Color FG_TOOLTIP_UNEXAMINED = + new GColor("color.bg.version.tracking.match.table.markup.status.tooltip.unexamined"); - private static Icon NOT_APPLIED_ICON = new TranslateIcon(NOT_APPLIED_BASE_ICON, 0, 4); - private static Icon APPLIED_ICON = new TranslateIcon(APPLIED_BASE_ICON, 9, 4); - private static Icon REJECTED_ICON = new TranslateIcon(REJECTED_BASE_ICON, 18, 4); - private static Icon IGNORED_ICON = new TranslateIcon(IGNORED_BASE_ICON, 27, 4); - private static Icon ERROR_ICON = new TranslateIcon(ERROR_BASE_ICON, 36, 4); + private static Icon EMPTY_ICON = new GIcon("icon.empty"); + private static Icon DISABLED_ICOL = + new GIcon("icon.version.tracking.match.table.markup.status.disabled"); + private static final Icon NOT_APPLIED_ICON = + new GIcon("icon.version.tracking.match.table.markup.status.not.applied"); + private static final Icon APPLIED_ICON = + new GIcon("icon.version.tracking.match.table.markup.status.applied"); + private static final Icon REJECTED_ICON = + new GIcon("icon.version.tracking.match.table.markup.status.rejected"); + private static final Icon IGNORED_ICON = + new GIcon("icon.version.tracking.match.table.markup.status.ignored"); + private static final Icon ERROR_ICON = + new GIcon("icon.version.tracking.match.table.markup.status.error"); - private static Icon DISABLED_NOT_APPLIED_ICON = new TranslateIcon(DISABLED_ICON, 0, 4); - private static Icon DISABLED_APPLIED_ICON = new TranslateIcon(DISABLED_ICON, 9, 4); - private static Icon DISABLED_REJECTED_ICON = new TranslateIcon(DISABLED_ICON, 18, 4); - private static Icon DISABLED_IGNORED_ICON = new TranslateIcon(DISABLED_ICON, 27, 4); - private static Icon DISABLED_ERROR_ICON = new TranslateIcon(DISABLED_ICON, 36, 4); + private static Icon DISABLED_NOT_APPLIED_ICON = new TranslateIcon(DISABLED_ICOL, 0, 4); + private static Icon DISABLED_APPLIED_ICON = new TranslateIcon(DISABLED_ICOL, 9, 4); + private static Icon DISABLED_REJECTED_ICON = new TranslateIcon(DISABLED_ICOL, 18, 4); + private static Icon DISABLED_IGNORED_ICON = new TranslateIcon(DISABLED_ICOL, 27, 4); + private static Icon DISABLED_ERROR_ICON = new TranslateIcon(DISABLED_ICOL, 36, 4); @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { @@ -81,7 +83,7 @@ public class MatchMarkupStatusRenderer extends AbstractGhidraColumnRenderer"); - if (!status.isInitialized()) { buf.append("Match has not been accepted; unknown markup status"); return buf.toString(); } - ImageIcon icon = DISABLED_ICON; + Icon icon = EMPTY_ICON; String message = "Has one or more \"Unexamined\" markup items"; - String fontColor = "gray"; + Color color = FG_TOOLTIP_DEFAULT; if (status.hasUnexaminedMarkup()) { - icon = NOT_APPLIED_BASE_ICON; - fontColor = "black"; + icon = NOT_APPLIED_ICON; + color = FG_TOOLTIP_UNEXAMINED; } - buf.append(""); + + String fontColor = WebColors.toString(color, false); + buf.append(""); buf.append(""); buf.append(message).append("
"); - icon = DISABLED_ICON; + icon = EMPTY_ICON; + message = "Has one or more \"Applied\" markup items"; fontColor = "gray"; if (status.hasAppliedMarkup()) { - icon = APPLIED_BASE_ICON; + icon = APPLIED_ICON; fontColor = "black"; } - buf.append(""); + buf.append(""); buf.append(""); buf.append(message).append("
"); - icon = DISABLED_ICON; + icon = EMPTY_ICON; + message = "Has one or more \"Rejected\" markup items to apply"; fontColor = "gray"; if (status.hasRejectedMarkup()) { - icon = REJECTED_BASE_ICON; + icon = REJECTED_ICON; fontColor = "black"; } - buf.append(""); + buf.append(""); buf.append(""); buf.append(message).append("
"); - icon = DISABLED_ICON; + icon = EMPTY_ICON; message = "Has one or more \"Ignored (Don't Know or Don't Care)\" markup items"; fontColor = "gray"; if (status.hasDontCareMarkup() || status.hasDontKnowMarkup()) { - icon = IGNORED_BASE_ICON; + icon = IGNORED_ICON; fontColor = "black"; } - buf.append(""); + buf.append(""); buf.append(""); buf.append(message).append("
"); - icon = DISABLED_ICON; + icon = EMPTY_ICON; message = "Has one or more \"Error\" markup items"; fontColor = "gray"; if (status.hasErrors()) { - icon = ERROR_BASE_ICON; + icon = ERROR_ICON; fontColor = "black"; } - buf.append(""); + buf.append(""); buf.append(""); buf.append(message).append("
"); return buf.toString(); } + private String getIconSource(Icon icon) { + if (icon instanceof GIcon gIcon) { + URL url = gIcon.getUrl(); + if (url != null) { + return url.toString(); + } + } + else if (icon instanceof UrlImageIcon urlIcon) { + return urlIcon.getUrl().toString(); + } + return ""; + } + @Override public String getFilterString(VTMatch t, Settings settings) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MatchTableRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MatchTableRenderer.java index 88ba481fd4..9f12a5edd3 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MatchTableRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MatchTableRenderer.java @@ -21,11 +21,13 @@ import java.awt.Component; import javax.swing.JTable; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GColor; import ghidra.feature.vt.api.main.*; import ghidra.util.table.CompositeGhidraTableCellRenderer; public class MatchTableRenderer extends CompositeGhidraTableCellRenderer { - private static final Color LOCKED_OUT_BACKGROUND_COLOR = new Color(239, 239, 239); + private static final Color LOCKED_OUT_BACKGROUND_COLOR = + new GColor("color.bg.version.tracking.match.table.locked.out"); @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MultipleLabelsRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MultipleLabelsRenderer.java index fc1591b538..b4f081cc56 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MultipleLabelsRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/MultipleLabelsRenderer.java @@ -20,12 +20,12 @@ import java.awt.Component; import javax.swing.*; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GIcon; import ghidra.docking.settings.Settings; import ghidra.program.model.symbol.Symbol; import ghidra.util.HTMLUtilities; import ghidra.util.exception.AssertException; import ghidra.util.table.column.AbstractGhidraColumnRenderer; -import resources.ResourceManager; /** * This class provides a field renderer for version tracking tables. It is used for indicating @@ -60,7 +60,7 @@ public class MultipleLabelsRenderer extends AbstractGhidraColumnRenderer getColors(VTAssociationMarkupStatus status) { - Color ORANGE = new Color(255, 150, 0); - Color GREEN = new Color(0, 180, 0); - Color BLUE = new Color(80, 80, 240); - List list = new ArrayList(4); - if (status.hasRejectedMarkup()) { - list.add(Color.RED); + private List getColors(VTAssociationMarkupStatus markupStatus) { + + List list = new ArrayList<>(4); + if (markupStatus.hasRejectedMarkup()) { + list.add(BG_REJECTED); } - if (status.hasAppliedMarkup() || status.isFullyApplied()) { - list.add(GREEN); + if (markupStatus.hasAppliedMarkup() || markupStatus.isFullyApplied()) { + list.add(BG_APPLIED); } - if (status.hasDontCareMarkup()) { - list.add(BLUE); + if (markupStatus.hasDontCareMarkup()) { + list.add(BG_DONT_CARE); } - if (status.hasDontKnowMarkup()) { - list.add(ORANGE); + if (markupStatus.hasDontKnowMarkup()) { + list.add(BG_DONT_KNOW); } return list; } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchApplySettingsAction.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchApplySettingsAction.java index 915725cb74..bcd861449f 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchApplySettingsAction.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchApplySettingsAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +15,22 @@ */ package ghidra.feature.vt.gui.provider.matchtable; +import javax.swing.Icon; + +import docking.ActionContext; +import docking.action.*; +import generic.theme.GIcon; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.util.OptionsService; import ghidra.util.HelpLocation; -import javax.swing.Icon; - -import resources.ResourceManager; -import docking.ActionContext; -import docking.action.*; - public class VTMatchApplySettingsAction extends DockingAction { public static final String VERSION_TRACKING_OPTIONS_NAME = "Version Tracking"; public static final String VERSION_TRACKING_APPLY_MARKUP_OPTIONS = "Apply Markup Options"; - static final Icon ICON = ResourceManager.loadImage("images/settings16.gif"); + static final Icon ICON = new GIcon("icon.version.tracking.action.show.settings"); private static final String MENU_GROUP = VTPlugin.VT_SETTINGS_MENU_GROUP; private static final String TITLE = "Version Tracking Options"; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchOneToManyTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchOneToManyTableProvider.java index 754c333c5e..b68fa810dc 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchOneToManyTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchOneToManyTableProvider.java @@ -30,6 +30,8 @@ import docking.widgets.label.GDLabel; import docking.widgets.table.GTable; import docking.widgets.table.RowObjectTableModel; import docking.widgets.table.threaded.ThreadedTableModel; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.feature.vt.api.impl.VTChangeManager; import ghidra.feature.vt.api.main.*; import ghidra.feature.vt.gui.actions.*; @@ -54,7 +56,6 @@ import ghidra.util.SystemUtilities; import ghidra.util.layout.HorizontalLayout; import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraThreadedTablePanel; -import resources.ResourceManager; /** * The docking window that provides a table of the other tool's function matches for the function @@ -64,9 +65,10 @@ public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAda implements FilterDialogModel, VTControllerListener, VTSubToolManagerListener { private static final String TITLE_PREFIX = "Version Tracking Matches for "; - private static final Icon ICON = ResourceManager.loadImage("images/text_list_bullets.png"); + private static final Icon ICON = new GIcon("icon.version.tracking.provider.one.to.many"); - protected static final Color LOCAL_INFO_FOREGROUND_COLOR = new Color(0, 128, 0); + protected static final Color LOCAL_INFO_FOREGROUND_COLOR = + new GColor("color.fg.version.tracking.function.match.local.info"); private JComponent component; private MatchThreadedTablePanel tablePanel; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/RelatedMatchRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/RelatedMatchRenderer.java index 458569aab5..927d2a5cdd 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/RelatedMatchRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/RelatedMatchRenderer.java @@ -23,23 +23,32 @@ import javax.swing.*; import docking.widgets.label.GIconLabel; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTAssociationStatus; import ghidra.util.table.GhidraTableCellRenderer; -import resources.ResourceManager; public class RelatedMatchRenderer extends GhidraTableCellRenderer { + + private static final Color GOOD = + new GColor("color.bg.version.tracking.related.matches.table.good"); + private static final Color MEDIUM = + new GColor("color.bg.version.tracking.related.matches.table.medium"); + private static final Color BAD = + new GColor("color.bg.version.tracking.related.matches.table.bad"); + static Map sourceMap; static Map destinationMap; static Map statusMap; - static final Icon TARGET_ICON = ResourceManager.loadImage("images/user-online.png"); - static final Icon CALLER_ICON = ResourceManager.loadImage("images/go-down.png"); - static final Icon CALLEE_ICON = ResourceManager.loadImage("images/go-next.png"); - static final Icon UNRELATED_ICON = ResourceManager.loadImage("images/user-busy.png"); + static final Icon TARGET_ICON = new GIcon("icon.version.tracking.related.match.target"); + static final Icon CALLER_ICON = new GIcon("icon.version.tracking.related.match.caller"); + static final Icon CALLEE_ICON = new GIcon("icon.version.tracking.related.match.callee"); + static final Icon UNRELATED_ICON = new GIcon("icon.version.tracking.related.match.unrelated"); - static final Icon ACCEPTED_ICON = ResourceManager.loadImage("images/accept.png"); - static final Icon AVAILABLE_ICON = ResourceManager.loadImage("images/media-playback-stop.png"); - static final Icon LOCKED_OUT_ICON = ResourceManager.loadImage("images/edit-delete.png"); + static final Icon ACCEPTED_ICON = new GIcon("icon.version.tracking.related.match.accepted"); + static final Icon AVAILABLE_ICON = new GIcon("icon.version.tracking.related.match.available"); + static final Icon LOCKED_OUT_ICON = new GIcon("icon.version.tracking.related.match.locked.out"); private JPanel relatedMatchColumnComponent; private GridLayout layout; @@ -99,10 +108,6 @@ public class RelatedMatchRenderer extends GhidraTableCellRenderer { return renderer; } - private static final Color GOOD = Color.green; - private static final Color MEDIUM = Color.yellow; - private static final Color BAD = Color.red; - private Color findBackgroundColor(VTRelatedMatchType value) { double goodness = value.getGoodness() / 100.0; double badness = 1.0 - goodness; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/VTRelatedMatchesTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/VTRelatedMatchesTableProvider.java index 9b2c024417..4e8a90ea51 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/VTRelatedMatchesTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/relatedMatches/VTRelatedMatchesTableProvider.java @@ -29,17 +29,17 @@ import docking.ActionContext; import docking.widgets.table.GTable; import docking.widgets.table.RowObjectTableModel; import docking.widgets.table.threaded.ThreadedTableModel; +import generic.theme.GIcon; import ghidra.feature.vt.api.util.VTRelatedMatch; import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.PluginTool; import ghidra.util.table.*; -import resources.ResourceManager; public class VTRelatedMatchesTableProvider extends ComponentProviderAdapter { - private static final Icon ICON = ResourceManager.loadImage("images/user-online.png"); + private static final Icon ICON = new GIcon("icon.version.tracking.provider.related.matches"); private JComponent component; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java index adb8b489a7..ee43ba8ad0 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java @@ -27,6 +27,7 @@ import javax.swing.JLabel; import docking.widgets.table.GTableCellRenderingData; import docking.widgets.table.TableFilter; +import generic.theme.GColor; import ghidra.app.util.SymbolInspector; import ghidra.docking.settings.Settings; import ghidra.feature.vt.api.impl.VTProgramCorrelatorInfo; @@ -56,6 +57,8 @@ public abstract class AbstractVTMatchTableModel extends AddressBasedTableModel markupStatusColumnComparator = new MarkupStatusColumnComparator(); protected VTSession session; + private static final Color FG_ERROR = new GColor("color.fg.version.tracking.match.table.error"); + private Set> allFilters = new HashSet<>(); protected final VTController controller; @@ -589,7 +592,7 @@ public abstract class AbstractVTMatchTableModel extends AddressBasedTableModel extends Timer implements ActionListener { - private static final Icon EMPTY_ICON = ResourceManager.loadImage("images/EmptyIcon16.gif"); + private static final Icon EMPTY_ICON = new GIcon("icon.version.tracking.empty"); private static final long MINIMUM_TIME_BETWEEN_FLASHES = 20000; private static final int MAX_FLASH_COUNT = 10; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/MatchStatusRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/MatchStatusRenderer.java index 9ec0dbf8a9..756e2acb14 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/MatchStatusRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/MatchStatusRenderer.java @@ -21,32 +21,23 @@ import javax.swing.Icon; import javax.swing.JLabel; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GIcon; import ghidra.util.table.GhidraTableCellRenderer; -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.TranslateIcon; public class MatchStatusRenderer extends GhidraTableCellRenderer { -// private static final Icon DISABLED_APPLIED_ICON = -// ResourceManager.getDisabledIcon(ResourceManager.loadImage("images/flag.png")); - private static final Icon ACCEPTED_ICON = ResourceManager.loadImage("images/flag.png"); - private static final Icon REJECTED_ICON = ResourceManager.loadImage("images/dialog-cancel.png"); -// private static final Icon REJECTED_ICON = ResourceManager.loadImage("images/delete.png"); - private static final Icon BLOCKED_ICON = ResourceManager.loadImage("images/kgpg.png"); - -// private static final ImageIcon LOCK_ICON = -// ResourceManager.loadImage("images/lock.png"); - - private static final Icon WARN_ICON = new TranslateIcon( - ResourceManager.loadImage("images/bullet_error.png"), 10, 8); - private static final Icon FAILURE_ICON = new TranslateIcon(ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/edit-delete.png"), 8, 8), 10, 8); - private static final Icon FULLY_APPLIED_ICON = new TranslateIcon(ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/checkmark_green.gif"), 8, 8), 10, 8); - private static final Icon FULLY_CONSIDERED_ICON = new TranslateIcon( - ResourceManager.getScaledIcon(ResourceManager.loadImage("images/checkmark_yellow.gif"), 8, - 8), 10, 8); + private static final Icon ACCEPTED_SOME_UNEXAMINED_ICON = + new GIcon("icon.version.tracking.match.table.status.accepted.some.unexamined"); + private static final Icon ACCEPTED_ERROR_ICON = + new GIcon("icon.version.tracking.match.table.status.accepted.error"); + private static final Icon ACCEPTED_FULLY_APPLIED_ICON = + new GIcon("icon.version.tracking.match.table.status.accepted.fully.applied"); + private static final Icon ACCEPTED_FULLY_CONSIDERED_ICON = + new GIcon("icon.version.tracking.match.table.status.accepted.fully.considered"); + private static final Icon REJECTED_ICON = + new GIcon("icon.version.tracking.match.table.status.rejected"); + private static final Icon BLOCKED_ICON = + new GIcon("icon.version.tracking.match.table.status.blocked"); @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { @@ -74,16 +65,16 @@ public class MatchStatusRenderer extends GhidraTableCellRenderer { Icon icon = null; switch (status) { case ACCEPTED_FULLY_APPLIED: - icon = new MultiIcon(ACCEPTED_ICON, FULLY_APPLIED_ICON); + icon = ACCEPTED_FULLY_APPLIED_ICON; break; case ACCEPTED_HAS_ERRORS: - icon = new MultiIcon(ACCEPTED_ICON, FAILURE_ICON); + icon = ACCEPTED_ERROR_ICON; break; case ACCEPTED_NO_UNEXAMINED: - icon = new MultiIcon(ACCEPTED_ICON, FULLY_CONSIDERED_ICON); + icon = ACCEPTED_FULLY_CONSIDERED_ICON; break; case ACCEPTED_SOME_UNEXAMINED: - icon = new MultiIcon(ACCEPTED_ICON, WARN_ICON); + icon = ACCEPTED_SOME_UNEXAMINED_ICON; break; case AVAILABLE: // no icon diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/VTSymbolRenderer.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/VTSymbolRenderer.java index 0ee30ef127..44627b8f85 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/VTSymbolRenderer.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/VTSymbolRenderer.java @@ -21,6 +21,7 @@ import java.awt.Component; import javax.swing.JComponent; import docking.widgets.table.GTableCellRenderingData; +import generic.theme.GThemeDefaults.Colors; import ghidra.app.util.SymbolInspector; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.symbol.Symbol; @@ -49,7 +50,7 @@ public class VTSymbolRenderer extends GhidraTableCellRenderer { private void handleSymbol(Object value, boolean isSelected) { setBold(); if (!isSelected) { - Color color = Color.BLACK; + Color color = Colors.FOREGROUND; if (value instanceof Symbol) { Symbol s = (Symbol) value; inspector.setProgram(s.getProgram()); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/ChooseAddressSetEditorPanel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/ChooseAddressSetEditorPanel.java index 38dc9bdc3e..16a79b9ab4 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/ChooseAddressSetEditorPanel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/ChooseAddressSetEditorPanel.java @@ -27,12 +27,12 @@ import javax.swing.event.*; import docking.widgets.button.GRadioButton; import docking.widgets.label.GLabel; import docking.widgets.list.GList; +import generic.theme.GIcon; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.util.layout.MiddleLayout; import ghidra.util.layout.VerticalLayout; -import resources.ResourceManager; public class ChooseAddressSetEditorPanel extends JPanel { @@ -40,8 +40,8 @@ public class ChooseAddressSetEditorPanel extends JPanel { ENTIRE_PROGRAM, SELECTION, MANUALLY_DEFINED } - private static Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png"); - private static Icon SUBTRACT_ICON = ResourceManager.loadImage("images/list-remove.png"); + private static Icon ADD_ICON = new GIcon("icon.version.tracking.add"); + private static Icon SUBTRACT_ICON = new GIcon("icon.version.tracking.subtract"); private PluginTool tool; private final String name; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/NewSessionPanel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/NewSessionPanel.java index eb6bb77534..a0b69e6f8c 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/NewSessionPanel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/NewSessionPanel.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils; import docking.options.editor.ButtonPanelFactory; import docking.widgets.label.GDLabel; import docking.wizard.*; +import generic.theme.*; import ghidra.app.util.task.OpenProgramTask; import ghidra.framework.main.DataTreeDialog; import ghidra.framework.model.DomainFile; @@ -36,7 +37,6 @@ import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; import ghidra.util.InvalidNameException; import ghidra.util.task.TaskLauncher; -import resources.ResourceManager; /** * Version tracking wizard panel to create a new session. @@ -44,8 +44,8 @@ import resources.ResourceManager; public class NewSessionPanel extends AbstractMageJPanel { private static final int MAX_LENGTH_FOR_VT_SESSION_NAME = 20; - private static final Icon SWAP_ICON = ResourceManager.loadImage("images/doubleArrowUpDown.png"); - private static final Icon INFO_ICON = ResourceManager.loadImage("images/information.png"); + private static final Icon SWAP_ICON = new GIcon("icon.version.tracking.new.session.swap"); + private static final Icon INFO_ICON = new GIcon("icon.version.tracking.new.session.info"); private JTextField sourceField; private JTextField destinationField; @@ -73,14 +73,12 @@ public class NewSessionPanel extends AbstractMageJPanel { folderLabel.setHorizontalAlignment(SwingConstants.RIGHT); folderLabel.setToolTipText("The folder to store the new Version Tracking Session"); folderNameField = new JTextField(); - folderNameField.setFont(new Font("Monospaced", Font.PLAIN, 12)); + Gui.registerFont(folderNameField, GThemeDefaults.Ids.Fonts.MONOSPACED); folderNameField.setEditable(false); // force user to browse to choose JButton browseFolderButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE); browseFolderButton.addActionListener(e -> browseDataTreeFolders()); - Font font = browseFolderButton.getFont(); - browseFolderButton.setFont(new Font(font.getName(), Font.BOLD, font.getSize())); JLabel newSessionLabel = new GDLabel("New Session Name: "); newSessionLabel.setToolTipText("The name for the new Version Tracking Session"); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/VTProgramTableCorrelatorModel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/VTProgramTableCorrelatorModel.java index 573e22167d..a964855841 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/VTProgramTableCorrelatorModel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/wizard/VTProgramTableCorrelatorModel.java @@ -20,11 +20,11 @@ import java.util.*; import javax.swing.Icon; import docking.widgets.table.AbstractGTableModel; +import generic.theme.GIcon; import ghidra.feature.vt.api.main.VTProgramCorrelatorFactory; import ghidra.feature.vt.api.util.VTAbstractProgramCorrelatorFactory; import ghidra.util.classfinder.ClassSearcher; import ghidra.util.exception.AssertException; -import resources.ResourceManager; public class VTProgramTableCorrelatorModel extends AbstractGTableModel { @@ -40,7 +40,8 @@ public class VTProgramTableCorrelatorModel extends AbstractGTableModel list; private Set previouslyRunCorrelators; diff --git a/Ghidra/Framework/Docking/Module.manifest b/Ghidra/Framework/Docking/Module.manifest index e69de29bb2..139597f9cb 100644 --- a/Ghidra/Framework/Docking/Module.manifest +++ b/Ghidra/Framework/Docking/Module.manifest @@ -0,0 +1,2 @@ + + diff --git a/Ghidra/Framework/Docking/build.gradle b/Ghidra/Framework/Docking/build.gradle index 139ec36c1f..4cc5963654 100644 --- a/Ghidra/Framework/Docking/build.gradle +++ b/Ghidra/Framework/Docking/build.gradle @@ -26,7 +26,6 @@ eclipse.project.name = 'Framework Docking' dependencies { api project(':Generic') api project(':Help') - // include code from src/test in Generic testImplementation project(path: ':Generic', configuration: 'testArtifacts') diff --git a/Ghidra/Framework/Docking/certification.manifest b/Ghidra/Framework/Docking/certification.manifest index 0c37be739f..bec96bb78a 100644 --- a/Ghidra/Framework/Docking/certification.manifest +++ b/Ghidra/Framework/Docking/certification.manifest @@ -9,25 +9,23 @@ ##MODULE IP: Tango Icons - Public Domain Module.manifest||GHIDRA||||END| 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/shared/arrow.gif||GHIDRA||||END| -src/main/help/help/shared/close16.gif||GHIDRA||||END| -src/main/help/help/shared/menu16.gif||GHIDRA||||END| -src/main/help/help/shared/note-red.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/help/help/shared/note.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/help/help/shared/note.yellow.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/help/help/shared/redo.png||GHIDRA||||END| -src/main/help/help/shared/tip.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/help/help/shared/undo.png||GHIDRA||||END| -src/main/help/help/shared/warning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| -src/main/help/help/topics/PlacheholderTopic/Placeholder.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| +src/main/help/help/topics/Theming/images/ThemeDialog.png||GHIDRA||||END| src/main/java/docking/dnd/package.html||GHIDRA||reviewed||END| 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| @@ -36,16 +34,16 @@ 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/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| src/main/resources/images/eatbits2.png||GHIDRA||reviewed||END| @@ -55,9 +53,9 @@ 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-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| 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| @@ -77,11 +75,11 @@ 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/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| src/main/resources/images/media-playback-start.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/menu16.gif||GHIDRA||reviewed||END| src/main/resources/images/note-red.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| @@ -92,24 +90,20 @@ src/main/resources/images/page_code.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/page_excel.png||FAMFAMFAM Icons - CC 2.5||||END| src/main/resources/images/page_go.png||FAMFAMFAM Icons - CC 2.5||||END| 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/redo.png||Crystal Clear Icons - LGPL 2.1||||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/undo.png||Crystal Clear Icons - LGPL 2.1||||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/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| @@ -120,6 +114,9 @@ src/main/resources/images/www_128.png||Nuvola Icons - LGPL 2.1|||nuvola www.png| src/main/resources/images/www_16.png||Nuvola Icons - LGPL 2.1|||nuvola www 16x16|END| src/main/resources/images/www_32.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| src/main/resources/images/www_64.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END| +src/main/resources/images/zoom.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| +src/main/resources/images/zoom_in.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| +src/main/resources/images/zoom_out.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| src/main/svg/images/StackFrameElement.svg||GHIDRA||reviewed||END| src/main/svg/images/StackFrame_Red.svg||GHIDRA||reviewed||END| src/main/svg/images/cause.svg||GHIDRA||reviewed||END| diff --git a/Ghidra/Framework/Docking/data/ExtensionPoint.manifest b/Ghidra/Framework/Docking/data/ExtensionPoint.manifest index a7001f5a80..a6370472eb 100644 --- a/Ghidra/Framework/Docking/data/ExtensionPoint.manifest +++ b/Ghidra/Framework/Docking/data/ExtensionPoint.manifest @@ -1,3 +1,4 @@ ColumnConstraintProvider TypeMapper TableColumn +Theme diff --git a/Ghidra/Framework/Docking/data/docking.palette.theme.properties b/Ghidra/Framework/Docking/data/docking.palette.theme.properties new file mode 100644 index 0000000000..06fa3048d3 --- /dev/null +++ b/Ghidra/Framework/Docking/data/docking.palette.theme.properties @@ -0,0 +1,84 @@ +[Defaults] + +color.palette.nocolor = rgba(255,255,255,0) +color.palette.disabled = rgba(255,255,255,0) + +color.palette.black = black +color.palette.blue = blue +color.palate.cornflowerblue = cornflowerblue +color.palate.cornsilk = cornsilk +color.palette.crimson = crimson +color.palette.cyan = cyan +color.palette.darkblue = DarkBlue +color.palette.darkgray = DarkGray +color.palette.darkgreen = darkgreen +color.palette.darkkhaki = DarkKhaki +color.palette.darkred = DarkRed +color.palette.darkslategray = darkslategray +color.palette.dodgerblue = DodgerBlue +color.palette.fuchsia = fuchsia +color.palette.gold = gold +color.palette.gray = gray +color.palette.green = green +color.palette.greenyellow = greenyellow +color.palette.indigo = indigo +color.palette.khaki = khaki +color.palette.lavender = lavender +color.palette.lime = lime +color.palette.lightcoral = lightcoral +color.palette.lightgray = rgb(192, 192, 192) +color.palette.lightgreen = rgb(127, 255, 127) +color.palette.lightpink = lightpink +color.palette.lightred = rgb(255, 127, 127) +color.palette.lightskyblue = lightskyblue +color.palette.lightsteelblue = lightsteelblue +color.palette.magenta = magenta +color.palette.maroon = maroon +color.palette.mistyrose = mistyrose +color.palette.navy = navy +color.palette.olive = olive +color.palette.orange = orange +color.palette.palegreen = palegreen +color.palette.palevioletred = PaleVioletRed +color.palette.peachpuff = peachpuff +color.palette.pink = pink +color.palette.purple = purple +color.palette.red = red +color.palette.silver = silver +color.palette.steelblue = steelblue +color.palette.tan = tan +color.palette.teal = teal +color.palette.yellow = yellow +color.palette.yellowgreen = yellowgreen +color.palette.white = white + + + +[Dark Defaults] + +color.palette.black = lightgray + +color.palette.blue = #80a0c0 +color.palette.indigo = #c070c0 +color.palette.green = #70c070 +color.palette.darkgreen = #70a070 +color.palette.magenta = #ff80ff +color.palette.pink = #ff80a0 +color.palette.cyan = #80c0c0 +color.palette.darkcyan = #406060 +color.palette.red = #ff8080 +color.palette.teal = #80c0c0 +color.palette.purple = #c080c0 +color.palette.yellow = #ffff80 +color.palette.olive = #c0c080 +color.palette.orange = #ffa070 +color.palette.violetred = #ff7090 + +color.palette.bg.yellow = #404028 +color.palette.bg.yellowgreen = #344028 +color.palette.bg.green = #284028 +color.palette.bg.bluegrey = #282838 + +color.palette.bg.blindingyellow = #ffff00 +color.palette.bg.blindinggreen = #00ff00 +color.palette.bg.blindingorange = #ff8000 diff --git a/Ghidra/Framework/Docking/data/docking.theme.properties b/Ghidra/Framework/Docking/data/docking.theme.properties new file mode 100644 index 0000000000..e35755127a --- /dev/null +++ b/Ghidra/Framework/Docking/data/docking.theme.properties @@ -0,0 +1,251 @@ +[Defaults] + +color.bg = white // note: this is the text/widget bg color +color.fg = black +color.fg.error = red +color.bg.error = lightcoral +color.fg.disabled = lightGray +color.bg.uneditable = system.color.bg.application // TODO see if there exists an LaF setting for this +color.bg.filtered = yellow +color.fg.hint = gray + +color.fg.messages.hint = color.fg.hint +color.fg.messages.alert = orange +color.fg.messages.error = color.fg.error +color.fg.messages.normal = blue +color.fg.messages.warning = orange + + +color.bg.help.hint = rgba(100, 100, 255, 100) +color.fg.help.selector.h1 = #000080 +color.fg.help.selector.h2 = #984C4C +color.fg.help.selector.h3 = #0000FF +color.fg.help.selector.p.provided.by.plugin = #7F7F7F +color.fg.help.selector.p.related.topic = #800080 +color.fg.help.selector.th = #EDF3FE +color.fg.help.selector.code = black +color.fg.help.selector.code.path = #4682B4 + +color.bg.splashscreen = black + +color.bg.header.active = mintcream +color.bg.header.inactive = rgb(150, 150, 150) +color.fg.header.active = black +color.fg.header.inactive = black +color.header.drag.cursor = black + +color.fg.dialog.status.alert = color.fg.messages.alert +color.fg.dialog.status.error = color.fg.messages.error +color.fg.dialog.status.normal = color.fg.messages.normal +color.fg.dialog.status.warning = color.fg.messages.warning + +color.bg.selection = rgb(180, 255, 180) // pale green +color.bg.highlight = rgb(255,255,150) // pale yellow +color.bg.tooltip = rgb(255, 255, 230) + +color.bg.currentline = rgb(232,242,254) +color.cursor.focused = red +color.cursor.unfocused = pink + +color.bg.table.grid = gray +color.bg.table.row.drag = color.palette.lavender +color.bg.table.row = color.bg +color.bg.table.row.alt = rgb(237,243,254) +color.fg.table.uneditable.selected = yellow +color.fg.table.uneditable.unselected = lightgray +color.fg.table = color.fg +color.fg.table.unselected = white +color.fg.error.table.unselected = color.fg.error +color.fg.error.table.selected = lightpink + +color.bg.tableheader.gradient.start = color.bg +color.bg.tableheader.gradient.end = lightGray +color.bg.tableheader.gradient.start.primary = rgb(205, 227, 244) +color.bg.tableheader.gradient.end.primary = rgb(126, 186, 233) + +color.bg.textfield.hint.valid = color.bg +color.bg.textfield.hint.invalid = rgb(255,225,225) +color.fg.textfield.hint = color.fg.hint + +color.bg.tree.drag = color.palette.lavender +color.bg.tree.drag.no.selection = rgb(204, 204, 255) + +color.bg.filterfield = color.bg.filtered +color.fg.filterfield = black + +color.bg.selection.help = lightsteelblue + +// generic component items +color.border.bevel.highlight = lightGray +color.border.bevel.shadow = gray +color.border.provider.disconnected = orange + +color.bg.filechooser = color.bg +color.fg.filechooser = color.fg +color.bg.filechooser.shortcut = lightGray + +color.bg.fieldpanel = color.bg +color.fg.fieldpanel = color.fg +color.bg.fieldpanel.selection = color.bg.selection +color.bg.fieldpanel.highlight = color.bg.highlight +color.bg.fieldpanel.selection.and.highlight = green + +color.bg.tree = [color]Tree.textBackground +color.bg.tree.selected = [color]Tree.selectionBackground +// docking buttons +color.fg.button = black + +icon.folder.new = folder_add.png +icon.subtract = list-remove.png +icon.toggle.expand = expand.gif +icon.toggle.collapse = collapse.gif + +icon.undo = undo.png +icon.redo = redo.png +icon.font = text_lowercase.png +icon.rename = textfield_rename.png +icon.check = check.png +icon.search = magnifier.png +icon.properties = document-properties.png +icon.table = table.png +icon.drive = drive.png +icon.run = play.png +icon.spreadsheet = application-vnd.oasis.opendocument.spreadsheet-template.png +icon.pulldown = menu16.gif +icon.window = application_xp.png +icon.zoom.in = zoom_in.png +icon.zoom.out = zoom_out.png + +icon.theme.import = mail-receive.png +icon.theme.export = mail-folder-outbox.png + +icon.docking.application.home = www_16.png +icon.docking.application.16 = www_16.png +icon.docking.application.128 = www_128.png + +icon.dragon.256 = GhidraIcon256.png + +icon.help.navigation.aid.disabled.overlay = icon.not.allowed +icon.help.navigation.aid.enabled = software-update-available.png + +icon.filechooser.places.my.computer = computer.png +icon.filechooser.places.desktop = desktop.png +icon.filechooser.places.home = user-home.png +icon.filechooser.places.recent = inode-directory.png {edit-undo.png [move(6,10)]} + +icon.filter.options.contains = page_code.png +icon.filter.options.exact = page_green.png +icon.filter.options.regex = page_excel.png +icon.filter.options.starts.with = page_go.png +icon.filter.options.not = bullet_delete.png + +icon.widget.imagepanel.reset = tag.png +icon.widget.imagepanel.zoom.in = icon.zoom.in +icon.widget.imagepanel.zoom.out = icon.zoom.out +icon.widget.imagepanel.zoom.reset = zoom.png + +icon.widget.filterpanel.filter.off = filter_off.png +icon.widget.filterpanel.filter.on = filter_on.png + +icon.widget.pathmanager.reset = trash-empty.png + +icon.widget.table.header.help = info_small.png +icon.widget.table.header.help.hovered = info_small_hover.png +icon.widget.table.header.pending = hourglass.png + +icon.dialog.error.expandable.report = icon.spreadsheet +icon.dialog.error.expandable.exception = program_obj.png +icon.dialog.error.expandable.frame = StackFrameElement.png +icon.dialog.error.expandable.stack = StackFrame_Red.png +icon.dialog.error.expandable.cause = emblem-important.png + +icon.task.progress.1 = eatbits1.png +icon.task.progress.2 = eatbits2.png +icon.task.progress.3 = eatbits3.png +icon.task.progress.4 = eatbits4.png +icon.task.progress.5 = eatbits5.png +icon.task.progress.6 = eatbits6.png +icon.task.progress.7 = eatbits7.png + +icon.task.progress.hourglass.1 = hourglass24_01.png +icon.task.progress.hourglass.2 = hourglass24_02.png +icon.task.progress.hourglass.3 = hourglass24_03.png +icon.task.progress.hourglass.4 = hourglass24_04.png +icon.task.progress.hourglass.5 = hourglass24_05.png +icon.task.progress.hourglass.6 = hourglass24_06.png +icon.task.progress.hourglass.7 = hourglass24_07.png +icon.task.progress.hourglass.8 = hourglass24_08.png +icon.task.progress.hourglass.9 = hourglass24_09.png +icon.task.progress.hourglass.10 = hourglass24_10.png +icon.task.progress.hourglass.11 = hourglass24_11.png + +// Fonts + +font.splash.header.default = Serif-BOLD-35 +font.splash.status = Serif-BOLD-12 +font.table.header.number = arial-BOLD-12 +font.input.hint = monospaced-PLAIN-10 + +[Dark Defaults] + +color.bg = #1c1d1e +color.fg = lightgray +color.fg.error = indianRed +color.fg.disabled = gray +color.bg.filtered = beige +color.fg.hint = darkgray + +color.fg.help.selector.h1 = #66AAF4 +color.fg.help.selector.h2 = #9999F9 +color.fg.help.selector.h3 = #FF99CC +color.fg.help.selector.p.provided.by.plugin = #CCCCCC +color.fg.help.selector.p.related.topic = #800080 +color.fg.help.selector.th = #EDF3FE +color.fg.help.selector.code = gray +color.fg.help.selector.code.path = #5BA5E3 + +color.bg.splashscreen = black + +color.bg.header.active = #4c87c8 +color.bg.header.inactive = #466a92 +color.fg.header.active = lightGray +color.fg.header.inactive = black +color.header.drag.cursor = lightGray + +color.fg.dialog.status.alert = orange +color.fg.dialog.status.error = color.fg.error +color.fg.dialog.status.warning = orange +color.fg.dialog.status.normal = lightBlue + +color.bg.currentline = rgb(40,40,56) // dark bluish gray + +color.cursor.focused = indianRed +color.cursor.unfocussed = darkGray + +color.bg.textfield.hint.invalid = maroon + +color.bg.filterfield = color.bg.filtered +color.fg.filterfield = darkSlateGray + +color.bg.selection = color.palette.bg.green +color.bg.highlight = color.palette.bg.yellow + +color.bg.fieldpanel.selection.and.highlight = color.palette.bg.yellowgreen + +color.bg.table.row.alt = rgb(45,47,65) +color.fg.table.uneditable.selected = lemonchiffon +color.fg.table.uneditable.unselected = lightgray + +color.bg.tableheader.gradient.start = color.bg +color.bg.tableheader.gradient.end = darkGray +color.bg.tableheader.gradient.start.primary = color.bg +color.bg.tableheader.gradient.end.primary = darkBlue + +// docking buttons +color.fg.button = darkGray + +color.bg.filechooser.shortcut = system.color.bg.widget + +color.bg.tree = color.bg +color.bg.tree.selected = [color]Tree.selectionBackground + diff --git a/Ghidra/Framework/Docking/src/main/help/help/TOC_Source.xml b/Ghidra/Framework/Docking/src/main/help/help/TOC_Source.xml index 8a327c6107..233752f8a2 100644 --- a/Ghidra/Framework/Docking/src/main/help/help/TOC_Source.xml +++ b/Ghidra/Framework/Docking/src/main/help/help/TOC_Source.xml @@ -20,9 +20,9 @@ During the help build time, all TOC_Source.xml files will be parsed and validated to ensure that all tags point to valid tags. From these files will be generated _TOC.xml files, which are table of contents files written in the format - desired by the JavaHelp system. Additionally, the genated files will be merged together + desired by the JavaHelp system. Additionally, the generated files will be merged together as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra - help GUI, there will be on table of contents that has been created from the definitions in + help GUI, there will be one table of contents that has been created from the definitions in all of the modules' TOC_Source.xml files. @@ -43,12 +43,25 @@ **The URL for the target is relative and should start with 'help/topics'. This text is used by the Ghidra help system to provide a universal starting point for all links so that they can be resolved at runtime, across modules. - + --> - - + + + + + + + + + + diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/DarkStyle.css b/Ghidra/Framework/Docking/src/main/help/help/shared/DarkStyle.css new file mode 100644 index 0000000000..6ff0fe6fb8 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/help/help/shared/DarkStyle.css @@ -0,0 +1,58 @@ +/* ### + * 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. + */ +/* + Java Help Note: JavaHelp does not accept sizes (like in 'margin-top') in anything but + px (pixel) or with no type marking. +*/ + +body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */ +li { font-family:times new roman; font-size:14pt; } +h1 { color:#80a0c0; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } +h2 { margin: 10px; margin-top: 20px; color:#DDA0DD; font-family:times new roman; font-size:18pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#6495ED; font-family:times new roman; font-size:14pt; font-weight:bold; } +h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } + +/* + P tag code. Most of the help files nest P tags inside of blockquote tags (the was the + way it had been done in the beginning). The net effect is that the text is indented. In + modern HTML we would use CSS to do this. We need to support the Ghidra P tags, nested in + blockquote tags, as well as naked P tags. The following two lines accomplish this. Note + that the 'blockquote p' definition will inherit from the first 'p' definition. +*/ +p { margin-left: 40px; font-family:times new roman; font-size:14pt; } +blockquote p { margin-left: 10px; } + +p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px } +p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px } +p.relatedtopic { color:#9370DB; margin-left: 10px; font-size:14pt; } +p.RelatedTopic { color:#9370DB; margin-left: 10px; font-size:14pt; } + +/* + We wish for a tables to have space between it and the preceding element, so that text + is not too close to the top of the table. Also, nest the table a bit so that it is clear + the table relates to the preceding text. +*/ +table { margin-left: 20px; margin-top: 10px; width: 80%;} +td { font-family:times new roman; font-size:14pt; vertical-align: top; } +th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; color: gray;} + +/* + Code-like formatting for things such as file system paths and proper names of classes, + methods, etc. To apply this to a file path, use this syntax: + ... +*/ +code { color: #F5F5F5; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; } +code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; } diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/Frontpage.css b/Ghidra/Framework/Docking/src/main/help/help/shared/Frontpage.css index b8471669f4..557c37ca39 100644 --- a/Ghidra/Framework/Docking/src/main/help/help/shared/Frontpage.css +++ b/Ghidra/Framework/Docking/src/main/help/help/shared/Frontpage.css @@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1 li { font-family:times new roman; font-size:14pt; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } -h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; } +h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } /* diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/arrow.gif b/Ghidra/Framework/Docking/src/main/help/help/shared/arrow.gif deleted file mode 100644 index bcb3db7057..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/arrow.gif and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/close16.gif b/Ghidra/Framework/Docking/src/main/help/help/shared/close16.gif deleted file mode 100644 index f523864639..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/close16.gif and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/menu16.gif b/Ghidra/Framework/Docking/src/main/help/help/shared/menu16.gif deleted file mode 100644 index 4350a523dd..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/menu16.gif and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/note-red.png b/Ghidra/Framework/Docking/src/main/help/help/shared/note-red.png deleted file mode 100644 index b5f1d5cd1c..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/note-red.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/note.png b/Ghidra/Framework/Docking/src/main/help/help/shared/note.png deleted file mode 100644 index 51e1c8f8c1..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/note.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/note.yellow.png b/Ghidra/Framework/Docking/src/main/help/help/shared/note.yellow.png deleted file mode 100644 index f8ab6489f2..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/note.yellow.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/redo.png b/Ghidra/Framework/Docking/src/main/help/help/shared/redo.png deleted file mode 100644 index 88035efeec..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/redo.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/tip.png b/Ghidra/Framework/Docking/src/main/help/help/shared/tip.png deleted file mode 100644 index 209f1d28c8..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/tip.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/undo.png b/Ghidra/Framework/Docking/src/main/help/help/shared/undo.png deleted file mode 100644 index edd57f5c15..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/undo.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/shared/warning.png b/Ghidra/Framework/Docking/src/main/help/help/shared/warning.png deleted file mode 100644 index 8e9133789b..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/help/help/shared/warning.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Misc/Welcome_to_Help.htm b/Ghidra/Framework/Docking/src/main/help/help/topics/Misc/Welcome_to_Help.htm new file mode 100644 index 0000000000..4291313572 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/help/help/topics/Misc/Welcome_to_Help.htm @@ -0,0 +1,26 @@ + + + + Welcome to Help + + + + + + + + + + + +

Welcome to Help...

+ +
+

We provide context sensitive help on menu items, dialogs, buttons, +and tool windows. To access the help, press <F1> or <Help> on +any menu item or dialog. If specific help is not available for an item, +this page will be displayed.

+
+ + + diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/PlacheholderTopic/Placeholder.htm b/Ghidra/Framework/Docking/src/main/help/help/topics/PlacheholderTopic/Placeholder.htm deleted file mode 100644 index 13961916f5..0000000000 --- a/Ghidra/Framework/Docking/src/main/help/help/topics/PlacheholderTopic/Placeholder.htm +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Placholder Title - - - - -

Stub

- -

Blah blah

- -

Related Topics:

- - - diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingDeveloperDocs.html b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingDeveloperDocs.html new file mode 100644 index 0000000000..086394618e --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingDeveloperDocs.html @@ -0,0 +1,465 @@ + + + + + + + Developer's Guide + + + +

Developer's Guide to Theming

+ +

This document provides information an application developer should know when developing + plugins, actions, scripts, etc., that use colors, fonts, or icons. By following these guidelines, + developers can easily make use of Ghidra's theming capabilities.

+ +

Theme Resource Types

+ +

When developing application code for Ghidra such as plugins, actions, etc., developers often + want to use colors, fonts, and icons. The key idea to support theming is to never + directly + reference those resources. Instead, the developer should create an ID string for the resource + and then in a module.theme.properties file, provide a default value for that ID. + (Also, you may define an alternate "dark" default value that will be used if the + current theme is considered a dark theme). 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 developers use these types by creating either + GColor or GIcon. + Unfortunately, because of the way fonts are implemented, there is no equivalent + GFont, so using fonts is a bit more involved.

+ +
+

Colors

+ +

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 module.theme.properties file. + So, for example:

+ +
+
+ panel.setBackground(Color.Red); +
+ +

becomes

+ +
+ panel.setBackground(new GColor("color.bg.abc")); +
+ +

and

+ +
+ public static final Color MY_COLOR = Color.BLUE; +
+ +

becomes

+ +
+ public static final Color MY_COLOR = new + GColor("color.fg.xzy"); +
+
+ +

The GColor class uses a delegation model where all method calls to + GColor get mapped to + its delegate color. If ever the color associated with a GColor's resource ID + changes, the GColor is automatically updated by calling the + refresh() method. This is done whenever the + Gui.setColor(id) is called or a new theme is loaded.

+ +

Icons

+ +

Icons work just like colors, so you can just create a GIcon(String id). + So, for example,

+ +
+
+ public static final Icon MY_ICON = + ResourceManager("images/balloon.png"); +
+ +

becomes

+ +
+ public static final Icon MY_ICON = new + GIcon("icon.text.bubble"); +
+
+ +

Fonts

+ +

Unfortunately, fonts are unable to use the delegation model used for colors and icons. + Therefore, there is no GFont class. Programming fonts requires a bit more work. + If a font used directly, such as in renderer or in a paint method, simply get the + font each time + from the Gui class, as shown below. To set a font on a component, use + Gui.registerFont(Component, String). Once the component is registered, the + application will + automatically update the component if the font associated with that ID changes. So, for + example:

+ +
+
+ Font font = new Font("Monospaced", Font.BOLD, 12); +
+ +

becomes

+ +
+ Font font = Gui.getFont("font.xyz"); +
+ +

or

+ +
+ myLabel.setFont(new Font("Dialog", Font.PLAIN, 14) +
+ +

becomes

+ +
+ Gui.registerFont(myLabel, "font.xyz"); +
+
+ +
+ + +

Resource ID Strings

+ +
+

Resource IDs are strings used to identify a color, font, or icon. These strings are + created 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 help keep resource IDs + consistent, we created a convention for IDs as follows:

+ +
+
+
+
+     [type].[category[...]].[client].[specialized uses]
+
+
+
+
+ +
    +
  • type: color, font, or icon.
  • + +
  • category: any value, examples include 'bg'(background), 'fg'(foreground), + 'cursor'. There may be multiple dot-separated values.
  • + +
  • client: the plugin name or feature name.
  • + +
  • specialized uses: any key value here that applies to the client, such as + 'vertex' for a graph client.
  • +
+ +
+

Examples:

+ +
    +
  • color.bg
  • + +
  • color.bg.listing
  • + +
  • color.bg.functiongraph.vertex.group
  • + +
  • font.listing
  • + +
  • font.listing.header
  • + +
  • icon.error
  • + +
  • icon.delete
  • + +
  • icon.plugin.byteviewer.provider
  • +
+
+
+ +

Theme Property Files

+ +
+

The default values for resource IDs are defined in files that reside + a module's data directory (not all modules define this file). These files all + are named to end in theme.properties and begin with the module's name. Some + modules make use of multiple files in order to better manage the volume of IDs. In this + case, the name of each properties file offers a clue as to its contents. Thus, for small + modules, those without many resource IDs in use, one theme properties file is sufficient to + easily define and manage all required IDs. But, we recommend larger modules 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 are named with the + .theme.properties suffix.

+ +

Theme Properties File Naming Convention

+ +

To promote consistency, theme property files should use the following naming + convention:

+ +
+
+
+
+      module name[.additional name]].theme.properties
+
+
+
+ +

Examples:

+ +
    +
  • base.theme.properties
  • + +
  • base.listing.theme.properties
  • +
+
+ +

Theme Properties File Format

+ +

Theme files uses a very simple format for specifying theme property values. Each line + specifies a property ID (sometimes referred to as the 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. +

+ +
+ +
+[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]
+...
+
+
+
+ +

Example:

+ +
+
+[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
+
+
+ + +

NOTE: The [Dark Defaults] section is for optionally 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.

+
+ +

Theme Property Values

+ +
+

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.

+ +

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 Look and Feel 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 Java property named "table.background", + you would use the following definition: "color.bg.table = [color]table.background".

+ +

Color Values

+ +

Color values supports the following formats:

+ +
+
    +
  • #rrggbb
  • + +
  • #rrggbbaa
  • + +
  • 0xrrggbb
  • + +
  • 0xrrggbbaa
  • + +
  • rgb(red, green, blue)
  • + +
  • rgba(red, green, blue, alpha)
  • + +
  • web color name // the case-insensitive name of a web color such as red, olive, or + purple
  • +
+
+ +

Examples:

+
+        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
+
+ +

Font Values

+ +

Font values are specified using the following format:

+ +
+
+
+      family name-style-size
+
+
+ +
    +
  • family name: the font name such as monospaced, dialog, + courier.
  • + +
  • style: One of PLAIN, BOLD, ITALIC, or + BOLDITALIC.
  • + +
  • size: the font point size. 12 is very common.
  • +
+
+ +

Examples:

+
+        font.foo = monospaced-PLAIN-12
+        font.foo = courier-BOLD-14
+        font.foo = SansSerif-ITALIC-10
+
+ +

Font Modifiers

+ +

When referencing another font, the referenced font can be modified using the following + format:

+ +
+
+
+      font.ref[family name][style][size]
+
+
+ +
    +
  • font.ref: the theme property ID of some other font
  • + +
  • family name: use the size and style of the reference font, but use this font + family.
  • + +
  • style: use the same font as the reference font, but with this style. One of + PLAIN, BOLD, ITALIC, or + BOLDITALIC.
  • + +
  • size: use the same font as the reference font, but with this size.
  • +
+
+ +

Examples:

+
+        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
+
+ +

Icon Values

+ +

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:

+ +
+
+
+      iconName[size(width,height)][disabled]{iconOverlayName[size(width,height)[disabled][move(x,y)]}{...}
+
+
+
+ +
    +
  • iconName: the name the base icon
  • + +
  • size(width,height): optional modifier to scale the image to the given size.
  • + +
  • disabled: optional modifier to create a disabled version of the icon.
  • + +
  • {...}: optional modifier to overlay an icon on the base icon. It is recursively + defined using the standard icon format.
  • + +
  • move(x,y): optional modifier on overlays to position them relative to the base + icon.
  • +
+
+ +

Examples:

+
+        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
+
+ +

To create stand-alone icon suitable for dynamically overlaying other icons, there is + special syntax for specifying an empty base icon. Use the empty icon along with another + overlay icon in some specific area of the empty icon to create a final icon that can be used + as an overlay for other icons. For example, to + create an overlay icon that would add a flag to the bottom-right corner of any other icon:

+
+        icon.overlay.flag = EMPTY_ICON[size(16,16)]{flag.png[size(6,6)][move(10,10)]}
+
+ + +

Provided by: Theme Manager

+ +

Related Topics

+ +
+
+ + diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingInternals.html b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingInternals.html new file mode 100644 index 0000000000..6a72228954 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingInternals.html @@ -0,0 +1,227 @@ + + + + + + + Theming Architecture + + + + +

Theming Architecture

+ +

This document describes the API for initializing and managing themes. A theme (the + GTheme + class) in Ghidra represents a specific Look and Feel as well the set of values for the color, + font, and icon resource IDs used in the application. Resource IDs are defined in theme properties + files. Application writers refer to these IDs when using colors, fonts and icons. + The Gui class provides a set of + static methods that serves as the primary interface for managing all aspects of theming.

+ +

GTheme Class

+ +

The GTheme class is the implementation of the theme concept. At any given time, + the application is using resource values as specified by the active theme. The theme specifies + the Java Look and Feel, 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 themes and file-based themes. Built-in + themes are implemented directly as sub-classes of GTheme and simply specify a + Java Look and Feel + and whether or not the theme is "dark". There is one "built-in" theme for each supported + Look and Feel. File-based themes read their values from a theme file. Theme files are created by + editing and saving existing themes.

+ +

GThemeValueMap / ThemeValue Classes

+ +

These are the base classes for storing values for resource IDs. A GThemeValueMap + consists of three maps, one each for colors, fonts, and icons. Each map binds 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 referenced ID or the direct value must be null. 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 reference IDs, which is why it needs a value map as an + argument.

+ +

GThemeValueMaps have some convenience methods for performing set operations. + 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.

+ +

Gui Class

+ +

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. This + class is meant to be used by application developers, along with GColor for colors + and GIcon for icons. Fonts are handled slightly differently by making calls to + Gui.registerFont(Component, Id) +

+ +

Application Initialization

+ +

Applications need to call Gui.initialize() before any uses of color, fonts, or + icons occur. + This will load all resource defaults from all *.theme.properties files, read the + last used theme from preferences, and load that theme which includes setting the Look and Feel. +

+ +

Loading a Theme

+ +

Loading a theme consists of two main operations: loading the Look and Feel and building the + set of values for all defined resource IDs.

+ +

Loading the Look and Feel

+ +

Because each Look and Feel presents different challenges to the theming feature, there is a + LookandFeelManager for each Look and Feel. The LookandFeelManager is + responsible for installing + the Look and Feel (in the case of Nimbus, we had to install a special subclass of the + NimbusLookandFeel), extracting the Java resources mappings (Java Look and Feel + objects also use a resource ID concept), group the Java resources into common groups, possibly + fix up some issues specific to that Look and Feel, possibly install global properties, and have + specific update techniques to get that Look and Feel to update its component UIs when + values change.

+ +

Creating the Active Theme Values

+ +

After the Look and Feel 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 ThemeManager called + "currentValues" . When values are loaded into a GThemeValueMap, they will replace + any existing values with the same ID. The values are loaded in the following order:

+ +
+
    +
  • Java defaults (values from Look and Feel)
  • + +
  • application defaults (from *.theme.properties files)
  • + +
  • applications dark defaults (if theme is dark)
  • + +
  • theme values (values that were overridden by a specific theme)
  • +
+
+ +

Changing Values Associated With Resource Ids

+ +

Whenever the value associated with a resource ID changes, the application gets notified in + various ways to update the display with the new value. The technique used to notify the + application differs depending on the resource type and the Look and Feel (these differences are + captured in the LookandFeelManager sub-classes for each Look and Feel). It can also + vary depending on whether the value is an application defined resource or a Java defined + resource.

+ +

Updating Colors

+ +

Updating Colors is the easiest of all the resource types. First + GColor.refreshAll() is called, + which causes every GColor to refresh its internal delegate Color. + This is the purpose of using the GColor class, to introduce a level of indirection + that allows us to change runtime behavior without having to recompile. + 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.

+ +

Updating Icons

+ +

Updating icons is a mixed bag. If the icon is application defined, + GIcon.refreshAll() is + called which causes every GIcon to refresh its internal delegate icon 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.

+ +

Updating Fonts

+ +

Updating Fonts is a bit more involved than updating colors and icons, due to the inability + to use the indirection model when working with fonts. 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 called Gui.registeredFont() are updated. (The + registration system for fonts is what allows us to notify components of updates, since fonts + cannot use the indirection model.) + Finally, the updateComponentTreeUI() method is + called on all windows in the application.

+ + + +

Creating/Editing/Saving Themes

+ +

New themes can be created and saved to files in the theme directory in the user's + application directory (<home>/.ghidra/.ghidra-<version>/themes). + 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 using a new theme name. Saving the + theme will create a new "xyz.theme" file where "xyz" 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.

+ +

External Icons

+ +

When setting icons for an icon resource ID, the user has the option of using an icon that + exists in the application (on the classpath) or using any supported icon file (.png or .gif) on + the filesystem. If the user + chooses to use a non-application icon file, then that icon will be copied into an images + directory in their application directory. These icons are considered external in that if the + theme were given to another user, you would also need to give them these icon files, as they + will not exist in other application installations.

+ +

Importing/Exporting Themes

+ +

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 user's 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.

+ +

Look and Feel Notes

+ +

Getting the theming feature to work on all the various Java Look and Feels is a + challenge. Java created the concept of UIDefaults, which is a mapping of property + names + to values. The implication is that users can change Look and Feel settings by changing values + in the UIDefaults. Unfortunately, not all Look and Feels support this concept. + Nimbus and GTK+, in particular are problematic. Nimbus somewhat honors values in + UIDefaults, but only if those values are + installed before Nimbus is loaded. So for our theming purposes, we had to extend the Nimbus + Look and Feel in order to override the getDefaults() method (this is the method + where Look and Feels populate the UIDefaults) so that we can install any overridden + values from the selected theme. Also, since Nimbus does not respect changes to these values after + they have been created, every time a Java defined property changes, we have to re-install the + Nimbus Look and Feel. The GTK+ Look and Feel 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. To compensate for the + differences among Look and Feels, we created a LookandFeelManager base class with + sub-classes for each Look and Feel.

+ + + + +

Provided by: Theme Manager

+ +

Related Topics

+ +
+ + diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingOverview.html b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingOverview.html new file mode 100644 index 0000000000..d446609d85 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingOverview.html @@ -0,0 +1,137 @@ + + + + + + + General Overivew + + + + +

Theming Overview

+ +

This document describes Ghidra's support for using and managing UI themes. +

+ +

Goal

+ +

The primary goal of theming in Ghidra is to allow users to customize the appearance of the UI + and to share that customization with the community. We added infrastructure to Ghidra that + allows users/developers to completely configure the colors, fonts, and icons used within + the application. There are two main motivations for creating this feature. The first is to + provide the much requested "Dark Theme". Many users find Ghidra's current color scheme to be + hard on the eyes and have requested a dark color scheme. The + second motivation for creating this feature is for accessibility purposes. For example, the + theming feature allows the user to create a theme that uses high contrast colors and larger + fonts.

+ + +

Background

+ +

Before theming, Ghidra used thousands of hard-coded colors, fonts, and icons. They were + defined throughout the code in a somewhat haphazard fashion. Many features use colors to convey + similar concepts, but no effort was made to use similar colors for similar concepts. + Further, these colors were generally chosen to work with one of the common default Java Look and + Feels. (A Java Look and Feel is a grouping of UI settings that define the appearance of the + application.) Those original colors often looked terrible when used in conjunction with other + Look and Feels, especially dark ones.

+ +

Ghidra did allow some customization of the current colors using the Ghidra Options API, but + this was inadequate for several reasons. One issue with this approach is that not all colors and + fonts are changeable via the options. Another issue 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 Look and Feel; you couldn't have different option choices depending on the current Look + and Feel.

+ +

As mentioned, all of Ghidra's icons were hard-coded, with many not suitable for use in a dark + theme. Overall, the hard-coding of colors, fonts, and icons and the limitation of options made + creating a good dark theme virtually impossible. To address these issues, a new theming + infrastructure was created.

+ +

General Concepts and Approach

+ +

To achieve a theming capability in Ghidra, we had to make the following changes:

+
    +
  1. Replace hard-coded values with a level of indirection for colors, fonts, and icons + using property names/IDs +
  2. +
  3. Create the concept of a theme that allows for the the property values to change + as a group and along with the current Look and Feel in use +
  4. +
  5. Create an API that allows for the introduction of system-level properties that can + be mapped to specific Look and Feel values in order to create reusable groups of properties +
  6. +
  7. Provide methods for changing the property values, along with the ability to create, + edit, save, export and import themes +
  8. +
+ + +
+

Indirection

+ +

The goal of using indirection is to remove all uses of hard-coded colors, fonts, and icons + when developing a feature in the application. Instead, these objects 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 + the ID is located. 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 defined using a different property name, + allowing for properties to be defined by other properties. This allows users to change + individual values or entire groups of values with one edit.

+ +

Theme

+ +

A theme is simply the object that specifies all the values for colors, fonts, and icons + used in the application, as well as the Look and Feel. This allows there to be a set of + themes to choose from and by simply switching the theme, the system will then update the Look + and Feel along with the colors, fonts, and icons, all with one action. The set of themes to + choose from is a mix of built-in themes and saved custom themes. There is one built-in theme + for each supported Look and Feel. The chosen theme will use the UI values defied by the Look + and Feel, as well as all the values for the defined property IDs. Users are able to + create custom themes to change any color, font, or icon defined by the application, along with + UI values supplied by the associated Look and Feel.

+ +

Look and Feel Values

+ +

The Java Look and Feel is specified by the active theme. These Look and Feel objects + define colors, fonts, and icons indirectly using identifying strings such as "Button.font" + and "Menu.background". The Look and Feel mappings determine the default values used by all + GUI elements + unless overridden by developers when they create the components. With theming, users have the + ability to change these Java Look and Feel defined values in the same way as theme properties + defined created by application code. Another concept used by Java Look and Feels is that of + shared UI patterns. + Look and Feels typically share many of the same colors and those shared colors are defined + by the Look and Feel using a group name/key such as "control", "text", or "menu". This allows + for changes to be made at the group level or for the individual property. The theme + framework captures this Java grouping information when creating a theme that for a given + Look and Feel. +

+ +

User Interaction

+ +

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 perform 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 Look and Feel 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 importing themes.

+
+ + +

Provided by: Theme Manager

+ +

Related Topics

+ +
+ + diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingUserDocs.html b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingUserDocs.html new file mode 100644 index 0000000000..eb9ff2d102 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/ThemingUserDocs.html @@ -0,0 +1,259 @@ + + + + + + + Theming User Documentation + + + + +

Editing Themes

+ +

Description

+ +

The Theming feature allows users to customize the colors, fonts, and icons used throughout + the application. The active theme determines the Java Look and Feel, whether the theme should use + light or dark defaults, and any custom colors, fonts, and icons that override the default + values. Users can can easily switch between any of the built-in themes or any saved themes found + in their home application directory

+ +

Users can also edit and create their own themes using the Theme Editor. Custom themes are + stored in the user's <home>/.ghidra/.ghidra-<version>/themes directory. + These theme files 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 application.

+ +

Theme Dialog

+ +

The Theme Dialog is the primary means for creating, editing, and saving themes.

+ +


+  

+ +

The Theme Dialog consists of a theme drop-down and a tabbed set of tables that display the + values for every color property, font property, and icon property defined by either the Java + Look and Feel or the application. All application defined properties start with "color.", + "font.", or "icon.", depending on whether the the property is a color, font, or icon + respectively. All other properties are defined by the Java Look and Feel. This naming + convention is not enforced, thus it is possible that 3rd-party Extensions may introduce + property names that do not match this description. See + the Developer Documentation for more details on the property ID + format and naming conventions. +

+ +

Each table entry shows the property ID string, the current value, the theme value, + and the default value. Most often, the three values are equal. If the theme value is different + from the default value, that means that the active theme has overridden the default value for + that property. If the current value is different from the theme value, that means the user has + changed that value, but not yet saved the changes back to the theme.

+ +

Individual values can be changed by double-clicking the value in the ID or Current Value + column. This will bring up an appropriate editor for changing the value. When editing a value, + the change + takes place immediately in the application so you can see the effect. When you leave the + specific property editor, you have the choice of keeping the change or canceling and having it + revert back to its previous value.

+ +

If any values have been changed, the Save button will become enabled, allowing you to save + any changes you have made. (Pressing the Dismiss button will also give the the option to + save.) When saving, if the + current theme is a built-in theme, you will first have to supply a new theme name. If the + current theme is a not a built-in theme, you will have the option to overwrite the existing + theme or supplying a new name to save it as a new theme.

+ +
+

Color Editor

+ +

When you double-click on a color value, the Edit Color dialog appears.

+ +


+  

+ +

Any change you make in the editor is applied to the application immediately. If you press + the OK button, the change will stay. If you press the Cancel button, the color + will revert back to the original color.

+ +

Font Editor

+ +

When you double-click on a font value, the Edit Font dialog appears.

+ +


+  

+ +

Any change you make in the editor is applied to the application immediately. If you press + the OK button, the change will stay. If you press the Cancel button, the font + will revert back to the original font.

+ +

Icon Editor

+ +

When you double-click on an Icon value, the Edit Icon dialog appears.

+ +


+  

+ +

The Edit Icon dialog has a drop-down text field where you can find any existing icon on + the classpath. If you want to choose an Icon from the file system, press the ... button + and a File Chooser will appear, allowing you to pick an icon file from anywhere on the filesystem. + Any change you make in the editor is applied to the application immediately. If you press the + OK button, the change will stay. If you press the Cancel button, the icon will + revert back to the original icon.

+
+ +

Theme Actions

+ +
+

Switching Themes

+ +

To change the current theme, first bring up the Theme Dialog. + The Theme Dialog can be invoked from the main application menu using the + EditTheme menu. From the Theme + Dialog you can select a theme from the combo box at the top.

+ +

Modifying Theme Values

+ +

All the colors, fonts, and icons that have been registered with the theme API can be + modified using the Theme Dialog. The Theme Dialog can be invoked + from the main application menu using the + EditTheme menu. Choose the + tab for the appropriate type and double-click on the ID column or Current Value column of the + item you want to change. An editor for that type will appear.

+ +

Reseting Theme Values

+ +

To reset an individual value back to its original theme value, from the + main application menu invoke the Theme Dialog using the Edit Theme menu. Choose the + tab for the appropriate type and right-click on the row of the value you want to reset, then + choose the Restore Value menu item.

+ +

Reseting All Theme Values

+ +

To reset all values back to the original values established by the current theme, from the + main application menu invoke + the EditTheme Actions Reset Theme Values menu.

+ +

Saving Themes

+ +

After making changes to one or more theme values, the Theme + Dialog's Save button will be enabled. Pressing the Save button will give + the user the option of creating a new theme or overwriting the current them (if the current + theme is not a built-in theme). Also, users will have the option of saving a theme if they + dismiss the Theme Dialog while there are changes to one or more theme values.

+ +

Deleting Themes

+ +

To delete a custom saved theme, from the main application menu invoke the + EditTheme Actions Delete Theme... menu. This will bring up a dialog + with a list of themes that can be deleted. Select the theme to delete and press the Ok + button.

+ +

Exporting Themes>

+ +

To export a theme so that it can be shared with others, from the + main application menu invoke the Edit Theme Actions Export Theme... menu. You will first be asked if + you want to export as a regular theme file or as a Zip file. The Zip file option is useful if + the current theme has icon values that are not included with standard application. In that case, + the Zip file will include those non-standard icon files.

+ +

Importing Themes

+ +

To import a theme, from the main application menu + invoke the Edit Theme Actions Import + Theme... menu. A file chooser dialog will appear allowing the user to choose a theme file + to import. The selected file can be either a standard theme file or a Zip file containing the + theme file and any non-standard icon files defined by that theme.

+ +

Reloading Default Values

+ +

This action causes Ghidra to reload all theme default values. It is really only useful + for developers who are actively making changes to theme.properties files. To activate this + action, press the refresh button in the top + right corner of the Theme Dialog.

+
+ +

Theme Property Names

+ +

Theme Property Names (also referred to as IDs or keys) that are defined by the application + use a common format to help make sorting and viewing properties more intuitive as to their use. See + the Developer Documentation for more details on the property ID + format and naming conventions.

+ +

Theme Files

+
+ +

Theme Files are used to store saved custom themes. They are simple text files and are + stored in the user's home application directory under + <home>/.ghidra/.ghidra-<version>/themes. The first three properties are always the + theme name, the Look and Feel name, and whether the theme uses standard defaults or dark + defaults. Finally, there is a list of overridden property "name = value" lines. The format + is:

+ +
+        name = [theme name]
+        Look and Feel = [Look and Feel 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]
+        ...
+	
+
+ +
+

Example:

+
+        name = BigFontTheme
+        Look and Feel = Nimbus
+        useDarkDefaults = false
+		
+        color.bg = Black
+        color.bg.foo = #012345
+        [color]Panel.background = Red
+        font.button = dialog-PLAIN-14
+        icon.refresh = images/reload3.png    
+        color.bg.bar = color.bg.foo   
+        color.bg.xxx = [color]Panel.background
+	
+ + +

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]", + or "[icon]" prepended to their property name. These brackets are only used to aid in + parsing this file. When the properties are used in Ghidra, the bracketed prefixes are + removed.

+ +

Also, note that the values of these properties can reference other property names. If the + 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."

+ +

Specifying Theme Property Values

+ +

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 Developer Documentation. + +

+ + +

Provided by: Theme Manager

+ +

Related Topics

+
+ + diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/ColorEditor.png b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/ColorEditor.png new file mode 100644 index 0000000000..937e5a7b70 Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/ColorEditor.png differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/FontEditor.png b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/FontEditor.png new file mode 100644 index 0000000000..10e4350d97 Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/FontEditor.png differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/IconEditor.png b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/IconEditor.png new file mode 100644 index 0000000000..b806590033 Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/IconEditor.png differ diff --git a/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/ThemeDialog.png b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/ThemeDialog.png new file mode 100644 index 0000000000..5254f290aa Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/help/help/topics/Theming/images/ThemeDialog.png differ diff --git a/Ghidra/Framework/Docking/src/main/java/docking/CloseIcon.java b/Ghidra/Framework/Docking/src/main/java/docking/CloseIcon.java new file mode 100644 index 0000000000..48d28967e3 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/CloseIcon.java @@ -0,0 +1,120 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking; + +import java.awt.*; +import java.awt.geom.GeneralPath; + +import javax.swing.Icon; + +/** + * Icon for a close button + */ +public class CloseIcon implements Icon { + private int size; + private Color color; + private Shape shape; + + /** + * Creates a close icon. + * @param isSmall false signals to use a 16x16 size; true signals to use an 8x8 size + * @param color the color of the "x" + */ + public CloseIcon(boolean isSmall, Color color) { + this.size = isSmall ? 8 : 16; + this.color = color; + this.shape = buildShape(); + } + + private Shape buildShape() { + GeneralPath path = new GeneralPath(); + + /* + We use trial and error sizing. This class allows clients to specify the icon size. At + the time of writing, there were only 2 sizes in use: 16 and 8 pixels. If more size + needs arise, we can revisit how the values below are chosen. + */ + + double margin = 2; + double shapeSize = 11; + double thickness = 1.7; + if (size == 8) { + margin = 0; + shapeSize = 7; + thickness = 1; + } + + double p1x = margin; + double p1y = margin + thickness; + double p2x = margin + thickness; + double p2y = margin; + double p3x = margin + shapeSize; + double p3y = margin + shapeSize - thickness; + double p4x = margin + shapeSize - thickness; + double p4y = margin + shapeSize; + + path.moveTo(p1x, p1y); + path.lineTo(p2x, p2y); + path.lineTo(p3x, p3y); + path.lineTo(p4x, p4y); + path.lineTo(p1x, p1y); + + p1x = margin + shapeSize - thickness; + p1y = margin; + p2x = margin + shapeSize; + p2y = margin + thickness; + p3x = margin + thickness; + p3y = margin + shapeSize; + p4x = margin; + p4y = margin + shapeSize - thickness; + + path.moveTo(p1x, p1y); + path.lineTo(p2x, p2y); + path.lineTo(p3x, p3y); + path.lineTo(p4x, p4y); + path.lineTo(p1x, p1y); + + path.closePath(); + return path; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + try { + g2d.translate(x, y); + g2d.setColor(color); + g2d.fill(shape); + } + finally { + g2d.translate(-x, -y); + } + } + + @Override + public int getIconWidth() { + return size; + } + + @Override + public int getIconHeight() { + return size; + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java index cb71394ff5..20bfef2bc5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java @@ -15,14 +15,15 @@ */ package docking; -import java.awt.Component; -import java.awt.KeyboardFocusManager; +import java.awt.*; import java.awt.event.MouseEvent; import java.util.*; import javax.swing.*; import docking.action.*; +import generic.theme.Gui; +import generic.theme.ThemeManager; import ghidra.util.*; import ghidra.util.exception.AssertException; import help.HelpDescriptor; @@ -114,6 +115,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext private String inceptionInformation; + private String registeredFontId; + /** * Creates a new component provider with a default location of {@link WindowPosition#WINDOW}. * @param tool The tool will manage and show this provider @@ -776,6 +779,41 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext return dockingTool; } + /** + * Tells the provider to adjust the font size for this provider. By default, this method + * will adjust the font for the registered font id if it has been registered using + * {@link #registeredFontId}. Subclasses can override this method to a more comprehensive + * adjustment to multiple fonts if necessary. + * @param bigger if true, the font should be made bigger, otherwise the font should be made + * smaller + */ + public void adjustFontSize(boolean bigger) { + if (registeredFontId == null) { + return; + } + Font font = Gui.getFont(registeredFontId); + if (font == null) { + return; + } + int size = font.getSize(); + if (bigger) { + size += 1; + } + else { + size = Math.max(size - 1, 3); + } + ThemeManager.getInstance().setFont(registeredFontId, font.deriveFont((float) size)); + } + + /** + * Registers a fontId for the font that will be automatically adjusted when + * {@link #adjustFontSize(boolean)} is called. + * @param fontId the id of the theme font to be adjusted + */ + protected void registerAdjustableFontId(String fontId) { + this.registeredFontId = fontId; + } + @Override public String toString() { return name + " - " + getTitle() + " - " + getSubTitle(); @@ -885,4 +923,5 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext return inceptionInformation; } } + } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 605fb3d1f7..8d47d68f05 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -32,6 +32,8 @@ import docking.event.mouse.GMouseListenerAdapter; import docking.menu.DialogToolbarButton; import docking.util.AnimationUtils; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.*; import ghidra.util.exception.AssertException; import ghidra.util.task.*; @@ -45,7 +47,10 @@ import utility.function.Callback; public class DialogComponentProvider implements ActionContextProvider, StatusListener, TaskListener { - private static final Color WARNING_COLOR = new Color(0xff9900); + private static final Color FG_COLOR_ALERT = new GColor("color.fg.dialog.status.alert"); + private static final Color FG_COLOR_ERROR = new GColor("color.fg.dialog.status.error"); + private static final Color FG_COLOR_WARNING = new GColor("color.fg.dialog.status.warning"); + private static final Color FG_COLOR_NORMAL = new GColor("color.fg.dialog.status.normal"); private final static int DEFAULT_DELAY = 750; @@ -699,13 +704,13 @@ public class DialogComponentProvider protected Color getStatusColor(MessageType type) { switch (type) { case ALERT: - return Color.orange; + return FG_COLOR_ALERT; case WARNING: - return WARNING_COLOR; + return FG_COLOR_WARNING; case ERROR: - return Color.red; + return FG_COLOR_ERROR; default: - return Color.blue; + return FG_COLOR_NORMAL; } } @@ -914,7 +919,7 @@ public class DialogComponentProvider statusLabel = new GDHtmlLabel(" "); statusLabel.setName("statusLabel"); statusLabel.setHorizontalAlignment(SwingConstants.CENTER); - statusLabel.setForeground(Color.blue); + statusLabel.setForeground(Messages.NORMAL); statusLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); statusLabel.addComponentListener(new ComponentAdapter() { @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockableHeader.java b/Ghidra/Framework/Docking/src/main/java/docking/DockableHeader.java index 3ad420264f..aed16982ec 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockableHeader.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockableHeader.java @@ -23,7 +23,8 @@ import java.util.*; import java.util.List; import java.util.stream.Collectors; -import javax.swing.*; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; import org.jdesktop.animation.timing.Animator; import org.jdesktop.animation.timing.Animator.RepeatBehavior; @@ -31,6 +32,8 @@ import org.jdesktop.animation.timing.TimingTargetAdapter; import org.jdesktop.animation.timing.interpolation.PropertySetter; import docking.util.AnimationUtils; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.WindowUtilities; import generic.util.image.ImageUtils; import ghidra.framework.OperatingSystem; @@ -41,7 +44,6 @@ import ghidra.util.bean.GGlassPane; import ghidra.util.bean.GGlassPanePainter; import help.Help; import help.HelpService; -import resources.ResourceManager; /** * Component for providing component titles and toolbar. Also provides Drag @@ -490,6 +492,7 @@ public class DockableHeader extends GenericHeader private static class EmphasizeDockableComponentPainter implements GGlassPanePainter { + private static final GIcon DRAGON_ICON = new GIcon("icon.dragon.256"); private Set otherComponentInfos = new HashSet<>(); private Image image; @@ -538,7 +541,7 @@ public class DockableHeader extends GenericHeader g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - Color background = new Color(218, 232, 250); + Color background = Palette.getColor("aliceblue"); g.setColor(background); Rectangle othersBounds = null; @@ -567,8 +570,7 @@ public class DockableHeader extends GenericHeader g2d.fillRect(othersBounds.x, othersBounds.y, othersBounds.width, othersBounds.height); - ImageIcon ghidra = ResourceManager.loadImage("images/GhidraIcon256.png"); - Image ghidraImage = ghidra.getImage(); + Image ghidraImage = DRAGON_ICON.getImageIcon().getImage(); double scale = percentComplete * 7; int gw = ghidraImage.getWidth(null); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockableToolBarManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockableToolBarManager.java index 82e8c35169..0116deda95 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockableToolBarManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockableToolBarManager.java @@ -15,8 +15,7 @@ */ package docking; -import java.awt.Dimension; -import java.awt.FlowLayout; +import java.awt.*; import java.util.Collections; import java.util.Iterator; @@ -24,17 +23,17 @@ import javax.swing.*; import docking.action.*; import docking.menu.*; +import generic.theme.GColor; import ghidra.util.exception.AssertException; import ghidra.util.task.SwingUpdateManager; -import resources.ResourceManager; /** * Manages to toolbar for the dockable components. */ class DockableToolBarManager { - private static final ImageIcon CLOSE_ICON = ResourceManager.loadImage("images/close16.gif"); - private static final ImageIcon MENU_ICON = ResourceManager.loadImage("images/menu16.gif"); - + private static final Color BUTTON_COLOR = new GColor("color.fg.button"); + private static final Icon CLOSE_ICON = new CloseIcon(false, BUTTON_COLOR); + private Icon MENU_ICON = new DropDownMenuIcon(BUTTON_COLOR); private GenericHeader dockableHeader; private ToolBarManager toolBarManager; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingUtils.java index e44ac282c9..6da2c86f27 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingUtils.java @@ -37,7 +37,8 @@ import docking.widgets.list.GList; import docking.widgets.list.GListCellRenderer; import docking.widgets.table.GTableCellRenderer; import docking.widgets.tree.support.GTreeRenderer; -import ghidra.docking.util.DockingWindowsLookAndFeelUtils; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.docking.util.LookAndFeelUtils; import ghidra.util.HTMLUtilities; import resources.ResourceManager; @@ -125,7 +126,7 @@ public class DockingUtils { public static JSeparator createToolbarSeparator() { Dimension sepDim = new Dimension(2, ICON_SIZE + 2); JSeparator separator = new JSeparator(SwingConstants.VERTICAL); - if (DockingWindowsLookAndFeelUtils.isUsingAquaUI(separator.getUI())) { + if (LookAndFeelUtils.isUsingAquaUI(separator.getUI())) { separator.setUI(new BasicSeparatorUI()); } separator.setPreferredSize(sepDim); // ugly work around to force height of separator @@ -349,7 +350,7 @@ public class DockingUtils { c.setBorder(BorderFactory.createEmptyBorder()); } - c.setBackground(new Color(0, 0, 0, 0)); + c.setBackground(Palette.NO_COLOR); } /** Hides any open tooltip window */ diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DropDownMenuIcon.java b/Ghidra/Framework/Docking/src/main/java/docking/DropDownMenuIcon.java new file mode 100644 index 0000000000..7f07f50405 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/DropDownMenuIcon.java @@ -0,0 +1,94 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking; + +import java.awt.*; +import java.awt.geom.GeneralPath; + +import javax.swing.Icon; + +/** + * Icon for a drop down menu button (triangle pointing down) + */ +public class DropDownMenuIcon implements Icon { + private static final int ICON_SIZE = 16; + + private Color color; + private Shape shape; + + /** + * Creates a drop down menu icon. + * @param color the color of the triangle + */ + public DropDownMenuIcon(Color color) { + this.color = color; + this.shape = buildShape(); + } + + private Shape buildShape() { + + GeneralPath path = new GeneralPath(); + + double iconSize = 16; + double height = 6; + double width = 10; + double leftMargin = (iconSize - width) / 2; + double topMargin = (iconSize - height) / 2; + + // draw a triangle pointing down; p1 is the bottom; p2 is the left + double p1x = leftMargin + (width / 2); + double p1y = topMargin + height; + double p2x = leftMargin; + double p2y = topMargin; + double p3x = leftMargin + width; + double p3y = topMargin; + + path.moveTo(p1x, p1y); + path.lineTo(p2x, p2y); + path.lineTo(p3x, p3y); + path.lineTo(p1x, p1y); + path.closePath(); + + return path; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + try { + g2d.translate(x, y); + g2d.setColor(color); + g2d.fill(shape); + } + finally { + g2d.translate(-x, -y); + } + } + + @Override + public int getIconWidth() { + return ICON_SIZE; + } + + @Override + public int getIconHeight() { + return ICON_SIZE; + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/EditWindow.java b/Ghidra/Framework/Docking/src/main/java/docking/EditWindow.java index bc1e21c2e1..9512e3eb65 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/EditWindow.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/EditWindow.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +22,8 @@ import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import generic.theme.GThemeDefaults.Colors; + /** * A re-usable floating text edit window. */ @@ -34,7 +35,7 @@ public class EditWindow extends JWindow { private Component comp; private Rectangle rect; private EditListener listener; - + private AssociatedComponentListener compListener = new AssociatedComponentListener(); /** @@ -46,7 +47,7 @@ public class EditWindow extends JWindow { this.mgr = mgr; create(); } - + Component getAssociatedComponent() { return comp; } @@ -55,7 +56,7 @@ public class EditWindow extends JWindow { * @see java.awt.Window#isActive() */ @Override - public boolean isActive() { + public boolean isActive() { return active; } @@ -63,16 +64,16 @@ public class EditWindow extends JWindow { * @see java.awt.Component#setVisible(boolean) */ @Override - public void setVisible(boolean state) { - + public void setVisible(boolean state) { + active = state; super.setVisible(state); - + if (!state) { if (comp != null) { comp.removeComponentListener(compListener); if (comp instanceof JTabbedPane) { - ((JTabbedPane)comp).removeChangeListener(compListener); + ((JTabbedPane) comp).removeChangeListener(compListener); } Frame frame = mgr.getRootFrame(); frame.removeComponentListener(compListener); @@ -81,7 +82,7 @@ public class EditWindow extends JWindow { } } } - + void close() { setVisible(false); dispose(); @@ -90,55 +91,55 @@ public class EditWindow extends JWindow { void show(String defaultText, Component c, Rectangle r, EditListener editListener) { if (comp != null) { - setVisible(false); + setVisible(false); } - + if (c == null || !c.isVisible()) { return; } - + this.comp = c; this.rect = r; this.listener = editListener; - + comp.addComponentListener(compListener); - + if (comp instanceof JTabbedPane) { - ((JTabbedPane)comp).addChangeListener(compListener); + ((JTabbedPane) comp).addChangeListener(compListener); } - + Frame frame = mgr.getRootFrame(); frame.addComponentListener(compListener); setLocation(); - + textField.setText(defaultText != null ? defaultText : ""); Dimension d = textField.getPreferredSize(); textField.setPreferredSize(new Dimension(rect.width, d.height)); pack(); - + setVisible(true); - + toFront(); - textField.requestFocus(); - textField.selectAll(); + textField.requestFocus(); + textField.selectAll(); } - + private void setLocation() { Point p = comp.getLocationOnScreen(); - setLocation(p.x+rect.x+3, p.y+rect.y); + setLocation(p.x + rect.x + 3, p.y + rect.y); } - + private void create() { textField = new JTextField(" "); JPanel panel = new JPanel(new BorderLayout()); - Color bgColor = new Color(255, 255, 195); + Color bgColor = Colors.BACKGROUND_TOOLTIP; panel.setBackground(bgColor); - panel.add(textField, BorderLayout.CENTER); + panel.add(textField, BorderLayout.CENTER); textField.addKeyListener(new KeyAdapter() { @Override - public void keyPressed(KeyEvent e) { + public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { close(); } @@ -146,51 +147,53 @@ public class EditWindow extends JWindow { }); textField.addFocusListener(new FocusAdapter() { @Override - public void focusLost(FocusEvent e) { - if ( !e.isTemporary() ) { - close(); - } + public void focusLost(FocusEvent e) { + if (!e.isTemporary()) { + close(); + } } }); - textField.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (listener != null) { - String text = textField.getText(); - EditListener l = listener; - close(); - l.editCompleted(text); - } + textField.addActionListener(e -> { + if (listener != null) { + String text = textField.getText(); + EditListener l = listener; + close(); + l.editCompleted(text); } }); getContentPane().add(panel, BorderLayout.CENTER); } - + private class AssociatedComponentListener implements ComponentListener, ChangeListener { - + /* * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent) */ + @Override public void componentHidden(ComponentEvent e) { close(); } - + /* * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent) */ + @Override public void componentResized(ComponentEvent e) { close(); } - + /* * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent) */ + @Override public void componentShown(ComponentEvent e) { } - + /* * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent) */ + @Override public void componentMoved(ComponentEvent e) { if (comp != null && comp.isVisible()) { setLocation(); @@ -200,6 +203,7 @@ public class EditWindow extends JWindow { /* * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) */ + @Override public void stateChanged(ChangeEvent e) { close(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ErrLogExpandableDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/ErrLogExpandableDialog.java index aa8674bb60..fed06a9180 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ErrLogExpandableDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ErrLogExpandableDialog.java @@ -31,19 +31,18 @@ import javax.swing.tree.TreePath; import docking.widgets.label.GHtmlLabel; import docking.widgets.tree.*; import docking.widgets.tree.support.GTreeDragNDropHandler; +import generic.theme.GIcon; import ghidra.util.*; import ghidra.util.exception.MultipleCauses; import ghidra.util.html.HTMLElement; -import resources.ResourceManager; import util.CollectionUtils; public class ErrLogExpandableDialog extends AbstractErrDialog { - public static ImageIcon IMG_REPORT = ResourceManager.loadImage("images/report.png"); - public static ImageIcon IMG_EXCEPTION = ResourceManager.loadImage("images/exception.png"); - public static ImageIcon IMG_FRAME_ELEMENT = - ResourceManager.loadImage("images/StackFrameElement.png"); - public static ImageIcon IMG_STACK = ResourceManager.loadImage("images/StackFrame_Red.png"); - public static ImageIcon IMG_CAUSE = ResourceManager.loadImage("images/cause.png"); + public static Icon IMG_REPORT = new GIcon("icon.dialog.error.expandable.report"); + public static Icon IMG_EXCEPTION = new GIcon("icon.dialog.error.expandable.exception"); + public static Icon IMG_FRAME_ELEMENT = new GIcon("icon.dialog.error.expandable.frame"); + public static Icon IMG_STACK = new GIcon("icon.dialog.error.expandable.stack"); + public static Icon IMG_CAUSE = new GIcon("icon.dialog.error.expandable.cause"); private static final String SEND = "Send Report..."; private static final String DETAIL = "Details >>>"; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/GenericHeader.java b/Ghidra/Framework/Docking/src/main/java/docking/GenericHeader.java index ab224f95fb..8252b8598a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/GenericHeader.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/GenericHeader.java @@ -29,16 +29,22 @@ import docking.action.DockingActionIf; import docking.util.AnimationUtils; import docking.widgets.VariableHeightPanel; import docking.widgets.label.GDLabel; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.GThemeDefaults.Colors.Palette; // TODO: should this be put into generic? public class GenericHeader extends JPanel { - private static final Color NON_FOCUS_START_COLOR = new Color(150, 150, 150); - private static final Color FOCUS_START_COLOR = new Color(30, 30, 150); + private static final Color NON_FOCUS_START_COLOR = new GColor("color.bg.header.inactive"); + private static final Color FOCUS_START_COLOR = new GColor("color.bg.header.active"); private static final int MINIMUM_TITLE_SIZE = 80; private Color nonFocusColor = NON_FOCUS_START_COLOR; private Color focusColor = FOCUS_START_COLOR; + private Color activeForeground = new GColor("color.fg.header.active"); + private Color inactiveForeground = new GColor("color.fg.header.inactive"); protected Component component; protected DockableToolBarManager toolBarMgr; @@ -68,7 +74,7 @@ public class GenericHeader extends JPanel { BorderLayout layout = new BorderLayout(); layout.setVgap(1); setLayout(layout); - setBorder(BorderFactory.createLineBorder(Color.GRAY)); + setBorder(BorderFactory.createLineBorder(Palette.GRAY)); setFocusable(false); titlePanel = new TitlePanel(); @@ -206,7 +212,7 @@ public class GenericHeader extends JPanel { private void constructMultiLinePanel() { removeAll(); - toolbar.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.BLACK)); + toolbar.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Java.BORDER)); add(toolbar, BorderLayout.SOUTH); add(titlePanel, BorderLayout.CENTER); add(menuCloseToolbar, BorderLayout.EAST); @@ -294,11 +300,7 @@ public class GenericHeader extends JPanel { TitleFlasher() { animator = PropertySetter.createAnimator(1000, this, "color", NON_FOCUS_START_COLOR, - NON_FOCUS_START_COLOR, Color.YELLOW, FOCUS_START_COLOR); - -// animator = -// PropertySetter.createAnimator(1000, this, "color", NON_FOCUS_START_COLOR, -// NON_FOCUS_START_COLOR, Color.YELLOW, FOCUS_START_COLOR); + NON_FOCUS_START_COLOR, Palette.YELLOW, FOCUS_START_COLOR); animator.setAcceleration(0.2f); animator.setDeceleration(0.8f); @@ -347,7 +349,7 @@ public class GenericHeader extends JPanel { setFocusable(false); titleLabel = new GDLabel(); titleLabel.setBorder(BorderFactory.createEmptyBorder(0, 6, 0, 0)); - titleLabel.setForeground(Color.BLACK); + titleLabel.setForeground(Colors.FOREGROUND); titleLabel.setFocusable(false); add(titleLabel, BorderLayout.CENTER); } @@ -419,7 +421,7 @@ public class GenericHeader extends JPanel { */ void setSelected(boolean state) { isSelected = state; - titleLabel.setForeground(state ? Color.WHITE : Color.BLACK); + titleLabel.setForeground(state ? activeForeground : inactiveForeground); repaint(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java b/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java index a5b03c1574..cf88ecc39c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/HeaderCursor.java @@ -19,11 +19,20 @@ import java.awt.*; import java.awt.dnd.DragSource; import java.awt.image.BufferedImage; +import generic.theme.*; + /** * The cursor values used when drag-n-dropping dockable components */ public class HeaderCursor { + private static final GColor CURSOR_COLOR = new GColor("color.header.drag.cursor"); + private static final ThemeListener THEME_LISTENER = event -> { + if (event.isColorChanged(CURSOR_COLOR.getId())) { + initilizeCursors(); + } + }; + static Cursor LEFT; static Cursor RIGHT; static Cursor TOP; @@ -33,6 +42,12 @@ public class HeaderCursor { static Cursor NO_DROP = DragSource.DefaultMoveNoDrop; static { + initilizeCursors(); + + Gui.addThemeListener(THEME_LISTENER); + } + + private static void initilizeCursors() { Toolkit tk = Toolkit.getDefaultToolkit(); Image image = drawLeftArrow(); @@ -57,7 +72,7 @@ public class HeaderCursor { private static Image drawLeftArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int y = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -76,7 +91,7 @@ public class HeaderCursor { private static Image drawRightArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int y = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -95,7 +110,7 @@ public class HeaderCursor { private static Image drawTopArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int x = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -113,7 +128,7 @@ public class HeaderCursor { private static Image drawBottomArrow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); int x = 6; for (int i = 0; i < 6; i++) { for (int j = 0; j < 2 * i + 1; j++) { @@ -131,7 +146,7 @@ public class HeaderCursor { private static Image drawStack() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int v = CURSOR_COLOR.getRGB(); for (int i = 0; i < 3; i++) { int x = i * 3; int y = 6 - i * 3; @@ -149,10 +164,11 @@ public class HeaderCursor { private static Image drawNewWindow() { BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); - int v = 0xff000000; + int headerColor = new GColor("color.bg.header.active").getRGB(); + int v = CURSOR_COLOR.getRGB(); for (int i = 0; i < 5; i++) { for (int j = 0; j < 14; j++) { - image.setRGB(j, i, 0xff0000ff); + image.setRGB(j, i, headerColor); } } for (int i = 0; i < 14; i++) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ShowComponentAction.java b/Ghidra/Framework/Docking/src/main/java/docking/ShowComponentAction.java index 35d96ba10b..87dc4a7427 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ShowComponentAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ShowComponentAction.java @@ -16,12 +16,11 @@ package docking; import javax.swing.Icon; -import javax.swing.ImageIcon; import docking.action.*; import docking.actions.AutoGeneratedDockingAction; import ghidra.util.HelpLocation; -import resources.ResourceManager; +import resources.Icons; /** * Action for showing components. If the component is hidden it will be made visible. @@ -31,8 +30,7 @@ class ShowComponentAction extends DockingAction implements AutoGeneratedDockingAction, Comparable { private static final int MAX_LENGTH = 40; - protected static final ImageIcon EMPTY_ICON = - ResourceManager.loadImage("images/EmptyIcon16.gif"); + protected static final Icon EMPTY_ICON = Icons.EMPTY_ICON; protected static final String MENU_WINDOW = "&" + DockingWindowManager.COMPONENT_MENU_NAME; protected DockingWindowManager winMgr; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ShowWindowAction.java b/Ghidra/Framework/Docking/src/main/java/docking/ShowWindowAction.java index ecc997bdf6..641f04ae5c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ShowWindowAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ShowWindowAction.java @@ -21,13 +21,13 @@ import docking.action.DockingAction; import docking.action.MenuData; import docking.actions.AutoGeneratedDockingAction; import docking.tool.ToolConstants; +import generic.theme.GIcon; import ghidra.util.HelpLocation; -import resources.ResourceManager; class ShowWindowAction extends DockingAction implements AutoGeneratedDockingAction, Comparable { - private static final Icon ICON = ResourceManager.loadImage("images/application_xp.png"); + private static final Icon ICON = new GIcon("icon.window"); private static final String MENU_WINDOW = "&" + DockingWindowManager.COMPONENT_MENU_NAME; private static final int MAX_LENGTH = 40; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java index 1e095352bd..9a3d9cea87 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/SplitPanel.java @@ -22,6 +22,8 @@ import java.awt.event.MouseMotionAdapter; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import generic.theme.GColor; + public class SplitPanel extends JPanel { private static int DIVIDER_SIZE = 4; private Component leftComp; @@ -38,7 +40,7 @@ public class SplitPanel extends JPanel { this.rightComp = rightComp; this.isHorizontal = isHorizontal; divider = new Divider(); - divider.setBackground(Color.LIGHT_GRAY); + divider.setBackground(new GColor("SplitPane.background")); add(leftComp); add(divider); add(rightComp); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/StatusBar.java b/Ghidra/Framework/Docking/src/main/java/docking/StatusBar.java index 0576a65e2e..9ed42d82cf 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/StatusBar.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/StatusBar.java @@ -30,6 +30,8 @@ import org.jdesktop.animation.timing.Animator; import docking.util.AnimationUtils; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.Gui; import generic.util.WindowUtilities; import ghidra.util.*; import ghidra.util.layout.HorizontalLayout; @@ -196,7 +198,7 @@ public class StatusBar extends JPanel { String updatedText = fixupMultilineText(text); statusLabel.setText(updatedText); statusLabel.setToolTipText(getToolTipText()); - statusLabel.setForeground(Color.BLACK); + statusLabel.setForeground(Colors.FOREGROUND); if (StringUtils.isBlank(updatedText)) { return; @@ -304,24 +306,40 @@ public class StatusBar extends JPanel { private FadeTimer() { super(5000, null); addActionListener(this); - initFadeColors(); } private void initFadeColors() { - fadeColorMap.put(Color.BLACK, new Color(16, 16, 16)); - fadeColorMap.put(new Color(16, 16, 16), new Color(32, 32, 32)); - fadeColorMap.put(new Color(32, 32, 32), new Color(64, 64, 64)); - fadeColorMap.put(new Color(64, 64, 64), new Color(80, 80, 80)); - fadeColorMap.put(new Color(80, 80, 80), new Color(96, 96, 96)); - fadeColorMap.put(new Color(96, 96, 96), new Color(112, 112, 112)); - fadeColorMap.put(new Color(112, 112, 112), new Color(128, 128, 128)); + + int value = 0; + int delta = 16; + if (Gui.isDarkTheme()) { + value = 128; + delta = -16; + } + + Color start = ColorUtils.getColor(value, value, value); + fadeColorMap.put(statusLabel.getForeground(), start); + + for (int i = 0; i < 8; i++) { + + Color from = ColorUtils.getColor(value, value, value); + value += delta; + Color to = ColorUtils.getColor(value, value, value); + fadeColorMap.put(from, to); + } + } + + @Override + public void restart() { + initFadeColors(); + super.restart(); } @Override public void actionPerformed(ActionEvent event) { Color nextFadeColor = fadeColorMap.get(statusLabel.getForeground()); - if (nextFadeColor != null) { + statusLabel.setForeground(nextFadeColor); } else { @@ -385,7 +403,7 @@ public class StatusBar extends JPanel { int red = color.getRed(); int green = color.getGreen(); int blue = color.getBlue(); - return new Color((255 - red), (255 - green), (255 - blue)); + return ColorUtils.getColor((255 - red), (255 - green), (255 - blue)); } private void contrastStatusLabelColors() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/StatusBarSpacer.java b/Ghidra/Framework/Docking/src/main/java/docking/StatusBarSpacer.java index 10bb194fc8..1225e447e0 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/StatusBarSpacer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/StatusBarSpacer.java @@ -18,16 +18,16 @@ package docking; import javax.swing.Icon; import docking.widgets.label.GIconLabel; +import generic.theme.GIcon; import ghidra.framework.OperatingSystem; import ghidra.framework.Platform; -import resources.ResourceManager; /** * A class to handle the space requirements on the status bar that vary for different OSes. For * example, the Mac requires extra space on the status bar, due to the drag icon the Mac uses. */ public class StatusBarSpacer extends GIconLabel { - private static Icon EMPTY_ICON = ResourceManager.loadImage("images/EmptyIcon.gif"); + private static Icon EMPTY_ICON = new GIcon("icon.empty.20"); public StatusBarSpacer() { super( diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/ComponentThemeInspectorAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/ComponentThemeInspectorAction.java new file mode 100644 index 0000000000..a23b59e0b9 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/ComponentThemeInspectorAction.java @@ -0,0 +1,273 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.action; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.swing.*; +import javax.swing.table.TableCellRenderer; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; + +import org.apache.commons.lang3.StringUtils; + +import docking.ActionContext; +import docking.DockingWindowManager; +import generic.util.action.ReservedKeyBindings; +import ghidra.util.Msg; + +public class ComponentThemeInspectorAction extends DockingAction { + + public ComponentThemeInspectorAction() { + super("Component Theme Inspector", DockingWindowManager.DOCKING_WINDOWS_OWNER, false); + createReservedKeyBinding(ReservedKeyBindings.COMPONENT_THEME_INFO_KEY); + + // System action; no help needed + DockingWindowManager.getHelpService().excludeFromHelp(this); + } + + private Object getMouseOverObject() { + + PointerInfo pointerInfo = MouseInfo.getPointerInfo(); + Point mouseLocation = pointerInfo.getLocation(); + Object lastObject = DockingWindowManager.getMouseOverObject(); + + if (!(lastObject instanceof Component)) { + return lastObject; + } + + Component c = (Component) lastObject; + Window w; + if (c instanceof Window) { + w = (Window) c; + } + else { + w = SwingUtilities.windowForComponent(c); + } + + if (w != null) { + + SwingUtilities.convertPointFromScreen(mouseLocation, w); + Component deepestComponent = + SwingUtilities.getDeepestComponentAt(w, mouseLocation.x, mouseLocation.y); + if (deepestComponent != null) { + return deepestComponent; + } + } + + return lastObject; + } + + @Override + public void actionPerformed(ActionContext context) { + + Object object = getMouseOverObject(); + if (!(object instanceof Component)) { + Msg.debug(this, "Mouse not over a component: " + object); + return; + } + + Entry entry = null; + Component component = (Component) object; + List tree = new ArrayList<>(); + while (component != null) { + + Entry next; + if (component instanceof JTable) { + next = new TableEntry((JTable) component); + } + else if (component instanceof JTree) { + next = new TreeEntry((JTree) component); + } + else { + next = new Entry(component); + } + + if (entry != null) { + entry.parent = next; + } + entry = next; + + tree.add(entry); + component = component.getParent(); + } + + Collections.reverse(tree); + + StringBuilder buffy = new StringBuilder("\n"); + for (int i = 0; i < tree.size() - 1; i++) { + Entry e = tree.get(i); + e.toString(buffy, i + 1); // +1 to start printing at 1, as an ordinal + } + + buffy.append('\n'); + Entry hoveredEntry = tree.get(tree.size() - 1); + hoveredEntry.toString(buffy, 0); // no indent for the hovered item so it is easy to see + buffy.append('\n'); + Msg.debug(this, buffy); + } + + private void print(StringBuilder buffy, Component component, int indent) { + + Color bg = component.getBackground(); + Color fg = component.getForeground(); + String id; + String clazz = component.getClass().getSimpleName(); + if (clazz.isEmpty()) { + clazz = component.getClass().getName(); + } + String name = component.getName(); + if (name == null) { + id = clazz; + } + else { + id = clazz + "; name = " + name; + } + + String indentMarker = ""; + String spacer = ""; + if (indent > 0) { + indentMarker = Integer.toString(indent) + ") "; + + String asString = Integer.toString(indent); + int length = asString.length(); + spacer = StringUtils.repeat(' ', length + 2); // +2 for the text ") " + } + else { + // no indent; custom spacing of attributes + spacer = "\t"; + } + + String tabs = '\n' + StringUtils.repeat(' ', (indent * 3)); + buffy.append(tabs) + .append(indentMarker) + .append(id) + .append(tabs) + .append(spacer) + .append("bg: ") + .append(bg) + .append(tabs) + .append(spacer) + .append("fg: ") + .append(fg) + .append('\n'); + } + + private void debugComponent(Component component) { + // stub for debugging + } + + private void debugTable(TableCellRenderer renderer, Component component, + Component rendererComponent) { + // stub for debugging + } + + @Override + public boolean isEnabledForContext(ActionContext context) { + return true; + } + + private class Entry { + + private Entry parent; + protected Component component; + protected Point mouseLocation; + + Entry(Component component) { + this.component = component; + + PointerInfo pointerInfo = MouseInfo.getPointerInfo(); + mouseLocation = pointerInfo.getLocation(); + SwingUtilities.convertPointFromScreen(mouseLocation, component); + } + + public void toString(StringBuilder buffy, int indent) { + debugComponent(component); + print(buffy, component, indent); + } + + protected boolean isLeaf(int indent) { + return indent == 0; + } + } + + private class TableEntry extends Entry { + private JTable table; + + TableEntry(JTable table) { + super(table); + this.table = table; + } + + @Override + public void toString(StringBuilder buffy, int indent) { + print(buffy, component, indent); + + if (!isLeaf(indent)) { + return; + } + + // print extra data for the leaf component, as that is the hovered component + int row = table.rowAtPoint(mouseLocation); + int col = table.columnAtPoint(mouseLocation); + + if (row != -1 && col != -1) { + TableCellRenderer renderer = table.getCellRenderer(row, col); + Component rendererComponent = table.prepareRenderer(renderer, row, col); + debugTable(renderer, component, rendererComponent); + + print(buffy, rendererComponent, indent); + } + } + } + + private class TreeEntry extends Entry { + private JTree tree; + + TreeEntry(JTree tree) { + super(tree); + this.tree = tree; + } + + @Override + public void toString(StringBuilder buffy, int indent) { + print(buffy, component, indent); + + if (!isLeaf(indent)) { + return; + } + + // print extra data for the leaf component, as that is the hovered component + TreeCellRenderer renderer = tree.getCellRenderer(); + int row = tree.getClosestRowForLocation(mouseLocation.x, mouseLocation.y); + + if (row != -1) { + TreePath path = tree.getPathForRow(row); + Object pathValue = path.getLastPathComponent(); + Component rendererComponent = + renderer.getTreeCellRendererComponent(tree, pathValue, tree.isRowSelected(row), + tree.isExpanded(row), tree.getModel().isLeaf(pathValue), row, + true); + + print(buffy, rendererComponent, indent); + } + } + + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingsManager.java b/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingsManager.java index f2e9140e5c..b3585703b7 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingsManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/KeyBindingsManager.java @@ -24,7 +24,7 @@ import javax.swing.Action; import javax.swing.KeyStroke; import docking.*; -import ghidra.util.ReservedKeyBindings; +import generic.util.action.ReservedKeyBindings; import ghidra.util.exception.AssertException; /** diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusCycleAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusCycleAction.java index ea6b7b4695..4b24f27eef 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusCycleAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusCycleAction.java @@ -24,7 +24,7 @@ import org.apache.logging.log4j.Logger; import docking.ActionContext; import docking.DockingWindowManager; -import ghidra.util.ReservedKeyBindings; +import generic.util.action.ReservedKeyBindings; public class ShowFocusCycleAction extends DockingAction { static final Logger log = LogManager.getLogger(ShowFocusCycleAction.class); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusInfoAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusInfoAction.java index 806dcbd6fa..2c489bfc25 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusInfoAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/ShowFocusInfoAction.java @@ -25,7 +25,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import docking.*; -import ghidra.util.ReservedKeyBindings; +import generic.util.action.ReservedKeyBindings; public class ShowFocusInfoAction extends DockingAction { static final Logger log = LogManager.getLogger(ShowFocusInfoAction.class); @@ -82,6 +82,7 @@ public class ShowFocusInfoAction extends DockingAction { Object mouseOverObject = DockingWindowManager.getMouseOverObject(); if (mouseOverObject instanceof Component) { log.info("Mouse-over Object: " + printComp((Component) mouseOverObject)); + log.info("Focusable?: " + ((Component) mouseOverObject).isFocusable()); } log.info(""); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java index 030ca16eb6..7e1a114377 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java @@ -27,9 +27,10 @@ import docking.KeyEntryTextField; import docking.action.*; import docking.tool.ToolConstants; import docking.widgets.label.GIconLabel; +import generic.theme.GThemeDefaults.Colors.Messages; +import generic.util.action.ReservedKeyBindings; import ghidra.util.HelpLocation; -import ghidra.util.ReservedKeyBindings; -import resources.ResourceManager; +import resources.Icons; /** * Dialog to set the key binding on an action; it is popped up when the F4 key @@ -69,7 +70,7 @@ public class KeyEntryDialog extends DialogComponentProvider { defaultPanel = new JPanel(new BorderLayout()); defaultPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 5)); - JLabel imageLabel = new GIconLabel(ResourceManager.loadImage("images/information.png")); + JLabel imageLabel = new GIconLabel(Icons.INFO_ICON); bgColor = imageLabel.getBackground(); JTextPane pane = new JTextPane(); pane.setBorder(BorderFactory.createEmptyBorder(0, 5, 2, 5)); @@ -172,7 +173,7 @@ public class KeyEntryDialog extends DialogComponentProvider { textAttrSet = new SimpleAttributeSet(); textAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma"); textAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11)); - textAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE); + textAttrSet.addAttribute(StyleConstants.Foreground, Messages.NORMAL); tabAttrSet = new SimpleAttributeSet(); TabStop tabs = new TabStop(20, StyleConstants.ALIGN_LEFT, TabStop.LEAD_NONE); @@ -206,9 +207,7 @@ public class KeyEntryDialog extends DialogComponentProvider { String ksName = KeyBindingUtils.parseKeyStroke(ks); try { doc.insertString(0, "Actions mapped to " + ksName + "\n\n", textAttrSet); - for (int i = 0; i < list.size(); i++) { - DockingActionIf a = list.get(i); - + for (DockingActionIf a : list) { String collisionStr = "\t" + a.getName() + " (" + a.getOwnerDescription() + ")\n"; int offset = doc.getLength(); doc.insertString(offset, collisionStr, textAttrSet); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java index 7a7d2ebd00..171e2a20c3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java @@ -32,6 +32,7 @@ import org.apache.commons.collections4.map.LazyMap; import docking.*; import docking.action.*; import docking.tool.util.DockingToolConstants; +import generic.util.action.ReservedKeyBindings; import ghidra.framework.options.*; import ghidra.util.*; import ghidra.util.exception.AssertException; @@ -99,6 +100,7 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener { if (SystemUtilities.isInDevelopmentMode()) { keyBindingsManager.addReservedAction(new ShowFocusInfoAction()); keyBindingsManager.addReservedAction(new ShowFocusCycleAction()); + keyBindingsManager.addReservedAction(new ComponentThemeInspectorAction()); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/framework/AboutDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/framework/AboutDialog.java index 14599e1452..58a7c14c2f 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/framework/AboutDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/framework/AboutDialog.java @@ -16,12 +16,14 @@ package docking.framework; import java.awt.BorderLayout; -import java.awt.Color; import javax.swing.*; import docking.DialogComponentProvider; import docking.DockingWindowManager; +import generic.theme.GThemeDefaults.Colors; +import ghidra.framework.Application; +import utility.application.ApplicationLayout; /** * Splash screen window to display version information about the current release of @@ -29,7 +31,6 @@ import docking.DockingWindowManager; * initialization is complete, the splash screen is dismissed. */ public class AboutDialog extends DialogComponentProvider { - private static final Color DEFAULT_BACKGROUND_COLOR = new Color(243, 250, 255); public AboutDialog() { super(ApplicationInformationDisplayFactory.createAboutTitle(), true, false, true, false); @@ -57,7 +58,7 @@ public class AboutDialog extends DialogComponentProvider { private JPanel createMainPanel() { JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.setBorder(BorderFactory.createRaisedBevelBorder()); - mainPanel.setBackground(DEFAULT_BACKGROUND_COLOR); + mainPanel.setBackground(Colors.BACKGROUND); mainPanel.add(createInfoComponent(), BorderLayout.CENTER); return mainPanel; } @@ -67,6 +68,10 @@ public class AboutDialog extends DialogComponentProvider { } public static void main(String[] args) throws Exception { + ApplicationLayout layout = new DockingApplicationLayout("About Dialog", "1.0"); + DockingApplicationConfiguration config = new DockingApplicationConfiguration(); + config.setShowSplashScreen(false); + Application.initializeApplication(layout, config); DockingWindowManager.showDialog(null, new AboutDialog()); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/framework/ApplicationInformationDisplayFactory.java b/Ghidra/Framework/Docking/src/main/java/docking/framework/ApplicationInformationDisplayFactory.java index 74e41a53f1..94d5a40d59 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/framework/ApplicationInformationDisplayFactory.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/framework/ApplicationInformationDisplayFactory.java @@ -23,14 +23,19 @@ import javax.swing.*; import docking.widgets.label.GIconLabel; import docking.widgets.label.GLabel; +import generic.theme.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.framework.Application; import ghidra.framework.PluggableServiceRegistry; import ghidra.util.HelpLocation; import ghidra.util.Msg; -import resources.ResourceManager; public class ApplicationInformationDisplayFactory { + private static final String ICON_HOME = "icon.docking.application.home"; + private static final String ICON_16 = "icon.docking.application.16"; + private static final String ICON_128 = "icon.docking.application.128"; + static { PluggableServiceRegistry.registerPluggableService( ApplicationInformationDisplayFactory.class, new ApplicationInformationDisplayFactory()); @@ -70,7 +75,7 @@ public class ApplicationInformationDisplayFactory { return bestImageSoFar; } - public static ImageIcon getHomeIcon() { + public static Icon getHomeIcon() { ApplicationInformationDisplayFactory factory = PluggableServiceRegistry.getPluggableService( ApplicationInformationDisplayFactory.class); return factory.doGetHomeIcon(); @@ -115,13 +120,12 @@ public class ApplicationInformationDisplayFactory { final JPanel panel = new JPanel(new BorderLayout()); panel.setPreferredSize(new Dimension(400, 400)); - Color background = Color.BLACK; - + Color background = new GColor("color.bg.splashscreen"); panel.setBackground(background); JLabel nameLabel = new GLabel(Application.getName()); - nameLabel.setForeground(new Color(155, 155, 155)); - Font newFont = new Font("Garamond", Font.BOLD, 35); + nameLabel.setForeground(Palette.GRAY); + Font newFont = Gui.getFont("font.splash.header.default"); nameLabel.setFont(newFont); nameLabel.setHorizontalAlignment(SwingConstants.CENTER); nameLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); @@ -139,14 +143,14 @@ public class ApplicationInformationDisplayFactory { return panel; } - protected ImageIcon getSplashScreenIcon128() { - return ResourceManager.loadImage("images/www_128.png"); + protected Icon getSplashScreenIcon128() { + return new GIcon(ICON_128); } protected List doGetWindowIcons() { List list = new ArrayList<>(); - list.add(ResourceManager.loadImage("images/www_128.png").getImage()); - list.add(ResourceManager.loadImage("images/www_16.png").getImage()); + list.add(new GIcon(ICON_128).getImageIcon().getImage()); + list.add(new GIcon(ICON_16).getImageIcon().getImage()); return list; } @@ -158,8 +162,8 @@ public class ApplicationInformationDisplayFactory { return null; } - protected ImageIcon doGetHomeIcon() { - return ResourceManager.loadImage("images/www_16.png"); + protected Icon doGetHomeIcon() { + return new GIcon(ICON_HOME); } protected Runnable doGetHomeCallback() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationConfiguration.java b/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationConfiguration.java index aa57f15fe5..fef37b3cf4 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationConfiguration.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationConfiguration.java @@ -17,7 +17,8 @@ package docking.framework; import docking.DockingErrorDisplay; import docking.widgets.PopupKeyStorePasswordProvider; -import ghidra.docking.util.DockingWindowsLookAndFeelUtils; +import generic.theme.ApplicationThemeManager; +import ghidra.docking.util.LookAndFeelUtils; import ghidra.framework.ApplicationConfiguration; import ghidra.net.ApplicationKeyManagerFactory; import ghidra.util.ErrorDisplay; @@ -48,14 +49,15 @@ public class DockingApplicationConfiguration extends ApplicationConfiguration { protected void initializeApplication() { super.initializeApplication(); - DockingWindowsLookAndFeelUtils.loadFromPreferences(); + ApplicationThemeManager.initialize(); + LookAndFeelUtils.performPlatformSpecificFixups(); if (showSplashScreen) { SplashScreen.showSplashScreen(); } - ApplicationKeyManagerFactory.setKeyStorePasswordProvider( - new PopupKeyStorePasswordProvider()); + ApplicationKeyManagerFactory + .setKeyStorePasswordProvider(new PopupKeyStorePasswordProvider()); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationLayout.java b/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationLayout.java index d169142e32..ce42b87d9f 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationLayout.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/framework/DockingApplicationLayout.java @@ -15,12 +15,16 @@ */ package docking.framework; +import java.io.File; import java.io.FileNotFoundException; -import java.util.Collection; -import java.util.Objects; +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; @@ -36,6 +40,10 @@ public class DockingApplicationLayout 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. * @@ -74,6 +82,7 @@ public class DockingApplicationLayout extends ApplicationLayout { this.applicationProperties = Objects.requireNonNull(applicationProperties); this.applicationRootDirs = applicationRootDirs; + applicationRootDirs.addAll(getAdditionalApplicationRootDirs(applicationRootDirs)); // Application installation directory applicationInstallationDir = applicationRootDirs.iterator().next().getParentFile(); @@ -102,6 +111,53 @@ public class DockingApplicationLayout extends ApplicationLayout { applicationInstallationDir); } + protected Collection getAdditionalApplicationRootDirs( + Collection roots) { + return Collections.emptyList(); + } + + protected Map 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 roots = + ModuleUtilities.findModuleRootDirectories(applicationRootDirs, new ArrayList<>()); + Map 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 cpNames = getClassPathModuleNames(); + Map filteredModules = new HashMap<>(); + Set> entrySet = allModules.entrySet(); + for (Entry entry : entrySet) { + GModule module = entry.getValue(); + if (cpNames.contains(module.getName())) { + filteredModules.put(entry.getKey(), module); + } + } + + return filteredModules; + } + + private Set getClassPathModuleNames() { + String cp = System.getProperty("java.class.path"); + String[] pathParts = cp.split(File.pathSeparator); + Set paths = new HashSet<>(Arrays.asList(pathParts)); + Set 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. diff --git a/Ghidra/Framework/Docking/src/main/java/docking/framework/SplashScreen.java b/Ghidra/Framework/Docking/src/main/java/docking/framework/SplashScreen.java index 6deff243de..a3c3a99b74 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/framework/SplashScreen.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/framework/SplashScreen.java @@ -24,7 +24,8 @@ import javax.swing.border.BevelBorder; import docking.*; import docking.widgets.label.GDLabel; -import docking.widgets.label.GLabel; +import generic.theme.GColor; +import generic.theme.Gui; import generic.util.WindowUtilities; import ghidra.framework.Application; import ghidra.util.Msg; @@ -37,7 +38,9 @@ import utility.application.ApplicationLayout; */ public class SplashScreen extends JWindow { - private static final Color DEFAULT_BACKGROUND_COLOR = new Color(243, 250, 255); + private static final Color BG_COLOR = new GColor("color.bg.splashscreen"); + + private static final String FONT_ID = "font.splash.status"; private static SplashScreen splashWindow; // splash window displayed while ghidra is coming up private static DockingFrame hiddenFrame; @@ -250,7 +253,7 @@ public class SplashScreen extends JWindow { List list = ApplicationInformationDisplayFactory.getWindowIcons(); hiddenFrame.setIconImages(list); hiddenFrame.setUndecorated(true); - hiddenFrame.setTransient(); + hiddenFrame.setTransient(); } return hiddenFrame; } @@ -286,8 +289,7 @@ public class SplashScreen extends JWindow { private JPanel createMainPanel() { JPanel mainPanel = new JPanel(new BorderLayout()); - mainPanel.setBackground(DEFAULT_BACKGROUND_COLOR); - mainPanel.add(createTitlePanel(), BorderLayout.NORTH); + mainPanel.setBackground(BG_COLOR); mainPanel.add(createContentPanel(), BorderLayout.CENTER); return mainPanel; } @@ -300,38 +302,12 @@ public class SplashScreen extends JWindow { return contentPanel; } - private Component createTitlePanel() { - Color backgroundColor = UIManager.getColor("InternalFrame.activeTitleBackground"); - Color foregroundColor = UIManager.getColor("InternalFrame.activeTitleForeground"); - - JPanel titlePanel = new JPanel(); - if (backgroundColor == null) { - backgroundColor = new Color(0, 0, 255); - } - titlePanel.setBackground(backgroundColor); - titlePanel.setLayout(new BorderLayout()); - - JLabel titleLabel = - new GLabel(ApplicationInformationDisplayFactory.createSplashScreenTitle()); - Font font = titleLabel.getFont(); - font = new Font(font.getName(), Font.BOLD, 11); - titleLabel.setFont(font); - if (foregroundColor == null) { - foregroundColor = Color.white; - } - titleLabel.setForeground(foregroundColor); - titlePanel.add(titleLabel, BorderLayout.CENTER); - titlePanel.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10)); - return titlePanel; - } - private Component createStatusComponent() { - Font f = new Font("serif", Font.BOLD, 12); statusLabel = new GDLabel(" Loading..."); - statusLabel.setFont(f); + Gui.registerFont(statusLabel, FONT_ID); + statusLabel.setFont(Gui.getFont(FONT_ID)); statusLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 2, 10)); - statusLabel.setBackground(DEFAULT_BACKGROUND_COLOR); statusLabel.setOpaque(true); return statusLabel; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/help/DockingHelpBroker.java b/Ghidra/Framework/Docking/src/main/java/docking/help/DockingHelpBroker.java index 04d8054c5d..7049358cdf 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/help/DockingHelpBroker.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/help/DockingHelpBroker.java @@ -37,6 +37,7 @@ import org.jdesktop.animation.timing.TimingTargetAdapter; import docking.framework.ApplicationInformationDisplayFactory; import docking.util.AnimationPainter; import docking.util.AnimationUtils; +import generic.theme.GColor; import ghidra.framework.preferences.Preferences; import ghidra.util.Msg; import ghidra.util.Swing; @@ -398,7 +399,7 @@ public class DockingHelpBroker extends GHelpBroker { private class LocationHintPainter implements AnimationPainter { - private Color color = new Color(100, 100, 255, 100); + private Color color = new GColor("color.bg.help.hint"); private Shape paintShape; LocationHintPainter(Shape paintShape) { @@ -450,11 +451,11 @@ public class DockingHelpBroker extends GHelpBroker { /* // Debug Shape box = scaler.createTransformedShape(b); - g2d.setColor(Color.GREEN); + g2d.setColor(Palette.GREEN); g2d.fill(box); - + box = transform.createTransformedShape(box); - g2d.setColor(Color.YELLOW); + g2d.setColor(Palette.YELLOW); g2d.fill(box); */ diff --git a/Ghidra/Framework/Docking/src/main/java/docking/help/HelpManager.java b/Ghidra/Framework/Docking/src/main/java/docking/help/HelpManager.java index dc3678c550..350cefd820 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/help/HelpManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/help/HelpManager.java @@ -28,7 +28,6 @@ import java.util.Map.Entry; import javax.help.*; import javax.help.Map.ID; import javax.swing.JButton; -import javax.swing.UIManager; import docking.ComponentProvider; import docking.action.DockingActionIf; @@ -52,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"; @@ -85,11 +90,10 @@ 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); - setColorResources(); - isValidHelp = isValidHelp(); } @@ -124,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); @@ -195,6 +208,18 @@ public class HelpManager implements HelpService { return mainHS; } + @Override + public void reload() { + + if (!(mainHB instanceof GHelpBroker)) { + // not our broker installed; can't force a reload + return; + } + + GHelpBroker gHelpBroker = (GHelpBroker) mainHB; + gHelpBroker.reload(); + } + @Override public void showHelp(URL url) { if (!isValidHelp) { @@ -686,21 +711,13 @@ 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; } return null; } - /** - * Set the color resources on the JEditorPane for selection so that - * you can see the highlights when you do a search in the JavaHelp. - */ - private void setColorResources() { - UIManager.put("EditorPane.selectionBackground", new Color(204, 204, 255)); - UIManager.put("EditorPane.selectionForeground", UIManager.get("EditorPane.foreground")); - } - private void displayHelpInfo(Object helpObj, HelpLocation loc, Window parent) { String msg = getHelpInfo(helpObj, loc); Msg.showInfo(this, parent, "Help Info", msg); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/help/ToggleNavigationAid.java b/Ghidra/Framework/Docking/src/main/java/docking/help/ToggleNavigationAid.java index 5af1ff1b19..8bd568c358 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/help/ToggleNavigationAid.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/help/ToggleNavigationAid.java @@ -21,6 +21,7 @@ import java.awt.event.ActionEvent; import javax.swing.*; +import generic.theme.GIcon; import ghidra.framework.preferences.Preferences; import resources.MultiIcon; import resources.ResourceManager; @@ -29,9 +30,9 @@ import resources.icons.TranslateIcon; public class ToggleNavigationAid extends AbstractAction { - private static final Icon ENABLED_ICON = - ResourceManager.loadImage("images/software-update-available.png"); - private static final Icon CANCEL_ICON = ResourceManager.loadImage("images/dialog-cancel.png"); + private static final Icon ENABLED_ICON = new GIcon("icon.help.navigation.aid.enabled"); + private static final Icon DISABLED_OVERLAY_ICON = + new GIcon("icon.help.navigation.aid.disabled.overlay"); private static Icon DISABLED_ICON; private boolean showingNavigationAid = true; @@ -44,7 +45,7 @@ public class ToggleNavigationAid extends AbstractAction { "when navigating within the help system"); TranslateIcon translatedIcon = - new CenterTranslateIcon(CANCEL_ICON, ENABLED_ICON.getIconWidth()); + new CenterTranslateIcon(DISABLED_OVERLAY_ICON, ENABLED_ICON.getIconWidth()); ImageIcon disabledBaseIcon = ResourceManager.getDisabledIcon(ENABLED_ICON, 50); DISABLED_ICON = new MultiIcon(disabledBaseIcon, translatedIcon); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/menu/DockingToolBarUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/menu/DockingToolBarUtils.java index 9db8af21b1..f5601a1ae2 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/menu/DockingToolBarUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/menu/DockingToolBarUtils.java @@ -24,7 +24,7 @@ import javax.swing.KeyStroke; import org.apache.commons.lang3.StringUtils; import docking.action.DockingActionIf; -import ghidra.docking.util.DockingWindowsLookAndFeelUtils; +import ghidra.docking.util.LookAndFeelUtils; import ghidra.util.StringUtilities; class DockingToolBarUtils { @@ -96,7 +96,7 @@ class DockingToolBarUtils { builder.append(InputEvent.getModifiersExText(modifiers)); // The Aqua LaF does not use the '+' symbol between modifiers - if (!DockingWindowsLookAndFeelUtils.isUsingAquaUI(button.getUI())) { + if (!LookAndFeelUtils.isUsingAquaUI(button.getUI())) { builder.append('+'); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/menu/MultipleActionDockingToolbarButton.java b/Ghidra/Framework/Docking/src/main/java/docking/menu/MultipleActionDockingToolbarButton.java index 8a68fcbd11..6492259535 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/menu/MultipleActionDockingToolbarButton.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/menu/MultipleActionDockingToolbarButton.java @@ -30,6 +30,7 @@ import docking.*; import docking.action.*; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GThemeDefaults.Colors; import ghidra.util.Swing; import resources.ResourceManager; @@ -52,7 +53,7 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton { public MultipleActionDockingToolbarButton(MultiActionDockingActionIf action) { multipleAction = action; installMouseListeners(); - setIcon(ResourceManager.loadImage("images/core.png")); + setIcon(ResourceManager.getDefaultIcon()); } @Override @@ -96,6 +97,16 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton { popupContext = createPopupContext(); } + @Override + public void updateUI() { + + removeMouseListener(popupListener); + + super.updateUI(); + + installMouseListeners(); + } + private void installMouseListeners() { MouseListener[] mouseListeners = getMouseListeners(); for (MouseListener mouseListener : mouseListeners) { @@ -251,7 +262,7 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton { return; // shouldn't happen } - g.setColor(Color.BLACK); + g.setColor(Colors.FOREGROUND); int iconWidth = baseIcon.getIconWidth(); int iconHeight = baseIcon.getIconHeight(); int insetsPadding = insets.left + insets.right; // the insets of the left icon and the arrow (between the two) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ButtonPanelFactory.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ButtonPanelFactory.java index 09c79c7a62..68147cd3fe 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ButtonPanelFactory.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ButtonPanelFactory.java @@ -20,6 +20,7 @@ import java.awt.*; import javax.swing.*; import javax.swing.border.Border; +import generic.theme.GThemeDefaults.Colors; import resources.ResourceManager; /** @@ -99,7 +100,7 @@ public class ButtonPanelFactory { public final static Icon BROWSE_ICON = new Icon() { @Override public void paintIcon(Component c, Graphics g, int x, int y) { - g.setColor(Color.BLACK); + g.setColor(Colors.FOREGROUND); g.fillRect(x, y + 5, 2, 2); g.fillRect(x + 4, y + 5, 2, 2); g.fillRect(x + 8, y + 5, 2, 2); @@ -115,10 +116,6 @@ public class ButtonPanelFactory { return 10; } }; - /** - * Font for the browse button label. - */ - public final static Font BROWSE_FONT = new Font("Dialog", Font.BOLD, 12); /** * internal values used when creating the panels and buttons diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java index c3b5e8cfaf..7f8ae726cd 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java @@ -21,31 +21,27 @@ import java.awt.event.MouseEvent; import java.beans.PropertyEditorSupport; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; import docking.DialogComponentProvider; import docking.DockingWindowManager; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.util.ColorUtils; +import ghidra.util.WebColors; /** - * Color editor that uses the JColorChooser. + * Color editor that is a bit unusual in that its custom component is a button that when pushed, + * pops up a dialog for editing the color. Use {@link ColorPropertyEditor} for a more traditional + * property editor that returns a direct color editing component. */ public class ColorEditor extends PropertyEditorSupport { - private static final String LIGHT_COLOR = "SILVER"; - private static final String DARK_COLOR = "BLACK"; - private static GhidraColorChooser colorChooser; private JLabel previewLabel = new GDHtmlLabel(); private Color color; private Color lastUserSelectedColor; - /** - * The default constructor. - * - */ public ColorEditor() { previewLabel.setOpaque(true); previewLabel.setPreferredSize(new Dimension(100, 20)); @@ -72,42 +68,16 @@ public class ColorEditor extends PropertyEditorSupport { DockingWindowManager.showDialog(previewLabel, provider); } - /** - * A PropertyEditor may chose to make available a full custom Component - * that edits its property value. It is the responsibility of the - * PropertyEditor to hook itself up to its editor Component itself and - * to report property value changes by firing a PropertyChange event. - *

- * The higher-level code that calls getCustomEditor may either embed - * the Component in some larger property sheet, or it may put it in - * its own individual dialog, or ... - * - * @return A java.awt.Component that will allow a human to directly - * edit the current property value. May be null if this is - * not supported. - */ @Override public Component getCustomEditor() { return previewLabel; } - /** - * Determines whether the propertyEditor can provide a custom editor. - * - * @return True if the propertyEditor can provide a custom editor. - */ @Override public boolean supportsCustomEditor() { return true; } - /** - * Set (or change) the object that is to be edited. - * @param value The new target object to be edited. Note that this - * object should not be modified by the PropertyEditor, rather - * the PropertyEditor should create a new object to hold any - * modified value. - */ @Override public void setValue(Object value) { color = (Color) value; @@ -116,61 +86,37 @@ public class ColorEditor extends PropertyEditorSupport { } private void updateColor(Color newColor) { - String colorString = LIGHT_COLOR; // change the color to a darker value if the color being set is light - int colorValue = newColor.getRed() + newColor.getGreen() + newColor.getBlue(); - if (colorValue > 400) { // arbitrary threshold determined by trial-and-error - colorString = DARK_COLOR; - } - + String colorString = WebColors.toString(ColorUtils.contrastForegroundColor(newColor)); previewLabel.setText( "

click
"); previewLabel.setBackground(color); } - /** - * Get the value. - */ @Override public Object getValue() { return color; } - /** - * Return true which this editor can paint its property value. - */ @Override public boolean isPaintable() { return false; } - /** - * Paint a representation of the value into a given area of screen - * real estate. Note that the propertyEditor is responsible for doing - * its own clipping so that it fits into the given rectangle. - *

- * If the PropertyEditor doesn't honor paint requests (see isPaintable) - * this method should be a silent noop. - * - * @param gfx Graphics object to paint into. - * @param box Rectangle within graphics object into which we should paint. - */ @Override public void paintValue(Graphics gfx, Rectangle box) { if (color != null) { gfx.setColor(color); } else { - gfx.setColor(Color.black); + gfx.setColor(Palette.BLACK); } gfx.fillRect(box.x, box.y, box.width, box.height); } - ///////////////////////////////////////////////////////////////////////// - - class EditorProvider extends DialogComponentProvider { + private class EditorProvider extends DialogComponentProvider { EditorProvider(JPanel contentPanel) { super("Color Editor", true); @@ -186,7 +132,7 @@ public class ColorEditor extends PropertyEditorSupport { } } - class ColorEditorPanel extends JPanel { + private class ColorEditorPanel extends JPanel { ColorEditorPanel() { @@ -197,15 +143,12 @@ public class ColorEditor extends PropertyEditorSupport { } add(colorChooser, BorderLayout.CENTER); - colorChooser.getSelectionModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - lastUserSelectedColor = colorChooser.getColor(); - // This could be a ColorUIResource, but Options only support storing Color. - lastUserSelectedColor = - new Color(lastUserSelectedColor.getRed(), lastUserSelectedColor.getGreen(), - lastUserSelectedColor.getBlue(), lastUserSelectedColor.getAlpha()); - } + colorChooser.getSelectionModel().addChangeListener(e -> { + + // This could be a ColorUIResource, but Options only support storing Color. So, + // manually create a new Color object to avoid saving a ColorUIResource. + Color c = colorChooser.getColor(); + lastUserSelectedColor = ColorUtils.getColor(c.getRGB()); }); colorChooser.setColor(color); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorPropertyEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorPropertyEditor.java new file mode 100644 index 0000000000..7fb6a09f39 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorPropertyEditor.java @@ -0,0 +1,68 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.options.editor; + +import java.awt.Color; +import java.awt.Component; +import java.beans.PropertyEditorSupport; +import java.util.Objects; + +import ghidra.util.Swing; + +/** + * Property Editor for Colors. Uses a {@link GhidraColorChooser} as its custom component + */ +public class ColorPropertyEditor extends PropertyEditorSupport { + + private GhidraColorChooser colorChooser; + + private void colorChanged() { + // run later - allows debugging without hanging the UI in some environments + Swing.runLater(() -> setValue(colorChooser.getColor())); + } + + @Override + public Component getCustomEditor() { + if (colorChooser != null) { + return colorChooser; + } + + colorChooser = new GhidraColorChooser(); + colorChooser.getSelectionModel().addChangeListener(e -> colorChanged()); + return colorChooser; + } + + public void saveState() { + if (colorChooser != null) { + colorChooser.addColorToHistory(colorChooser.getColor()); + } + } + + @Override + public boolean supportsCustomEditor() { + return true; + } + + @Override + public void setValue(Object value) { + if (colorChooser != null) { + colorChooser.setColor((Color) value); + } + if (!Objects.equals(value, getValue())) { + super.setValue(value); + } + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/EditorInitializer.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/EditorInitializer.java index c0940375c5..2eb5a320eb 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/EditorInitializer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/EditorInitializer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +30,7 @@ public class EditorInitializer implements ModuleInitializer { public void run() { PropertyEditorManager.registerEditor(String.class, StringEditor.class); PropertyEditorManager.registerEditor(Color.class, ColorEditor.class); - PropertyEditorManager.registerEditor(Font.class, FontPropertyEditor.class); + PropertyEditorManager.registerEditor(Font.class, FontEditor.class); PropertyEditorManager.registerEditor(Enum.class, EnumEditor.class); PropertyEditorManager.registerEditor(Boolean.class, BooleanEditor.class); PropertyEditorManager.registerEditor(Date.class, DateEditor.class); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java index 7362459aaf..82d3a743f6 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FileChooserEditor.java @@ -16,7 +16,6 @@ package docking.options.editor; import java.awt.Component; -import java.awt.Font; import java.awt.event.MouseListener; import java.beans.PropertyEditorSupport; import java.io.File; @@ -107,9 +106,6 @@ public class FileChooserEditor extends PropertyEditorSupport { textField.setText(currentFileValue != null ? currentFileValue.getAbsolutePath() : ""); browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE); - Font f = browseButton.getFont(); - f = new Font(f.getName(), Font.BOLD, f.getSize()); - browseButton.setFont(f); add(textField); add(Box.createHorizontalStrut(5)); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java new file mode 100644 index 0000000000..b44509de46 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontEditor.java @@ -0,0 +1,111 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.options.editor; + +import java.awt.*; +import java.beans.PropertyEditorSupport; +import java.util.Objects; + +import javax.swing.*; + +import docking.DialogComponentProvider; +import docking.DockingWindowManager; + +/** + * Font property editor that is a bit unusual in that its custom component is a button that when + * pushed, pops up a dialog for editing the color. Use {@link FontPropertyEditor} for a more + * traditional property editor that returns a direct color editing component. + */ + +public class FontEditor extends PropertyEditorSupport { + private JButton previewButton; + private FontPropertyEditor fontPropertyEditor; + + public FontEditor() { + previewButton = new JButton(FontPropertyEditor.SAMPLE_STRING); + previewButton.addActionListener(e -> buttonPushed()); + fontPropertyEditor = new FontPropertyEditor(); + fontPropertyEditor.addPropertyChangeListener(ev -> fontChanged()); + } + + private void buttonPushed() { + showDialog(); + previewButton.setFont((Font) getValue()); + } + + /** + * Convenience method for directly showing a dialog for editing fonts + */ + public void showDialog() { + EditorDialogProvider provider = new EditorDialogProvider(); + DockingWindowManager.showDialog(previewButton, provider); + previewButton.repaint(); + } + + @Override + public void setValue(Object o) { + if (Objects.equals(o, getValue())) { + return; + } + Font font = (Font) o; + previewButton.setFont(font); + fontPropertyEditor.setValue(font); + super.setValue(font); + } + + @Override + public boolean supportsCustomEditor() { + return true; + } + + @Override + public Component getCustomEditor() { + return previewButton; + } + + private void fontChanged() { + Font font = (Font) fontPropertyEditor.getValue(); + setValue(font); + } + + class EditorDialogProvider extends DialogComponentProvider { + private Font originalFont = (Font) getValue(); + + EditorDialogProvider() { + super("Font Editor", true); + addWorkPanel(buildWorkPanel()); + addOKButton(); + addCancelButton(); + } + + private JComponent buildWorkPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.add(fontPropertyEditor.getCustomEditor()); + return panel; + } + + @Override + protected void okCallback() { + close(); + } + + @Override + protected void cancelCallback() { + setValue(originalFont); + close(); + } + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontPropertyEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontPropertyEditor.java index 017ad8fca5..3af96b8769 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontPropertyEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/FontPropertyEditor.java @@ -16,74 +16,31 @@ package docking.options.editor; import java.awt.*; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyEditorSupport; -import java.util.ArrayList; -import java.util.Collections; +import java.util.*; import java.util.List; -import java.util.stream.IntStream; +import java.util.stream.*; import javax.swing.*; -import docking.DialogComponentProvider; -import docking.DockingWindowManager; import docking.widgets.combobox.GComboBox; import docking.widgets.label.GDLabel; +import ghidra.util.Swing; /** - * This Bean FontEditor displays a String with the current selected font name, - * style and size attributes. + * Property Editor for editing {@link Font}s */ public class FontPropertyEditor extends PropertyEditorSupport { - private Font font; -// private JLabel previewLabel = new GDLabel(); - private final static String SAMPLE_STRING = "ABCabc \u00a9\u00ab\u00a7\u0429\u05d1\u062c\u4eb9"; - private JButton previewButton = new JButton(SAMPLE_STRING); + public final static String SAMPLE_STRING = "ABCabc \u00a9\u00ab\u00a7\u0429\u05d1\u062c\u4eb9"; - /** - * The default constructor. - * - */ - public FontPropertyEditor() { - - previewButton.addActionListener(e -> { - // show the editor to get the user value - showDialog(); - - // now set the new value - previewButton.setFont(font); - }); - -// previewLabel.addMouseListener( new MouseAdapter() { -// @Override -// public void mouseClicked( MouseEvent evt ) { -// // show the editor to get the user value -// showDialog(); -// -// // now set the new value -// previewLabel.setFont( font ); -// } -// } ); - } - - public void showDialog() { - EditorProvider provider = new EditorProvider(new FontPanel()); - DockingWindowManager.showDialog(previewButton, provider); - previewButton.repaint(); - } + private FontChooserPanel fontChooserPanel; @Override - public void setValue(Object o) { - font = (Font) o; - previewButton.setFont(font); - - // set the font values on the widget - } - - @Override - public Object getValue() { - return font; + public Component getCustomEditor() { + fontChooserPanel = new FontChooserPanel(); + fontChooserPanel.updateControls((Font) getValue()); + return fontChooserPanel; } @Override @@ -92,205 +49,221 @@ public class FontPropertyEditor extends PropertyEditorSupport { } @Override - public Component getCustomEditor() { - return previewButton; + public void setValue(Object value) { + if (fontChooserPanel != null) { + fontChooserPanel.updateControls((Font) value); + } + if (!Objects.equals(value, getValue())) { + super.setValue(value); + } } -//================================================================================================== -// Inner Classes -//================================================================================================== + class FontChooserPanel extends JPanel { - private class FontPanel extends JPanel implements ActionListener { - JLabel fontLabel, sizeLabel, styleLabel; - JLabel fontStringLabel; - JComboBox fonts; - JComboBox sizes; - JComboBox styles; - int styleChoice; - int sizeChoice; + private GDLabel previewLabel; + private GComboBox fontCombo; + private GComboBox sizeCombo; + private GComboBox styleCombo; + private ActionListener actionListener = e -> fontChanged(); + private List systemFontNames; - FontPanel() { - init(); + public FontChooserPanel() { + build(); } - public void init() { - this.setLayout(new BorderLayout()); - - JPanel topPanel = new JPanel(); - JPanel fontPanel = new JPanel(); - JPanel sizePanel = new JPanel(); - JPanel stylePanel = new JPanel(); - JPanel sizeAndStylePanel = new JPanel(); - - topPanel.setLayout(new BorderLayout()); - fontPanel.setLayout(new GridLayout(2, 1)); - sizePanel.setLayout(new GridLayout(2, 1)); - stylePanel.setLayout(new GridLayout(2, 1)); - sizeAndStylePanel.setLayout(new BorderLayout()); - - topPanel.add(BorderLayout.WEST, fontPanel); - sizeAndStylePanel.add(BorderLayout.WEST, sizePanel); - sizeAndStylePanel.add(BorderLayout.CENTER, stylePanel); - topPanel.add(BorderLayout.CENTER, sizeAndStylePanel); - - fontStringLabel = new GDLabel(FontPropertyEditor.SAMPLE_STRING); - fontStringLabel.setPreferredSize(new Dimension(350, 50)); - fontStringLabel.setHorizontalAlignment(SwingConstants.CENTER); - fontStringLabel.setFont(font); - topPanel.add(BorderLayout.SOUTH, fontStringLabel); - - add(BorderLayout.NORTH, topPanel); - - fontLabel = new GDLabel("Fonts"); - Font newFont = getFont().deriveFont(1); - fontLabel.setFont(newFont); - fontLabel.setHorizontalAlignment(SwingConstants.CENTER); - fontPanel.add(fontLabel); - - sizeLabel = new GDLabel("Sizes"); - sizeLabel.setFont(newFont); - sizeLabel.setHorizontalAlignment(SwingConstants.CENTER); - sizePanel.add(sizeLabel); - - styleLabel = new GDLabel("Styles"); - styleLabel.setFont(newFont); - styleLabel.setHorizontalAlignment(SwingConstants.CENTER); - stylePanel.add(styleLabel); - - GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment(); - - String envfonts[] = gEnv.getAvailableFontFamilyNames(); - List list = new ArrayList<>(envfonts.length); - for (String envfont : envfonts) { - list.add(new FontWrapper(envfont)); + public void updateControls(Font font) { + if (font == null) { + return; } - Collections.sort(list); - fonts = new GComboBox<>(list.toArray(new FontWrapper[envfonts.length])); - fonts.setMaximumRowCount(9); + updatePreviewLabel(font); + + fontCombo.removeActionListener(actionListener); + sizeCombo.removeActionListener(actionListener); + styleCombo.removeActionListener(actionListener); + FontWrapper fontWrapper = new FontWrapper(font.getName()); - fontPanel.add(fonts); - fonts.setSelectedItem(fontWrapper); + updateComboBoxModeIfNeeded(fontWrapper); - sizes = new GComboBox<>(IntStream.rangeClosed(1, 72).boxed().toArray(Integer[]::new)); - sizes.setMaximumRowCount(9); - sizePanel.add(sizes); - sizeChoice = font.getSize(); - sizes.setSelectedItem(sizeChoice); - sizes.setMaximumRowCount(9); + int styleChoice = font.getStyle(); + int size = font.getSize(); + fontCombo.setSelectedItem(fontWrapper); + sizeCombo.setSelectedItem(size); + styleCombo.setSelectedIndex(styleChoice); + + fontCombo.addActionListener(actionListener); + sizeCombo.addActionListener(actionListener); + styleCombo.addActionListener(actionListener); - styles = new GComboBox<>(new String[] { "PLAIN", "BOLD", "ITALIC", "BOLD & ITALIC" }); - styles.setMaximumRowCount(9); - stylePanel.add(styles); - styleChoice = font.getStyle(); - styles.setSelectedIndex(styleChoice); - fonts.addActionListener(this); - styles.addActionListener(this); - sizes.addActionListener(this); } - @Override - public void actionPerformed(ActionEvent event) { - // get values of panels - // set the editors new font - Object list = event.getSource(); + private void updateComboBoxModeIfNeeded(FontWrapper fontWrapper) { + if (systemFontNames.contains(fontWrapper)) { + return; + } + systemFontNames.add(fontWrapper); + DefaultComboBoxModel model = + new DefaultComboBoxModel<>(systemFontNames.toArray(new FontWrapper[0])); + fontCombo.setModel(model); + } - String fontNameChoice = font.getName(); - if (list == fonts) { - FontWrapper fontWrapper = (FontWrapper) fonts.getSelectedItem(); - fontNameChoice = fontWrapper.getFontName(); - } - else if (list == styles) { - styleChoice = styles.getSelectedIndex(); - } - else { - sizeChoice = (Integer) sizes.getSelectedItem(); - } + private void build() { + setLayout(new BorderLayout()); + add(buildTopPanel(), BorderLayout.NORTH); + add(buildPreviewLabel(), BorderLayout.CENTER); + } - font = new Font(fontNameChoice, styleChoice, sizeChoice); - fontStringLabel.setFont(font); - FontMetrics fm = fontStringLabel.getFontMetrics(font); + private Component buildTopPanel() { + JPanel panel = new JPanel(new FlowLayout(SwingConstants.CENTER, 10, 0)); + panel.add(buildFontNamePanel()); + panel.add(buildSizePanel()); + panel.add(buildStylePanel()); + return panel; + } + + private Component buildPreviewLabel() { + previewLabel = new GDLabel(SAMPLE_STRING); + previewLabel.setPreferredSize(new Dimension(350, 50)); + previewLabel.setHorizontalAlignment(SwingConstants.CENTER); + previewLabel.setVerticalAlignment(SwingConstants.CENTER); + previewLabel.setMinimumSize(new Dimension(300, 50)); + return previewLabel; + } + + private Component buildStylePanel() { + JPanel panel = new JPanel(new GridLayout(2, 1)); + + GDLabel styleLabel = new GDLabel("Styles"); + styleLabel.setFont(getFont().deriveFont(1)); + styleLabel.setHorizontalAlignment(SwingConstants.CENTER); + panel.add(styleLabel); + + styleCombo = + new GComboBox<>(new String[] { "PLAIN", "BOLD", "ITALIC", "BOLD & ITALIC" }); + styleCombo.setMaximumRowCount(9); + styleCombo.addActionListener(actionListener); + panel.add(styleCombo); + + return panel; + } + + private Component buildSizePanel() { + JPanel panel = new JPanel(new GridLayout(2, 1)); + + GDLabel sizeLabel = new GDLabel("Sizes"); + sizeLabel.setFont(getFont().deriveFont(1)); + sizeLabel.setHorizontalAlignment(SwingConstants.CENTER); + panel.add(sizeLabel); + + sizeCombo = + new GComboBox<>(IntStream.rangeClosed(1, 72).boxed().toArray(Integer[]::new)); + sizeCombo.setMaximumRowCount(9); + sizeCombo.setMaximumRowCount(9); + sizeCombo.addActionListener(actionListener); + panel.add(sizeCombo); + + return panel; + } + + private Component buildFontNamePanel() { + JPanel panel = new JPanel(new GridLayout(2, 1)); + + GDLabel fontLabel = new GDLabel("Fonts"); + fontLabel.setFont(getFont().deriveFont(1)); + fontLabel.setHorizontalAlignment(SwingConstants.CENTER); + panel.add(fontLabel); + + systemFontNames = getSystemFontNames(); + fontCombo = new GComboBox<>(systemFontNames.toArray(new FontWrapper[0])); + fontCombo.setMaximumRowCount(9); + fontCombo.addActionListener(actionListener); + panel.add(fontCombo); + + return panel; + } + + private List getSystemFontNames() { + GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment(); + Stream stream = Arrays.stream(gEnv.getAvailableFontFamilyNames()); + List collect = + stream.map(s -> new FontWrapper(s)).collect(Collectors.toList()); + Collections.sort(collect); + return new ArrayList<>(collect); + } + + private void fontChanged() { + FontWrapper fontWrapper = (FontWrapper) fontCombo.getSelectedItem(); + String fontNameChoice = fontWrapper.getFontName(); + int styleChoice = styleCombo.getSelectedIndex(); + int sizeChoice = (Integer) sizeCombo.getSelectedItem(); + Font font = new Font(fontNameChoice, styleChoice, sizeChoice); + updatePreviewLabel(font); + // allows debugging without hanging amazon aws + Swing.runLater(() -> setValue(font)); + } + + private void updatePreviewLabel(Font font) { + previewLabel.setFont(font); + FontMetrics fm = previewLabel.getFontMetrics(font); int height = fm.getHeight(); - Dimension d = fontStringLabel.getSize(); + Dimension d = previewLabel.getSize(); if (d.height < height) { d = new Dimension(d.width, height); - fontStringLabel.setPreferredSize(d); + previewLabel.setPreferredSize(d); } - fontStringLabel.invalidate(); + previewLabel.invalidate(); - setValue(font); - FontPropertyEditor.this.firePropertyChange(); } + + // A wrapper class created so that the names of fonts are comparable ignoring case + private class FontWrapper implements Comparable { + private final String fontName; + + private FontWrapper(String fontName) { + this.fontName = fontName; + } + + private String getFontName() { + return fontName; + } + + @Override + public String toString() { + return fontName; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (!getClass().equals(obj.getClass())) { + return false; + } + + FontWrapper otherWrapper = (FontWrapper) obj; + return fontName.toLowerCase().equals(otherWrapper.fontName.toLowerCase()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = + prime * result + ((fontName == null) ? 0 : fontName.toLowerCase().hashCode()); + return result; + } + + @Override + public int compareTo(FontWrapper otherWrapper) { + return fontName.compareToIgnoreCase(otherWrapper.fontName); + } + } + } - class EditorProvider extends DialogComponentProvider { - private Font originalFont = font; - - EditorProvider(JPanel contentPanel) { - super("Font Editor", true); - - addWorkPanel(contentPanel); - addOKButton(); - addCancelButton(); - } - - @Override - protected void okCallback() { - close(); - } - - @Override - protected void cancelCallback() { - font = originalFont; - super.cancelCallback(); - } - } - - // A wrapper class created so that the names of fonts are comparable ignoring case - private class FontWrapper implements Comparable { - private final String fontName; - - private FontWrapper(String fontName) { - this.fontName = fontName; - } - - private String getFontName() { - return fontName; - } - - @Override - public String toString() { - return fontName; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if (obj == null) { - return false; - } - - if (!getClass().equals(obj.getClass())) { - return false; - } - - FontWrapper otherWrapper = (FontWrapper) obj; - return fontName.toLowerCase().equals(otherWrapper.fontName.toLowerCase()); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((fontName == null) ? 0 : fontName.toLowerCase().hashCode()); - return result; - } - - @Override - public int compareTo(FontWrapper otherWrapper) { - return fontName.compareToIgnoreCase(otherWrapper.fontName); - } - } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/GhidraColorChooser.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/GhidraColorChooser.java index b892ff2919..b4a9030eee 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/GhidraColorChooser.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/GhidraColorChooser.java @@ -44,10 +44,16 @@ public class GhidraColorChooser extends JColorChooser { this.title = title; } + public void addColorToHistory(Color c) { + recentColorCache.addColor(c); + maybeInstallSettableColorSwatchChooserPanel(); + } + public void setColorHistory(List colors) { for (Color color : colors) { recentColorCache.addColor(color); } + maybeInstallSettableColorSwatchChooserPanel(); } public List getColorHistory() { @@ -66,8 +72,6 @@ public class GhidraColorChooser extends JColorChooser { @SuppressWarnings("deprecation") public Color showDialog(Component centerOverComponent) { - maybeInstallSettableColorSwatchChooserPanel(); - OKListener okListener = new OKListener(); JDialog dialog = createDialog(centerOverComponent, title, true, this, okListener, null); doSetActiveTab(dialog); @@ -123,7 +127,7 @@ public class GhidraColorChooser extends JColorChooser { } private void maybeInstallSettableColorSwatchChooserPanel() { - if (recentColorCache.size() == 0) { + if (recentColorCache.isEmpty()) { return; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java new file mode 100644 index 0000000000..68d863f44f --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/IconPropertyEditor.java @@ -0,0 +1,295 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.options.editor; + +import java.awt.*; +import java.beans.PropertyEditorSupport; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.List; + +import javax.swing.*; + +import org.apache.commons.io.FileUtils; + +import docking.theme.gui.ProtectedIcon; +import docking.widgets.*; +import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; +import docking.widgets.label.GDLabel; +import docking.widgets.list.GListCellRenderer; +import ghidra.framework.Application; +import ghidra.framework.preferences.Preferences; +import ghidra.util.Msg; +import ghidra.util.filechooser.ExtensionFileFilter; +import resources.ResourceManager; +import resources.icons.ScaledImageIcon; +import resources.icons.UrlImageIcon; + +public class IconPropertyEditor extends PropertyEditorSupport { + private IconChooserPanel iconChooserPanel; + + @Override + public Component getCustomEditor() { + iconChooserPanel = new IconChooserPanel(); + return iconChooserPanel; + } + + @Override + public boolean supportsCustomEditor() { + return true; + } + + @Override + public void setValue(Object value) { + if (iconChooserPanel != null) { + iconChooserPanel.setSelectedIcon((Icon) value); + } + doSetValue(value); + } + + private void doSetValue(Object value) { + if (!Objects.equals(value, getValue())) { + super.setValue(value); + } + } + + private String iconToString(Icon icon) { + if (icon instanceof UrlImageIcon urlIcon) { + return urlIcon.getOriginalPath(); + } + return ""; + } + + class IconChooserPanel extends JPanel { + + private static final String IMAGE_DIR = "images/"; + private static final String LAST_ICON_DIR_PREFERENCE_KEY = "IconEditor.lastDir"; + private GDLabel previewLabel; + private DropDownSelectionTextField dropDown; + private IconDropDownDataModel dataModel; + DropDownSelectionChoiceListener choiceListener = t -> iconChanged(t); + + public IconChooserPanel() { + build(); + } + + public void setSelectedIcon(Icon icon) { + if (icon == null) { + return; + } + if (!(icon instanceof UrlImageIcon)) { + icon = new ProtectedIcon(icon); + } + updateDropDownDataModel(icon); + updatePreviewLabel(icon); + + } + + private void updateDropDownDataModel(Icon icon) { + Set icons = ResourceManager.getLoadedUrlIcons(); + icons.add(icon); + dataModel.setData(new ArrayList<>(icons)); + dropDown.setSelectedValue(icon); + } + + private void build() { + setLayout(new BorderLayout()); + add(buildTopPanel(), BorderLayout.NORTH); + add(buildPreviewLabel(), BorderLayout.CENTER); + } + + private Component buildTopPanel() { + JPanel panel = new JPanel(new BorderLayout()); + dataModel = new IconDropDownDataModel(); + dropDown = new DropDownSelectionTextField<>(dataModel) { + protected List getMatchingData(String searchText) { + if (searchText.isBlank()) { + return ((IconDropDownDataModel) dataModel).getData(); + } + return super.getMatchingData(searchText); + } + }; + dropDown.addDropDownSelectionChoiceListener(choiceListener); + panel.add(dropDown, BorderLayout.CENTER); + JButton browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE); + panel.add(browseButton, BorderLayout.EAST); + browseButton.addActionListener(e -> browse()); + + return panel; + } + + private void iconChanged(Icon icon) { + boolean isDropDownWindowShowing = dropDown.isMatchingListShowing(); + if (!isDropDownWindowShowing) { + updatePreviewLabel(icon); + doSetValue(icon); + } + } + + private void browse() { + GhidraFileChooser chooser = new GhidraFileChooser(iconChooserPanel); + chooser.setTitle("Import Icon"); + chooser.setApproveButtonToolTipText("Import Icon"); + chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); + chooser.setSelectedFileFilter( + ExtensionFileFilter.forExtensions("Icon Files", ".png", "gif")); + String lastDir = Preferences.getProperty(LAST_ICON_DIR_PREFERENCE_KEY); + if (lastDir != null) { + chooser.setCurrentDirectory(new File(lastDir)); + } + File file = chooser.getSelectedFile(); + if (file != null) { + File dir = chooser.getCurrentDirectory(); + Preferences.setProperty(LAST_ICON_DIR_PREFERENCE_KEY, dir.getAbsolutePath()); + importIconFile(file); + } + } + + private void importIconFile(File file) { + + if (!isValidIcon(file)) { + Msg.error(this, "File is not a valid icon: " + file.getAbsolutePath()); + return; + } + File dir = Application.getUserSettingsDirectory(); + String relativePath = IMAGE_DIR + file.getName(); + + File destinationFile = new File(dir, relativePath); + if (destinationFile.exists()) { + int result = OptionDialog.showYesNoDialog(dropDown, "Overwrite?", + "An icon with that name already exists.\n Do you want to overwrite it?"); + if (result == OptionDialog.NO_OPTION) { + return; + } + } + try { + FileUtils.copyFile(file, destinationFile); + String path = ResourceManager.EXTERNAL_ICON_PREFIX + relativePath; + ImageIcon icon = ResourceManager.loadImage(path); + setValue(icon); + } + catch (IOException e) { + Msg.showError(this, dropDown, "Error importing file", e); + } + } + + private boolean isValidIcon(File file) { + if (!file.exists()) { + return false; + } + try { + UrlImageIcon icon = new UrlImageIcon(file.getAbsolutePath(), file.toURI().toURL()); + icon.getIconWidth(); + return true; + } + catch (Exception e) { + Msg.showError(this, dropDown, "Invalid Icon File", + "The file is not a valid icon: " + file.getAbsolutePath()); + return false; + } + + } + + private Component buildPreviewLabel() { + JPanel panel = new JPanel(new BorderLayout()); + + previewLabel = new GDLabel(""); + previewLabel.setIcon(ResourceManager.getDefaultIcon()); + previewLabel.setHorizontalAlignment(SwingConstants.CENTER); + previewLabel.setVerticalAlignment(SwingConstants.CENTER); + panel.add(previewLabel, BorderLayout.CENTER); + panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + return panel; + } + + private void updatePreviewLabel(Icon icon) { + previewLabel.setIcon(icon); + int height = icon.getIconHeight(); + int width = icon.getIconWidth(); + Dimension d = previewLabel.getSize(); + height = Math.max(d.height, height); + width = Math.max(d.width, width); + previewLabel.setPreferredSize(new Dimension(width, height)); + previewLabel.invalidate(); + iconChooserPanel.validate(); + } + + } + + class IconDropDownDataModel extends DefaultDropDownSelectionDataModel { + IconListCellRender renderer = new IconListCellRender(); + + public IconDropDownDataModel() { + super(Collections.emptyList(), IconPropertyEditor.this::iconToString); + } + + List getData() { + return data; + } + + void setData(List icons) { + Collections.sort(icons, comparator); + data = icons; + } + + @Override + public List getMatchingData(String searchText) { + if (searchText.isBlank()) { + return data; + } + searchText = searchText.toLowerCase(); + List results = new ArrayList<>(); + for (Icon icon : data) { + String name = iconToString(icon); + if (name.toLowerCase().contains(searchText)) { + results.add(icon); + } + } + + return results; + + } + + @Override + public ListCellRenderer getListRenderer() { + return renderer; + } + + } + + class IconListCellRender extends GListCellRenderer { + @Override + protected String getItemText(Icon icon) { + return iconToString(icon); + } + + @Override + public Component getListCellRendererComponent(JList list, Icon icon, + int index, boolean isSelected, boolean hasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, icon, index, + isSelected, hasFocus); + + if (icon.getIconWidth() != 16 || icon.getIconHeight() != 16) { + icon = new ScaledImageIcon(icon, 16, 16); + } + label.setIcon(icon); + return label; + } + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java index 0a89d0330a..824ba792ec 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsDialog.java @@ -15,7 +15,6 @@ */ package docking.options.editor; -import java.awt.Color; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -55,7 +54,6 @@ public class OptionsDialog extends DialogComponentProvider { new OptionsPropertyChangeListener()); setTitle(title); - setBackground(Color.lightGray); addWorkPanel(panel); addOKButton(); @@ -67,6 +65,7 @@ public class OptionsDialog extends DialogComponentProvider { setFocusComponent(panel.getFocusComponent()); } + @Override public void dispose() { panel.dispose(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsPanel.java index d8640fab9b..a7a14d5206 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsPanel.java @@ -40,7 +40,7 @@ import ghidra.util.layout.MiddleLayout; import ghidra.util.task.SwingUpdateManager; import help.Help; import help.HelpService; -import resources.ResourceManager; +import resources.Icons; public class OptionsPanel extends JPanel { private PropertyChangeListener changeListener; @@ -251,7 +251,7 @@ public class OptionsPanel extends JPanel { BoxLayout bl = new BoxLayout(labelPanel, BoxLayout.X_AXIS); labelPanel.setLayout(bl); labelPanel.add(Box.createHorizontalStrut(5)); - labelPanel.add(new GIconLabel(ResourceManager.loadImage("images/information.png"))); + labelPanel.add(new GIconLabel(Icons.INFO_ICON)); labelPanel.add(Box.createHorizontalStrut(5)); labelPanel.add(label); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsTreeNode.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsTreeNode.java index 6a3b5c86ff..50355b8cc6 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsTreeNode.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/OptionsTreeNode.java @@ -21,16 +21,14 @@ import javax.swing.Icon; import docking.widgets.tree.GTreeLazyNode; import docking.widgets.tree.GTreeNode; +import generic.theme.GIcon; import ghidra.framework.options.Options; -import resources.ResourceManager; +import resources.Icons; class OptionsTreeNode extends GTreeLazyNode { - private final static Icon OPEN_FOLDER_ICON = - ResourceManager.loadImage("images/openSmallFolder.png"); - private final static Icon CLOSED_FOLDER_ICON = - ResourceManager.loadImage("images/closedSmallFolder.png"); - private final static Icon PROPERTIES_ICON = - ResourceManager.loadImage("images/document-properties.png"); + private final static Icon OPEN_FOLDER_ICON = Icons.OPEN_FOLDER_ICON; + private final static Icon CLOSED_FOLDER_ICON = Icons.CLOSED_FOLDER_ICON; + private final static Icon PROPERTIES_ICON = new GIcon("icon.properties"); private final Options options; private final String name; @@ -46,7 +44,7 @@ class OptionsTreeNode extends GTreeLazyNode { @Override protected List generateChildren() { - List childList = new ArrayList(); + List childList = new ArrayList<>(); if (options.getOptionsEditor() == null) { // if hasOptionsEditor, don't show child options List childOptionsList = options.getChildOptions(); for (Options childOptions : childOptionsList) { @@ -108,7 +106,7 @@ class OptionsTreeNode extends GTreeLazyNode { public List getOptionNames() { if (options == null) { - return new ArrayList(); + return new ArrayList<>(); } return options.getLeafOptionNames(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/SettableColorSwatchChooserPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/SettableColorSwatchChooserPanel.java index 6585e6352e..7703baf713 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/SettableColorSwatchChooserPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/SettableColorSwatchChooserPanel.java @@ -21,11 +21,14 @@ import java.io.Serializable; import java.util.List; import javax.swing.*; -import javax.swing.border.*; +import javax.swing.border.LineBorder; import javax.swing.colorchooser.AbstractColorChooserPanel; import docking.widgets.label.GHtmlLabel; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Java; +import ghidra.util.ColorUtils; import ghidra.util.layout.VerticalLayout; public class SettableColorSwatchChooserPanel extends AbstractColorChooserPanel { @@ -66,6 +69,7 @@ public class SettableColorSwatchChooserPanel extends AbstractColorChooserPanel { return Integer.parseInt((String) value); } catch (NumberFormatException nfe) { + // return default value } } return defaultValue; @@ -118,8 +122,7 @@ public class SettableColorSwatchChooserPanel extends AbstractColorChooserPanel { recentSwatchListener = new RecentSwatchListener(); recentSwatchPanel.addMouseListener(recentSwatchListener); - Border border = - new CompoundBorder(new LineBorder(Color.black), new LineBorder(Color.white)); + LineBorder border = new LineBorder(Java.BORDER); swatchPanel.setBorder(border); gbc.weightx = 1.0; gbc.gridwidth = 2; @@ -182,6 +185,7 @@ public class SettableColorSwatchChooserPanel extends AbstractColorChooserPanel { @Override public void updateChooser() { + // stub } class HistorySwatchListener extends MouseAdapter { @@ -222,7 +226,7 @@ class SwatchPanel extends JPanel { initColors(); setToolTipText(""); // register for events setOpaque(true); - setBackground(Color.white); + setBackground(Colors.BACKGROUND); setRequestFocusEnabled(false); } @@ -232,6 +236,7 @@ class SwatchPanel extends JPanel { } protected void initValues() { + // stub } @Override @@ -251,7 +256,7 @@ class SwatchPanel extends JPanel { } int y = row * (swatchSize.height + gap.height); g.fillRect(x, y, swatchSize.width, swatchSize.height); - g.setColor(Color.black); + g.setColor(Java.BORDER); g.drawLine(x + swatchSize.width - 1, y, x + swatchSize.width - 1, y + swatchSize.height - 1); g.drawLine(x, y + swatchSize.height - 1, x + swatchSize.width - 1, @@ -268,7 +273,7 @@ class SwatchPanel extends JPanel { } protected void initColors() { - + // stub } @Override @@ -383,8 +388,8 @@ class MainSwatchPanel extends SwatchPanel { colors = new Color[numColors]; for (int i = 0; i < numColors; i++) { - colors[i] = - new Color(rawValues[(i * 3)], rawValues[(i * 3) + 1], rawValues[(i * 3) + 2]); + colors[i] = ColorUtils.getColor(rawValues[(i * 3)], rawValues[(i * 3) + 1], + rawValues[(i * 3) + 2]); } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/resources/icons/NumberIcon.java b/Ghidra/Framework/Docking/src/main/java/docking/resources/icons/NumberIcon.java index d219d6e16a..403882d31e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/resources/icons/NumberIcon.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/resources/icons/NumberIcon.java @@ -22,12 +22,15 @@ import javax.swing.Icon; import javax.swing.JComponent; import docking.util.GraphicsUtils; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; /** * An icon that paints the given number */ public class NumberIcon implements Icon { + private static final Color BORDER_COLOR = Palette.getColor("lightskyblue"); private String number; private float bestFontSize = -1; @@ -42,9 +45,9 @@ public class NumberIcon implements Icon { @Override public void paintIcon(Component c, Graphics g, int x, int y) { - g.setColor(Color.WHITE); + g.setColor(Colors.BACKGROUND); g.fillRect(x, y, getIconWidth(), getIconHeight()); - g.setColor(new Color(0xb5d5ff)); + g.setColor(BORDER_COLOR); g.drawRect(x, y, getIconWidth(), getIconHeight()); float fontSize = getMaxFontSize(g, getIconWidth() - 1, getIconHeight()); @@ -66,7 +69,7 @@ public class NumberIcon implements Icon { int halfTextWidth = textWidth >> 1; int baselineX = x + (halfWidth - halfTextWidth); - g.setColor(Color.BLACK); + g.setColor(Colors.FOREGROUND); JComponent jc = null; if (c instanceof JComponent) { jc = (JComponent) c; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ColorValueEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ColorValueEditor.java new file mode 100644 index 0000000000..69ef32f4c5 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ColorValueEditor.java @@ -0,0 +1,51 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.Color; +import java.beans.PropertyChangeListener; + +import docking.options.editor.ColorPropertyEditor; +import generic.theme.*; + +/** + * Editor for Theme colors + */ +public class ColorValueEditor extends ThemeValueEditor { + + /** + * Constructor + * @param listener the {@link PropertyChangeListener} to be notified when changes are made + */ + public ColorValueEditor(PropertyChangeListener listener) { + super("Color", listener, new ColorPropertyEditor()); + } + + @Override + protected Color getRawValue(String id) { + return Gui.getColor(id); + } + + @Override + protected ThemeValue createNewThemeValue(String id, Color color) { + return new ColorValue(id, color); + } + + @Override + protected void storeState() { + ((ColorPropertyEditor) editor).saveState(); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java new file mode 100644 index 0000000000..482be31be4 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ExportThemeDialog.java @@ -0,0 +1,168 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.io.File; +import java.io.IOException; + +import javax.swing.*; + +import docking.DialogComponentProvider; +import docking.options.editor.ButtonPanelFactory; +import docking.widgets.checkbox.GCheckBox; +import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; +import docking.widgets.label.GLabel; +import generic.theme.*; +import ghidra.util.MessageType; +import ghidra.util.Msg; +import ghidra.util.filechooser.GhidraFileFilter; +import ghidra.util.layout.PairLayout; + +/** + * Dialog for exporting themes to external files or zip files. + */ +public class ExportThemeDialog extends DialogComponentProvider { + + private JTextField nameField; + private JTextField fileTextField; + private GCheckBox includeDefaultsCheckbox; + private boolean exportAsZip; + private ThemeManager themeManager; + + public ExportThemeDialog(ThemeManager themeManager, boolean exportAsZip) { + super("Export Theme"); + this.themeManager = themeManager; + this.exportAsZip = exportAsZip; + addWorkPanel(buildMainPanel()); + addOKButton(); + addCancelButton(); + setRememberSize(false); + } + + @Override + protected void okCallback() { + if (exportTheme()) { + close(); + } + } + + private boolean exportTheme() { + String themeName = nameField.getText(); + GTheme activeTheme = themeManager.getActiveTheme(); + LafType laf = activeTheme.getLookAndFeelType(); + boolean useDarkDefaults = activeTheme.useDarkDefaults(); + File file = new File(fileTextField.getText()); + + if (themeName.isBlank()) { + setStatusText("Missing Theme Name", MessageType.ERROR, true); + return false; + } + + try { + GTheme exportTheme = new GTheme(file, themeName, laf, useDarkDefaults); + loadValues(exportTheme); + ThemeWriter themeWriter = new ThemeWriter(exportTheme); + themeWriter.writeTheme(file, exportAsZip); + return true; + } + catch (IOException e) { + Msg.error("Error Exporting Theme", "I/O Error encountered trying to export theme!", e); + } + return false; + } + + private void loadValues(GTheme exportTheme) { + if (includeDefaultsCheckbox.isSelected()) { + exportTheme.load(themeManager.getCurrentValues()); + } + else { + exportTheme.load(themeManager.getNonDefaultValues()); + } + } + + @Override + protected void cancelCallback() { + close(); + } + + private JComponent buildMainPanel() { + JPanel panel = new JPanel(new PairLayout(10, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + panel.add(new GLabel("Theme Name:", SwingConstants.RIGHT)); + panel.add(buildNameField()); + panel.add(new GLabel("Output File:", SwingConstants.RIGHT)); + panel.add(buildFilePanel()); + panel.add(new GLabel("Include Defaults:", SwingConstants.RIGHT)); + panel.add(buildIncludeDefaultsCheckbox()); + return panel; + } + + private Component buildNameField() { + nameField = new JTextField(25); + nameField.setText(themeManager.getActiveTheme().getName()); + return nameField; + } + + private Component buildIncludeDefaultsCheckbox() { + includeDefaultsCheckbox = new GCheckBox(); + includeDefaultsCheckbox.setSelected(true); + return includeDefaultsCheckbox; + } + + private Component buildFilePanel() { + File homeDir = new File(System.getProperty("user.home")); // prefer the home directory + + String name = themeManager.getActiveTheme().getName(); + String filename = name.replaceAll(" ", "_") + "."; + filename += exportAsZip ? GTheme.ZIP_FILE_EXTENSION : GTheme.FILE_EXTENSION; + File file = new File(homeDir, filename); + + fileTextField = new JTextField(); + fileTextField.setText(file.getAbsolutePath()); + fileTextField.setEditable(false); + fileTextField.setFocusable(false); + JButton folderButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE); + folderButton.addActionListener(e -> chooseFile()); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(fileTextField, BorderLayout.CENTER); + panel.add(folderButton, BorderLayout.EAST); + return panel; + } + + private void chooseFile() { + GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); + chooser.setTitle("Choose Theme File"); + chooser.setApproveButtonToolTipText("Select File"); + chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); + chooser.setSelectedFileFilter(GhidraFileFilter.ALL); + chooser.setSelectedFile(new File(fileTextField.getText())); + File file = chooser.getSelectedFile(); + if (file != null) { + fileTextField.setText(file.getAbsolutePath()); + } + } + + // used for testing + public void setOutputFile(File outputFile) { + fileTextField.setText(outputFile.getAbsolutePath()); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/FontValueEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/FontValueEditor.java new file mode 100644 index 0000000000..4d0291e38e --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/FontValueEditor.java @@ -0,0 +1,47 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.Font; +import java.beans.PropertyChangeListener; + +import docking.options.editor.FontPropertyEditor; +import generic.theme.*; + +/** + * Editor for Theme fonts + */ +public class FontValueEditor extends ThemeValueEditor { + + /** + * Constructor + * @param listener the {@link PropertyChangeListener} to be notified when changes are made + */ + public FontValueEditor(PropertyChangeListener listener) { + super("Font", listener, new FontPropertyEditor()); + } + + @Override + protected Font getRawValue(String id) { + return Gui.getFont(id); + } + + @Override + protected ThemeValue createNewThemeValue(String id, Font font) { + return new FontValue(id, font); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/IconValueEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/IconValueEditor.java new file mode 100644 index 0000000000..541641eb88 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/IconValueEditor.java @@ -0,0 +1,48 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.beans.PropertyChangeListener; + +import javax.swing.Icon; + +import docking.options.editor.IconPropertyEditor; +import generic.theme.*; + +/** + * Editor for Theme fonts + */ +public class IconValueEditor extends ThemeValueEditor { + + /** + * Constructor + * @param listener the {@link PropertyChangeListener} to be notified when changes are made + */ + public IconValueEditor(PropertyChangeListener listener) { + super("Icon", listener, new IconPropertyEditor()); + } + + @Override + protected Icon getRawValue(String id) { + return Gui.getIcon(id); + } + + @Override + protected ThemeValue createNewThemeValue(String id, Icon icon) { + return new IconValue(id, icon); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ProtectedIcon.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ProtectedIcon.java new file mode 100644 index 0000000000..6c9ab3d276 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ProtectedIcon.java @@ -0,0 +1,60 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.Icon; +import javax.swing.LookAndFeel; + +import resources.ResourceManager; + +/** + * A wrapper for an icon that suppresses errors. Some Icons that are mined from a + * {@link LookAndFeel} have specialized uses and will throw exceptions if used outside + * their intended component. This class is used when trying to show them in the the theme + * editor table. + */ +public class ProtectedIcon implements Icon { + Icon bomb = ResourceManager.getDefaultIcon(); + Icon delegate; + boolean isError = false; + + public ProtectedIcon(Icon delegate) { + this.delegate = delegate; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + try { + delegate.paintIcon(c, g, x, y); + } + catch (Exception e) { + bomb.paintIcon(c, g, x, y); + } + } + + @Override + public int getIconWidth() { + return Math.max(1, delegate.getIconWidth()); + } + + @Override + public int getIconHeight() { + return Math.max(1, delegate.getIconHeight()); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeColorTable.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeColorTable.java new file mode 100644 index 0000000000..12a328bdbc --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeColorTable.java @@ -0,0 +1,123 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.*; +import java.beans.PropertyChangeEvent; + +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import javax.swing.table.TableColumn; + +import docking.ActionContext; +import docking.action.ActionContextProvider; +import docking.widgets.table.GFilterTable; +import docking.widgets.table.GTable; +import generic.theme.ColorValue; +import generic.theme.ThemeManager; +import ghidra.util.Swing; + +/** + * Color Table for Theme Dialog + */ +public class ThemeColorTable extends JPanel implements ActionContextProvider { + + private ThemeColorTableModel colorTableModel; + private ColorValueEditor colorEditor = new ColorValueEditor(this::colorValueChanged); + private GTable table; + private GFilterTable filterTable; + private ThemeManager themeManager; + + public ThemeColorTable(ThemeManager themeManager) { + super(new BorderLayout()); + this.themeManager = themeManager; + colorTableModel = new ThemeColorTableModel(themeManager); + + filterTable = new GFilterTable<>(colorTableModel); + table = filterTable.getTable(); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + table.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + ColorValue colorValue = filterTable.getSelectedRowObject(); + if (colorValue != null) { + colorEditor.editValue(colorValue); + } + e.consume(); + } + } + }); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + ColorValue value = filterTable.getItemAt(e.getPoint()); + + int col = filterTable.getColumn(e.getPoint()); + TableColumn column = table.getColumnModel().getColumn(col); + Object identifier = column.getIdentifier(); + if ("Current Color".equals(identifier) || "Id".equals(identifier)) { + colorEditor.editValue(value); + } + } + } + }); + + add(filterTable, BorderLayout.CENTER); + + } + + void colorValueChanged(PropertyChangeEvent event) { + // run later - don't rock the boat in the middle of a listener callback + Swing.runLater(() -> { + ColorValue newValue = (ColorValue) event.getNewValue(); + themeManager.setColor(newValue); + }); + } + + /** + * Returns the current values displayed in the table + */ + public void reloadCurrent() { + colorTableModel.reloadCurrent(); + } + + /** + * Reloads all the values displayed in the table + */ + public void reloadAll() { + colorTableModel.reloadAll(); + } + + @Override + public ActionContext getActionContext(MouseEvent e) { + if (e != null && e.getSource() == table) { + ColorValue currentValue = filterTable.getSelectedRowObject(); + if (currentValue == null) { + return null; + } + String id = currentValue.getId(); + ColorValue themeValue = colorTableModel.getThemeValue(id); + return new ThemeTableContext(currentValue, themeValue); + } + return null; + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeColorTableModel.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeColorTableModel.java new file mode 100644 index 0000000000..cba8f3dc41 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeColorTableModel.java @@ -0,0 +1,263 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.*; +import java.util.Comparator; +import java.util.List; +import java.util.function.Supplier; + +import javax.swing.Icon; +import javax.swing.JLabel; + +import docking.widgets.table.*; +import generic.theme.*; +import ghidra.docking.settings.Settings; +import ghidra.framework.plugintool.ServiceProvider; +import ghidra.framework.plugintool.ServiceProviderStub; +import ghidra.util.ColorUtils; +import ghidra.util.WebColors; +import ghidra.util.table.column.AbstractGColumnRenderer; +import ghidra.util.table.column.GColumnRenderer; + +/** + * Table model for theme colors + */ +public class ThemeColorTableModel extends GDynamicColumnTableModel { + private List colors; + private GThemeValueMap currentValues; + private GThemeValueMap themeValues; + private GThemeValueMap defaultValues; + private GThemeValueMap lightDefaultValues; + private GThemeValueMap darkDefaultValues; + private ThemeManager themeManager; + + public ThemeColorTableModel(ThemeManager themeManager) { + super(new ServiceProviderStub()); + this.themeManager = themeManager; + load(); + } + + /** + * Reloads the just the current values shown in the table. Called whenever a color changes. + */ + public void reloadCurrent() { + currentValues = themeManager.getCurrentValues(); + colors = currentValues.getColors(); + fireTableDataChanged(); + } + + /** + * Reloads all the current values and all the default values in the table. Called when the + * theme changes or the application defaults have been forced to reload. + */ + public void reloadAll() { + load(); + fireTableDataChanged(); + } + + ColorValue getThemeValue(String id) { + return themeValues.getColor(id); + } + + private void load() { + currentValues = themeManager.getCurrentValues(); + colors = currentValues.getColors(); + themeValues = themeManager.getThemeValues(); + defaultValues = themeManager.getDefaults(); + lightDefaultValues = themeManager.getApplicationLightDefaults(); + darkDefaultValues = themeManager.getApplicationDarkDefaults(); + + } + + @Override + public String getName() { + return "Colors"; + } + + @Override + public List getModelData() { + return colors; + } + + @Override + protected TableColumnDescriptor createTableColumnDescriptor() { + TableColumnDescriptor descriptor = new TableColumnDescriptor<>(); + descriptor.addVisibleColumn(new IdColumn()); + descriptor.addVisibleColumn(new ValueColumn("Current Color", () -> currentValues)); + descriptor.addVisibleColumn(new ValueColumn("Theme Color", () -> themeValues)); + descriptor.addVisibleColumn(new ValueColumn("Default Color", () -> defaultValues)); + descriptor.addHiddenColumn(new ValueColumn("Light Defaults", () -> lightDefaultValues)); + descriptor.addHiddenColumn(new ValueColumn("Dark Defaults", () -> darkDefaultValues)); + return descriptor; + } + + @Override + public Object getDataSource() { + return null; + } + + class IdColumn extends AbstractDynamicTableColumn { + + @Override + public String getColumnName() { + return "Id"; + } + + @Override + public String getValue(ColorValue themeColor, Settings settings, Object data, + ServiceProvider provider) throws IllegalArgumentException { + return themeColor.getId(); + } + + @Override + public int getColumnPreferredWidth() { + return 300; + } + } + + class ValueColumn extends AbstractDynamicTableColumn { + private ThemeColorRenderer renderer; + private String name; + private Supplier valueSupplier; + + ValueColumn(String name, Supplier supplier) { + this.name = name; + this.valueSupplier = supplier; + renderer = new ThemeColorRenderer(); + } + + @Override + public String getColumnName() { + return name; + } + + @Override + public ResolvedColor getValue(ColorValue themeColor, Settings settings, Object data, + ServiceProvider provider) throws IllegalArgumentException { + GThemeValueMap valueMap = valueSupplier.get(); + String id = themeColor.getId(); + ColorValue colorValue = valueMap.getColor(id); + if (colorValue == null) { + return null; + } + Color color = colorValue.hasResolvableValue(valueMap) ? colorValue.get(valueMap) : null; + if (color == null) { + return null; + } + return new ResolvedColor(id, colorValue.getReferenceId(), color); + } + + @Override + public GColumnRenderer getColumnRenderer() { + return renderer; + } + + public Comparator getComparator() { + return (v1, v2) -> { + if (v1 == null && v2 == null) { + return 0; + } + if (v1 == null) { + return 1; + } + if (v2 == null) { + return -1; + } + return ColorUtils.COMPARATOR.compare(v1.color, v2.color); + }; + } + + @Override + public int getColumnPreferredWidth() { + return 300; + } + + } + + private class ThemeColorRenderer extends AbstractGColumnRenderer { + + public ThemeColorRenderer() { + setFont(Gui.getFont("font.monospaced")); + } + + @Override + public Component getTableCellRendererComponent(GTableCellRenderingData data) { + JLabel label = (JLabel) super.getTableCellRendererComponent(data); + ResolvedColor resolved = (ResolvedColor) data.getValue(); + + String text = getValueText(resolved); + Color color = resolved == null ? GThemeDefaults.Colors.BACKGROUND : resolved.color(); + label.setText(text); + label.setIcon(new SwatchIcon(color, label.getForeground())); + label.setOpaque(true); + return label; + } + + private String getValueText(ResolvedColor resolvedColor) { + if (resolvedColor == null) { + return ""; + } + Color color = resolvedColor.color(); + String name = WebColors.toWebColorName(color); + if (resolvedColor.refId() != null) { + return "[" + resolvedColor.refId() + "] "; + } + String text = WebColors.toString(color, false); + if (name != null) { + text += " (" + name + ")"; + } + return text; + } + + @Override + public String getFilterString(ResolvedColor colorValue, Settings settings) { + return getValueText(colorValue); + } + + } + + static class SwatchIcon implements Icon { + private Color color; + private Color border; + + SwatchIcon(Color c, Color border) { + this.color = c; + this.border = border; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + g.setColor(color); + g.fillRect(x, y, 25, 16); + g.setColor(border); + g.drawRect(x, y, 25, 16); + } + + @Override + public int getIconWidth() { + return 25; + } + + @Override + public int getIconHeight() { + return 16; + } + } + + record ResolvedColor(String id, String refId, Color color) {/**/} + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeDialog.java new file mode 100644 index 0000000000..8ff6662636 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeDialog.java @@ -0,0 +1,302 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.*; +import java.util.*; +import java.util.stream.Collectors; + +import javax.swing.*; + +import docking.*; +import docking.action.ActionContextProvider; +import docking.action.DockingAction; +import docking.action.builder.ActionBuilder; +import docking.widgets.OptionDialog; +import docking.widgets.combobox.GhidraComboBox; +import generic.theme.*; +import ghidra.util.*; + +/** + * Primary dialog for editing Themes. + */ +public class ThemeDialog extends DialogComponentProvider { + private static ThemeDialog INSTANCE; + + private JButton saveButton; + private JButton restoreButton; + private GhidraComboBox combo; + private ItemListener comboListener = this::themeComboChanged; + private ThemeListener listener = new DialogThemeListener(); + private JTabbedPane tabbedPane; + + private ThemeColorTable colorTable; + private ThemeFontTable fontTable; + private ThemeIconTable iconTable; + + private ThemeManager themeManager; + + public ThemeDialog(ThemeManager themeManager) { + super("Theme Dialog", false); + this.themeManager = themeManager; + addWorkPanel(createMainPanel()); + + addDismissButton(); + addButton(createSaveButton()); + addButton(createRestoreButton()); + + setPreferredSize(1100, 500); + setRememberSize(false); + updateButtons(); + createActions(); + Gui.addThemeListener(listener); + setHelpLocation(new HelpLocation("Theming", "Edit_Theme")); + } + + private void createActions() { + DockingAction reloadDefaultsAction = new ActionBuilder("Reload Ghidra Defaults", getTitle()) + .toolBarIcon(new GIcon("icon.refresh")) + .helpLocation(new HelpLocation("Theming", "Reload_Ghidra_Defaults")) + .onAction(e -> reloadDefaultsCallback()) + .build(); + addAction(reloadDefaultsAction); + + DockingAction resetValueAction = new ActionBuilder("Restore Value", getTitle()) + .popupMenuPath("Restore Value") + .withContext(ThemeTableContext.class) + .enabledWhen(c -> c.isChanged()) + .popupWhen(c -> true) + .helpLocation(new HelpLocation("Theming", "Restore_Value")) + .onAction(c -> c.getThemeValue().installValue(themeManager)) + .build(); + addAction(resetValueAction); + } + + @Override + protected void dismissCallback() { + if (handleChanges()) { + INSTANCE = null; + close(); + } + } + + private boolean handleChanges() { + if (themeManager.hasThemeChanges()) { + int result = OptionDialog.showYesNoCancelDialog(null, "Close Theme Dialog", + "You have changed the theme.\n Do you want save your changes?"); + if (result == OptionDialog.CANCEL_OPTION) { + return false; + } + if (result == OptionDialog.YES_OPTION) { + return ThemeUtils.saveThemeChanges(themeManager); + } + themeManager.restoreThemeValues(); + } + return true; + } + + protected void saveCallback() { + ThemeUtils.saveThemeChanges(themeManager); + } + + private void restoreCallback() { + if (themeManager.hasThemeChanges()) { + int result = OptionDialog.showYesNoDialog(null, "Restore Theme Values", + "Are you sure you want to discard all your changes?"); + if (result == OptionDialog.NO_OPTION) { + return; + } + } + themeManager.restoreThemeValues(); + } + + private void reloadDefaultsCallback() { + if (themeManager.hasThemeChanges()) { + int result = OptionDialog.showYesNoDialog(null, "Reload Ghidra Default Values", + "This will discard all your theme changes. Continue?"); + if (result == OptionDialog.NO_OPTION) { + return; + } + } + themeManager.reloadApplicationDefaults(); + } + + private void reset() { + colorTable.reloadAll(); + fontTable.reloadAll(); + iconTable.reloadAll(); + updateButtons(); + updateCombo(); + } + + private void themeComboChanged(ItemEvent e) { + + if (e.getStateChange() != ItemEvent.SELECTED) { + return; + } + + if (!ThemeUtils.askToSaveThemeChanges(themeManager)) { + Swing.runLater(() -> updateCombo()); + return; + } + String themeName = (String) e.getItem(); + + Swing.runLater(() -> { + GTheme theme = themeManager.getTheme(themeName); + themeManager.setTheme(theme); + if (theme.getLookAndFeelType() == LafType.GTK) { + setStatusText( + "Warning - Themes using the GTK LookAndFeel do not support changing java component colors, fonts or icons.", + MessageType.ERROR); + } + else { + setStatusText(""); + } + colorTable.reloadAll(); + fontTable.reloadAll(); + iconTable.reloadAll(); + }); + } + + private void updateButtons() { + boolean hasChanges = themeManager.hasThemeChanges(); + saveButton.setEnabled(hasChanges); + restoreButton.setEnabled(hasChanges); + } + + private JComponent createMainPanel() { + JPanel panel = new JPanel(); + + panel.setLayout(new BorderLayout()); + panel.add(buildControlPanel(), BorderLayout.NORTH); + panel.add(buildTabedTables()); + return panel; + } + + private Component buildControlPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + panel.add(buildThemeCombo(), BorderLayout.WEST); + panel.setName("gthemePanel"); + return panel; + } + + private void updateCombo() { + Set supportedThemes = themeManager.getSupportedThemes(); + List themeNames = + supportedThemes.stream().map(t -> t.getName()).collect(Collectors.toList()); + Collections.sort(themeNames); + combo.removeItemListener(comboListener); + combo.setModel(new DefaultComboBoxModel(new Vector(themeNames))); + combo.setSelectedItem(themeManager.getActiveTheme().getName()); + combo.addItemListener(comboListener); + } + + private Component buildThemeCombo() { + JPanel panel = new JPanel(); + Set supportedThemes = themeManager.getSupportedThemes(); + List themeNames = + supportedThemes.stream().map(t -> t.getName()).collect(Collectors.toList()); + Collections.sort(themeNames); + + combo = new GhidraComboBox<>(themeNames); + combo.setSelectedItem(themeManager.getActiveTheme().getName()); + combo.addItemListener(comboListener); + + panel.add(new JLabel("Theme: "), BorderLayout.WEST); + panel.add(combo); + panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + return panel; + } + + private Component buildTabedTables() { + tabbedPane = new JTabbedPane(); + colorTable = new ThemeColorTable(themeManager); + fontTable = new ThemeFontTable(themeManager); + iconTable = new ThemeIconTable(themeManager); + tabbedPane.add("Colors", colorTable); + tabbedPane.add("Fonts", fontTable); + tabbedPane.add("Icons", iconTable); + return tabbedPane; + } + + private JButton createRestoreButton() { + restoreButton = new JButton("Restore"); + restoreButton.setMnemonic('R'); + restoreButton.setName("Restore"); + restoreButton.addActionListener(e -> restoreCallback()); + restoreButton.setToolTipText("Restores all values to current theme"); + return restoreButton; + } + + private JButton createSaveButton() { + saveButton = new JButton("Save"); + saveButton.setMnemonic('S'); + saveButton.setName("Save"); + saveButton.addActionListener(e -> saveCallback()); + saveButton.setToolTipText("Saves changed values to a new Theme"); + return saveButton; + } + + /** + * Edits the current theme + * @param themeManager the application ThemeManager + */ + public static void editTheme(ThemeManager themeManager) { + if (INSTANCE != null) { + INSTANCE.toFront(); + return; + } + INSTANCE = new ThemeDialog(themeManager); + DockingWindowManager.showDialog(INSTANCE); + + } + + @Override + public void close() { + Gui.removeThemeListener(listener); + super.close(); + } + + @Override + public ActionContext getActionContext(MouseEvent event) { + ActionContextProvider contextProvider = + (ActionContextProvider) tabbedPane.getSelectedComponent(); + return contextProvider.getActionContext(event); + } + + class DialogThemeListener implements ThemeListener { + @Override + public void themeChanged(ThemeEvent event) { + if (event.haveAllValuesChanged()) { + reset(); + return; + } + if (event.hasAnyColorChanged()) { + colorTable.reloadCurrent(); + } + if (event.hasAnyFontChanged()) { + fontTable.reloadCurrent(); + } + if (event.hasAnyIconChanged()) { + iconTable.reloadCurrent(); + } + updateButtons(); + } + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeFontTable.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeFontTable.java new file mode 100644 index 0000000000..0b36688696 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeFontTable.java @@ -0,0 +1,125 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.event.*; +import java.beans.PropertyChangeEvent; + +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; +import javax.swing.table.TableColumn; + +import docking.ActionContext; +import docking.action.ActionContextProvider; +import docking.widgets.table.GFilterTable; +import docking.widgets.table.GTable; +import generic.theme.FontValue; +import generic.theme.ThemeManager; +import ghidra.util.Swing; + +/** + * Font Table for Theme Dialog + */ +public class ThemeFontTable extends JPanel implements ActionContextProvider { + + private ThemeFontTableModel fontTableModel; + private FontValueEditor fontEditor = new FontValueEditor(this::fontValueChanged); + private GTable table; + private GFilterTable filterTable; + private ThemeManager themeManager; + + public ThemeFontTable(ThemeManager themeManager) { + super(new BorderLayout()); + this.themeManager = themeManager; + + fontTableModel = new ThemeFontTableModel(themeManager); + filterTable = new GFilterTable<>(fontTableModel); + table = filterTable.getTable(); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + table.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + FontValue fontValue = filterTable.getSelectedRowObject(); + if (fontValue != null) { + fontEditor.editValue(fontValue); + } + e.consume(); + } + } + }); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + FontValue value = filterTable.getItemAt(e.getPoint()); + + int col = filterTable.getColumn(e.getPoint()); + TableColumn column = table.getColumnModel().getColumn(col); + Object identifier = column.getIdentifier(); + if ("Current Font".equals(identifier) || "Id".equals(identifier)) { + fontEditor.editValue(value); + } + } + } + }); + add(filterTable, BorderLayout.CENTER); + + } + + void fontValueChanged(PropertyChangeEvent event) { + // run later - don't rock the boat in the middle of a listener callback + Swing.runLater(() -> { + FontValue newValue = (FontValue) event.getNewValue(); + themeManager.setFont(newValue); + }); + } + + /** + * Reloads all the values displayed in the table + */ + public void reloadAll() { + fontTableModel.reloadAll(); + } + + /** + * Returns the current values displayed in the table + */ + public void reloadCurrent() { + fontTableModel.reloadCurrent(); + } + + @Override + public ActionContext getActionContext(MouseEvent e) { + if (e == null) { + return null; + } + if (e.getSource() == table) { + FontValue currentValue = filterTable.getSelectedRowObject(); + if (currentValue == null) { + return null; + } + String id = currentValue.getId(); + FontValue themeValue = fontTableModel.getThemeValue(id); + return new ThemeTableContext(currentValue, themeValue); + } + return null; + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeFontTableModel.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeFontTableModel.java new file mode 100644 index 0000000000..35740f365b --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeFontTableModel.java @@ -0,0 +1,211 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.Component; +import java.awt.Font; +import java.util.Comparator; +import java.util.List; +import java.util.function.Supplier; + +import javax.swing.JLabel; + +import docking.widgets.table.*; +import generic.theme.*; +import ghidra.docking.settings.Settings; +import ghidra.framework.plugintool.ServiceProvider; +import ghidra.framework.plugintool.ServiceProviderStub; +import ghidra.util.table.column.AbstractGColumnRenderer; +import ghidra.util.table.column.GColumnRenderer; + +/** + * Table model for theme fonts + */ +public class ThemeFontTableModel extends GDynamicColumnTableModel { + private List fonts; + private GThemeValueMap currentValues; + private GThemeValueMap themeValues; + private GThemeValueMap defaultValues; + private ThemeManager themeManager; + + public ThemeFontTableModel(ThemeManager themeManager) { + super(new ServiceProviderStub()); + this.themeManager = themeManager; + load(); + } + + /** + * Reloads the just the current values shown in the table. Called whenever a font changes. + */ + public void reloadCurrent() { + currentValues = themeManager.getCurrentValues(); + fonts = currentValues.getFonts(); + fireTableDataChanged(); + } + + /** + * Reloads all the current values and all the default values in the table. Called when the + * theme changes or the application defaults have been forced to reload. + */ + public void reloadAll() { + load(); + fireTableDataChanged(); + } + + private void load() { + currentValues = themeManager.getCurrentValues(); + fonts = currentValues.getFonts(); + themeValues = themeManager.getThemeValues(); + defaultValues = themeManager.getDefaults(); + } + + @Override + public String getName() { + return "Fonts"; + } + + @Override + public List getModelData() { + return fonts; + } + + @Override + protected TableColumnDescriptor createTableColumnDescriptor() { + TableColumnDescriptor descriptor = new TableColumnDescriptor<>(); + descriptor.addVisibleColumn(new IdColumn()); + descriptor.addVisibleColumn(new FontValueColumn("Current Font", () -> currentValues)); + descriptor.addVisibleColumn(new FontValueColumn("Theme Font", () -> themeValues)); + descriptor.addVisibleColumn(new FontValueColumn("Default Font", () -> defaultValues)); + return descriptor; + } + + @Override + public Object getDataSource() { + return null; + } + + private String getValueText(FontValue fontValue) { + if (fontValue == null) { + return ""; + } + if (fontValue.getReferenceId() != null) { + return "[" + fontValue.getReferenceId() + "]"; + } + + Font font = fontValue.getRawValue(); + return FontValue.fontToString(font); + } + + class IdColumn extends AbstractDynamicTableColumn { + + @Override + public String getColumnName() { + return "Id"; + } + + @Override + public String getValue(FontValue fontValue, Settings settings, Object data, + ServiceProvider provider) throws IllegalArgumentException { + return fontValue.getId(); + } + + @Override + public int getColumnPreferredWidth() { + return 300; + } + } + + class FontValueColumn extends AbstractDynamicTableColumn { + private ThemeFontRenderer renderer; + private String name; + private Supplier valueSupplier; + + FontValueColumn(String name, Supplier supplier) { + this.name = name; + this.valueSupplier = supplier; + renderer = new ThemeFontRenderer(); + } + + @Override + public String getColumnName() { + return name; + } + + @Override + public FontValue getValue(FontValue fontValue, Settings settings, Object data, + ServiceProvider provider) throws IllegalArgumentException { + GThemeValueMap valueMap = valueSupplier.get(); + String id = fontValue.getId(); + return valueMap.getFont(id); + } + + @Override + public GColumnRenderer getColumnRenderer() { + return renderer; + } + + public Comparator getComparator() { + return (v1, v2) -> { + if (v1 == null && v2 == null) { + return 0; + } + if (v1 == null) { + return 1; + } + if (v2 == null) { + return -1; + } + return getValueText(v1).compareTo(getValueText(v2)); + }; + } + + @Override + public int getColumnPreferredWidth() { + return 300; + } + + } + + private class ThemeFontRenderer extends AbstractGColumnRenderer { + + @Override + public Component getTableCellRendererComponent(GTableCellRenderingData data) { + JLabel label = (JLabel) super.getTableCellRendererComponent(data); + FontValue fontValue = (FontValue) data.getValue(); + + String text = getValueText(fontValue); + label.setText(text); + label.setOpaque(true); + return label; + } + + @Override + public String getFilterString(FontValue fontValue, Settings settings) { + return getValueText(fontValue); + } + + } + + /** + * Returns the original value for the id as defined by the current theme + * @param id the resource id to get a font value for + * @return the original value for the id as defined by the current theme + */ + public FontValue getThemeValue(String id) { + return themeValues.getFont(id); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeIconTable.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeIconTable.java new file mode 100644 index 0000000000..0514c902b7 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeIconTable.java @@ -0,0 +1,118 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.BorderLayout; +import java.awt.event.*; +import java.beans.PropertyChangeEvent; + +import javax.swing.*; +import javax.swing.table.TableColumn; + +import docking.ActionContext; +import docking.action.ActionContextProvider; +import docking.widgets.table.GFilterTable; +import docking.widgets.table.GTable; +import generic.theme.IconValue; +import generic.theme.ThemeManager; +import ghidra.util.Swing; + +/** + * Icon Table for Theme Dialog + */ +public class ThemeIconTable extends JPanel implements ActionContextProvider { + + private ThemeIconTableModel iconTableModel; + private IconValueEditor iconEditor = new IconValueEditor(this::iconValueChanged); + private GTable table; + private GFilterTable filterTable; + private ThemeManager themeManager; + + public ThemeIconTable(ThemeManager themeManager) { + super(new BorderLayout()); + this.themeManager = themeManager; + iconTableModel = new ThemeIconTableModel(themeManager); + filterTable = new GFilterTable<>(iconTableModel); + table = filterTable.getTable(); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + table.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + IconValue iconValue = filterTable.getSelectedRowObject(); + if (iconValue != null) { + iconEditor.editValue(iconValue); + } + e.consume(); + } + } + }); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + IconValue value = filterTable.getItemAt(e.getPoint()); + + int col = filterTable.getColumn(e.getPoint()); + TableColumn column = table.getColumnModel().getColumn(col); + Object identifier = column.getIdentifier(); + if ("Current Icon".equals(identifier) || "Id".equals(identifier)) { + iconEditor.editValue(value); + } + } + } + }); + add(filterTable, BorderLayout.CENTER); + } + + void iconValueChanged(PropertyChangeEvent event) { + // run later - don't rock the boat in the middle of a listener callback + Swing.runLater(() -> { + IconValue newValue = (IconValue) event.getNewValue(); + themeManager.setIcon(newValue); + }); + } + + /** + * Reloads all the values displayed in the table + */ + public void reloadAll() { + iconTableModel.reloadAll(); + } + + /** + * Returns the current values displayed in the table + */ + public void reloadCurrent() { + iconTableModel.reloadCurrent(); + } + + @Override + public ActionContext getActionContext(MouseEvent e) { + if (e.getSource() == table) { + IconValue currentValue = filterTable.getSelectedRowObject(); + if (currentValue == null) { + return null; + } + String id = currentValue.getId(); + IconValue themeValue = iconTableModel.getThemeValue(id); + return new ThemeTableContext(currentValue, themeValue); + } + return null; + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeIconTableModel.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeIconTableModel.java new file mode 100644 index 0000000000..13b60bc181 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeIconTableModel.java @@ -0,0 +1,245 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.Component; +import java.util.Comparator; +import java.util.List; +import java.util.function.Supplier; + +import javax.swing.*; + +import docking.widgets.table.*; +import generic.theme.*; +import ghidra.docking.settings.Settings; +import ghidra.framework.plugintool.ServiceProvider; +import ghidra.framework.plugintool.ServiceProviderStub; +import ghidra.util.table.column.AbstractGColumnRenderer; +import ghidra.util.table.column.GColumnRenderer; +import resources.icons.*; + +/** + * Table model for theme icons + */ +public class ThemeIconTableModel extends GDynamicColumnTableModel { + private List icons; + private GThemeValueMap currentValues; + private GThemeValueMap themeValues; + private GThemeValueMap defaultValues; + private ThemeManager themeManager; + + public ThemeIconTableModel(ThemeManager themeManager) { + super(new ServiceProviderStub()); + this.themeManager = themeManager; + load(); + } + + /** + * Reloads the just the current values shown in the table. Called whenever an icon changes. + */ + public void reloadCurrent() { + currentValues = themeManager.getCurrentValues(); + icons = currentValues.getIcons(); + fireTableDataChanged(); + } + + /** + * Reloads all the current values and all the default values in the table. Called when the + * theme changes or the application defaults have been forced to reload. + */ + public void reloadAll() { + load(); + fireTableDataChanged(); + } + + private void load() { + currentValues = themeManager.getCurrentValues(); + icons = currentValues.getIcons(); + themeValues = themeManager.getThemeValues(); + defaultValues = themeManager.getDefaults(); + } + + @Override + public String getName() { + return "Fonts"; + } + + @Override + public List getModelData() { + return icons; + } + + @Override + protected TableColumnDescriptor createTableColumnDescriptor() { + TableColumnDescriptor descriptor = new TableColumnDescriptor<>(); + descriptor.addVisibleColumn(new IdColumn()); + descriptor.addVisibleColumn(new IconValueColumn("Current Icon", () -> currentValues)); + descriptor.addVisibleColumn(new IconValueColumn("Theme Icon", () -> themeValues)); + descriptor.addVisibleColumn(new IconValueColumn("Default Icon", () -> defaultValues)); + return descriptor; + } + + @Override + public Object getDataSource() { + return null; + } + + class IdColumn extends AbstractDynamicTableColumn { + + @Override + public String getColumnName() { + return "Id"; + } + + @Override + public String getValue(IconValue iconValue, Settings settings, Object data, + ServiceProvider provider) throws IllegalArgumentException { + return iconValue.getId(); + } + + @Override + public int getColumnPreferredWidth() { + return 300; + } + } + + class IconValueColumn extends AbstractDynamicTableColumn { + private ThemeIconRenderer renderer; + private String name; + private Supplier valueSupplier; + + IconValueColumn(String name, Supplier supplier) { + this.name = name; + this.valueSupplier = supplier; + renderer = new ThemeIconRenderer(); + } + + @Override + public String getColumnName() { + return name; + } + + @Override + public ResolvedIcon getValue(IconValue iconValue, Settings settings, Object data, + ServiceProvider provider) throws IllegalArgumentException { + GThemeValueMap valueMap = valueSupplier.get(); + String id = iconValue.getId(); + IconValue value = valueMap.getIcon(id); + if (value == null) { + return null; + } + Icon icon = value.get(valueMap); + return new ResolvedIcon(id, value.getReferenceId(), icon); + } + + @Override + public GColumnRenderer getColumnRenderer() { + return renderer; + } + + @Override + public Comparator getComparator() { + return (v1, v2) -> { + if (v1 == null && v2 == null) { + return 0; + } + if (v1 == null) { + return 1; + } + if (v2 == null) { + return -1; + } + return v1.icon().toString().compareTo(v2.icon().toString()); + }; + } + + @Override + public int getColumnPreferredWidth() { + return 300; + } + + } + + private class ThemeIconRenderer extends AbstractGColumnRenderer { + + public ThemeIconRenderer() { + setFont(Gui.getFont("font.monospaced")); + } + + @Override + public Component getTableCellRendererComponent(GTableCellRenderingData data) { + Component comp = super.getTableCellRendererComponent(data); + JLabel label = (JLabel) comp; + ResolvedIcon resolved = (ResolvedIcon) data.getValue(); + + String text = getValueText(resolved); + Icon icon = prepareIcon(resolved.icon()); + label.setIcon(icon); + label.setText(text); + label.setOpaque(true); + return label; + } + + private Icon prepareIcon(Icon icon) { + if (!(icon instanceof LazyImageIcon)) { + icon = new ProtectedIcon(icon); + } + if (icon.getIconWidth() != 16 && icon.getIconHeight() != 16) { + icon = new ScaledImageIcon(icon, 16, 16); + } + return icon; + } + + private String getValueText(ResolvedIcon resolvedIcon) { + if (resolvedIcon == null) { + return ""; + } + Icon icon = resolvedIcon.icon(); + String sizeString = "[" + icon.getIconWidth() + "x" + icon.getIconHeight() + "] "; + + String iconString = GTheme.JAVA_ICON; + if (icon instanceof UrlImageIcon urlIcon) { + iconString = urlIcon.getOriginalPath(); + } + else if (icon instanceof ImageIcon imageIcon) { + String description = imageIcon.getDescription(); + if (description != null) { + iconString = "[" + description + "]"; + } + } + if (resolvedIcon.refId() != null) { + iconString = resolvedIcon.refId() + " [" + iconString + "]"; + } + return String.format("%-8s%s", sizeString, iconString); + } + + @Override + public String getFilterString(ResolvedIcon iconValue, Settings settings) { + return getValueText(iconValue); + } + } + + record ResolvedIcon(String id, String refId, Icon icon) {/**/} + + /** + * Returns the original value for the id as defined by the current theme + * @param id the resource id to get a font value for + * @return the original value for the id as defined by the current theme + */ + public IconValue getThemeValue(String id) { + return themeValues.getIcon(id); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeTableContext.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeTableContext.java new file mode 100644 index 0000000000..dbd0ae22a8 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeTableContext.java @@ -0,0 +1,61 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import docking.ActionContext; +import generic.theme.ThemeValue; + +/** + * ActionContext for ThemeDialog tables + * + * @param the resource type (Color, Font, or Icon) + */ +public class ThemeTableContext extends ActionContext { + + private ThemeValue currentValue; + private ThemeValue themeValue; + + public ThemeTableContext(ThemeValue currentValue, ThemeValue themeValue) { + this.currentValue = currentValue; + this.themeValue = themeValue; + } + + /** + * Returns the currentValue of the selected table row + * @return the currentValue of the selected table row + */ + public ThemeValue getCurrentValue() { + return currentValue; + } + + /** + * Returns the original theme value of the selected table row + * @return the original theme value of the selected table row + */ + public ThemeValue getThemeValue() { + return themeValue; + } + + /** + * Returns true if the current value is not the same as the original theme value for the + * selected table row + * @return true if the current value is not the same as the original theme value for the + * selected table row + */ + public boolean isChanged() { + return !currentValue.equals(themeValue); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java new file mode 100644 index 0000000000..0b3dcef9d9 --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeUtils.java @@ -0,0 +1,246 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import docking.DockingWindowManager; +import docking.widgets.OptionDialog; +import docking.widgets.SelectFromListDialog; +import docking.widgets.dialogs.InputDialog; +import docking.widgets.filechooser.GhidraFileChooser; +import docking.widgets.filechooser.GhidraFileChooserMode; +import generic.theme.*; +import ghidra.framework.Application; +import ghidra.util.Msg; +import ghidra.util.filechooser.ExtensionFileFilter; + +/** + * Some common methods related to saving themes. These are invoked from various places to handle + * what to do if a change is made that would result in loosing theme changes. + */ +public class ThemeUtils { + + /** + * Asks the user if they want to save the current theme changes. If they answer yes, it + * will handle several use cases such as whether it gets saved to a new file or + * overwrites an existing file. + * @return true if the operation was not cancelled + */ + public static boolean askToSaveThemeChanges(ThemeManager themeManager) { + if (themeManager.hasThemeChanges()) { + int result = OptionDialog.showYesNoCancelDialog(null, "Save Theme Changes?", + "You have made changes to the theme.\n Do you want save your changes?"); + if (result == OptionDialog.CANCEL_OPTION) { + return false; + } + if (result == OptionDialog.YES_OPTION) { + return ThemeUtils.saveThemeChanges(themeManager); + } + themeManager.reloadApplicationDefaults(); + } + return true; + } + + /** + * Saves all current theme changes. Handles several use cases such as requesting a new theme + * name and asking to overwrite an existing file. + * @return true if the operation was not cancelled + */ + public static boolean saveThemeChanges(ThemeManager themeManager) { + GTheme activeTheme = themeManager.getActiveTheme(); + String name = activeTheme.getName(); + + while (!canSaveToName(themeManager, name)) { + name = getNameFromUser(name); + if (name == null) { + return false; + } + } + return saveCurrentValues(themeManager, name); + } + + /** + * Resets the theme to the default, handling the case where the current theme has changes. + */ + public static void resetThemeToDefault(ThemeManager themeManager) { + if (askToSaveThemeChanges(themeManager)) { + themeManager.setTheme(themeManager.getDefaultTheme()); + } + } + + /** + * Imports a theme. Handles the case where there are existing changes to the current theme. + * @param themeManager the application ThemeManager + */ + public static void importTheme(ThemeManager themeManager) { + GhidraFileChooser chooser = new GhidraFileChooser(null); + chooser.setTitle("Choose Theme File"); + chooser.setApproveButtonToolTipText("Select File"); + chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY); + chooser.setFileFilter(ExtensionFileFilter.forExtensions("Ghidra Theme Files", + GTheme.FILE_EXTENSION, GTheme.ZIP_FILE_EXTENSION)); + + File file = chooser.getSelectedFile(); + if (file == null) { + return; + } + importTheme(themeManager, file); + } + + static void importTheme(ThemeManager themeManager, File themeFile) { + if (!ThemeUtils.askToSaveThemeChanges(themeManager)) { + return; + } + GTheme startingTheme = themeManager.getActiveTheme(); + try { + GTheme imported = GTheme.loadTheme(themeFile); + // by setting the theme, we can let the normal save handle all the edge cases + // such as if a theme with that names exists and if so, should it be overwritten? + // Also, the imported theme may contain default values which we don't want to save. So + // by going through the usual save mechanism, only values that differ from defaults + // be saved. + themeManager.setTheme(imported); + if (!ThemeUtils.saveThemeChanges(themeManager)) { + themeManager.setTheme(startingTheme); + } + } + catch (IOException e) { + Msg.showError(ThemeUtils.class, null, "Error Importing Theme File", + "Error encountered importing file: " + themeFile.getAbsolutePath(), e); + } + + } + + /** + * Exports a theme, prompting the user to pick an file. Also handles dealing with any + * existing changes to the current theme. + * @param themeManager the ThemeManager that actually does the export + */ + public static void exportTheme(ThemeManager themeManager) { + if (!ThemeUtils.askToSaveThemeChanges(themeManager)) { + return; + } + boolean hasExternalIcons = !themeManager.getActiveTheme().getExternalIconFiles().isEmpty(); + String message = + "Export as zip file? (You are not using any external icons so the zip\n" + + "file would only contain a single theme file.)"; + if (hasExternalIcons) { + message = + "Export as zip file? (You have external icons so a zip file is required if you\n" + + "want to include the icons in the export.)"; + } + int result = OptionDialog.showOptionDialog(null, "Export as Zip?", message, "Export Zip", + "Export File", OptionDialog.QUESTION_MESSAGE); + if (result == OptionDialog.CANCEL_OPTION) { + return; + } + boolean exportAsZip = result == OptionDialog.OPTION_ONE; + + ExportThemeDialog dialog = new ExportThemeDialog(themeManager, exportAsZip); + DockingWindowManager.showDialog(dialog); + } + + /** + * Prompts for and deletes a selected theme. + */ + public static void deleteTheme(ThemeManager themeManager) { + List savedThemes = new ArrayList<>( + themeManager.getAllThemes().stream().filter(t -> t.getFile() != null).toList()); + if (savedThemes.isEmpty()) { + Msg.showInfo(ThemeUtils.class, null, "Delete Theme", "There are no deletable themes"); + return; + } + + GTheme selectedTheme = SelectFromListDialog.selectFromList(savedThemes, "Delete Theme", + "Select theme to delete", t -> t.getName()); + if (selectedTheme == null) { + return; + } + if (themeManager.getActiveTheme().equals(selectedTheme)) { + Msg.showWarn(ThemeUtils.class, null, "Delete Failed", + "Can't delete the current theme."); + return; + } + GTheme fileTheme = selectedTheme; + int result = OptionDialog.showYesNoDialog(null, "Delete Theme: " + fileTheme.getName(), + "Are you sure you want to delete theme " + fileTheme.getName()); + if (result == OptionDialog.YES_OPTION) { + themeManager.deleteTheme(fileTheme); + } + } + + private static String getNameFromUser(String name) { + InputDialog inputDialog = new InputDialog("Create Theme", "New Theme Name", name); + DockingWindowManager.showDialog(inputDialog); + return inputDialog.getValue(); + } + + private static boolean canSaveToName(ThemeManager themeManager, String name) { + GTheme existing = themeManager.getTheme(name); + // if no theme exists with that name, then we are save to save it + if (existing == null) { + return true; + } + // if the existing theme is a built-in theme, then we definitely can't save to that name + if (existing instanceof DiscoverableGTheme) { + return false; + } + // if the existing theme with that name has no associated file, we can save it without + // worrying about overwriting an existing file. + if (existing.getFile() == null) { + return true; + } + int result = OptionDialog.showYesNoDialog(null, "Overwrite Existing Theme?", + "Do you want to overwrite the existing theme file for \"" + name + "\"?"); + return result == OptionDialog.YES_OPTION; + } + + private static boolean saveCurrentValues(ThemeManager themeManager, String themeName) { + GTheme activeTheme = themeManager.getActiveTheme(); + File file = getSaveFile(themeName); + + GTheme newTheme = new GTheme(file, themeName, activeTheme.getLookAndFeelType(), + activeTheme.useDarkDefaults()); + newTheme.load(themeManager.getNonDefaultValues()); + try { + newTheme.save(); + themeManager.addTheme(newTheme); + themeManager.setTheme(newTheme); + } + catch (IOException e) { + Msg.showError(ThemeUtils.class, null, "I/O Error", + "Error writing theme file: " + newTheme.getFile().getAbsolutePath(), e); + return false; + } + + return true; + + } + + private static File getSaveFile(String themeName) { + File dir = Application.getUserSettingsDirectory(); + File themeDir = new File(dir, ThemeFileLoader.THEME_DIR); + if (!themeDir.exists()) { + themeDir.mkdir(); + } + String cleanedName = themeName.replaceAll(" ", "_") + "." + GTheme.FILE_EXTENSION; + return new File(themeDir, cleanedName); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java new file mode 100644 index 0000000000..068bd640ae --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/theme/gui/ThemeValueEditor.java @@ -0,0 +1,159 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import java.awt.BorderLayout; +import java.beans.*; + +import javax.swing.*; + +import docking.DialogComponentProvider; +import docking.DockingWindowManager; +import generic.theme.ThemeValue; + +/** + * Base class for Theme property Editors (Colors, Fonts, and Icons) + * + * @param the base property (Color, Font, or Icon) + */ +public abstract class ThemeValueEditor { + private PropertyChangeListener clientListener; + protected ThemeValue currentThemeValue; + private EditorDialog dialog; + private String typeName; + protected PropertyEditor editor; + + /** + * Constructor + * + * @param typeName the name of the type (Used in the dialog title) + * @param listener the {@link PropertyChangeListener} to be notified for changes + * @param editor the standard property editor for the type + */ + protected ThemeValueEditor(String typeName, PropertyChangeListener listener, + PropertyEditor editor) { + this.typeName = typeName; + this.clientListener = listener; + this.editor = editor; + } + + /** + * Edits the ThemeValue by invoking the appropriate dialog for editing the type + * @param themeValue the value to be edited + */ + public void editValue(ThemeValue themeValue) { + this.currentThemeValue = themeValue; + if (dialog == null) { + dialog = new EditorDialog(themeValue); + DockingWindowManager.showDialog(dialog); + } + else { + dialog.setValue(themeValue); + dialog.toFront(); + } + + } + + /** + * Called when the user has pressed ok. This allows sub-classes to store any state for + * future dialog invocations. + */ + protected void storeState() { + // for sub-classes + } + + /** + * Returns the actual value (Color, Font, or Icon) + * @param id the theme property id for the value + * @return the current stored value for the id + */ + protected abstract T getRawValue(String id); + + /** + * Factory method for creating the ThemeValue of the correct type. + * @param id the id for theme property + * @param newValue the new value for the underlying type (Color, Font, or Icon) + * @return the new ThemeValue for the type + */ + protected abstract ThemeValue createNewThemeValue(String id, T newValue); + + private void valueChanged(T value) { + ThemeValue oldValue = currentThemeValue; + String id = oldValue.getId(); + ThemeValue newValue = createNewThemeValue(id, value); + firePropertyChangeEvent(oldValue, newValue); + PropertyChangeEvent event = + new PropertyChangeEvent(this, id, oldValue, newValue); + clientListener.propertyChange(event); + } + + private void firePropertyChangeEvent(ThemeValue oldValue, ThemeValue newValue) { + PropertyChangeEvent event = + new PropertyChangeEvent(this, oldValue.getId(), oldValue, newValue); + clientListener.propertyChange(event); + } + + class EditorDialog extends DialogComponentProvider { + private PropertyChangeListener internalListener = ev -> editorChanged(); + private ThemeValue originalValue; + + protected EditorDialog(ThemeValue initialValue) { + super("Edit " + typeName + ": " + currentThemeValue.getId(), false, false, true, false); + this.originalValue = initialValue; + addWorkPanel(buildWorkPanel(getRawValue(initialValue.getId()))); + addOKButton(); + addCancelButton(); + setRememberSize(false); + } + + @SuppressWarnings("unchecked") + private void editorChanged() { + valueChanged((T) editor.getValue()); + } + + JComponent buildWorkPanel(T initialValue) { + JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10)); + panel.add(editor.getCustomEditor(), BorderLayout.CENTER); + + editor.setValue(initialValue); + editor.addPropertyChangeListener(internalListener); + return panel; + } + + void setValue(ThemeValue value) { + originalValue = value; + editor.removePropertyChangeListener(internalListener); + editor.setValue(getRawValue(value.getId())); + editor.addPropertyChangeListener(internalListener); + } + + @Override + protected void okCallback() { + close(); + storeState(); + dialog = null; + } + + @Override + protected void cancelCallback() { + firePropertyChangeEvent(currentThemeValue, originalValue); + close(); + dialog = null; + } + + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/AnimationUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/util/AnimationUtils.java index db1a2d9f79..23e83db0f4 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/AnimationUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/util/AnimationUtils.java @@ -25,13 +25,15 @@ import org.jdesktop.animation.timing.Animator.RepeatBehavior; import org.jdesktop.animation.timing.TimingTargetAdapter; import org.jdesktop.animation.timing.interpolation.PropertySetter; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.WindowUtilities; import generic.util.image.ImageUtils; import ghidra.util.Msg; import ghidra.util.bean.GGlassPane; import ghidra.util.bean.GGlassPanePainter; import ghidra.util.exception.AssertException; -import resources.ResourceManager; public class AnimationUtils { @@ -392,12 +394,11 @@ public class AnimationUtils { @Override public void paint(GGlassPane glassPane, Graphics g) { - Color gray = Color.GRAY; + Color gray = Palette.GRAY; // double darknessFudge = .95; // double progress = percentComplete * darknessFudge; // emphasis starts at 1 // int alpha = Math.min(255, (int) (255 * progress)); -// gray = new Color(gray.getRed(), gray.getGreen(), gray.getBlue(), alpha); - gray = new Color(gray.getRed(), gray.getGreen(), gray.getBlue()); +// gray = ColorUtils.fromRgba(gray.getRed(), gray.getGreen(), gray.getBlue(), alpha); Graphics2D g2d = (Graphics2D) g; Composite originaComposite = g2d.getComposite(); @@ -819,7 +820,7 @@ public class AnimationUtils { @Override public void paint(GGlassPane glassPane, Graphics g) { - Color background = new Color(218, 232, 250); + Color background = Palette.getColor("lightsteelblue"); g.setColor(background); Rectangle defaultBounds = component.getBounds(); @@ -877,7 +878,7 @@ public class AnimationUtils { double cx = emphasizedBounds.getCenterX(); double cy = emphasizedBounds.getCenterY(); g2d.rotate(rad, cx, cy); - g.setColor(Color.BLACK); + g.setColor(Java.BORDER); int iw = emphasizedBounds.width; int ih = emphasizedBounds.height; @@ -1170,6 +1171,7 @@ public class AnimationUtils { private static class DragonImagePainter implements GGlassPanePainter { + private static final GIcon ICON = new GIcon("icon.dragon.256"); private Component component; private double percentComplete = 0.0; @@ -1195,9 +1197,7 @@ public class AnimationUtils { AlphaComposite.getInstance(AlphaComposite.SrcOver.getRule(), alpha); g2d.setComposite(alphaComposite); - ImageIcon ghidra = ResourceManager.loadImage("images/GhidraIcon256.png"); - Image ghidraImage = ghidra.getImage(); - + Image ghidraImage = ICON.getImageIcon().getImage(); Rectangle fullBounds = component.getBounds(); fullBounds = SwingUtilities.convertRectangle(component.getParent(), fullBounds, glassPane); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java b/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java deleted file mode 100644 index c48cc0151e..0000000000 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/BadgedIcon.java +++ /dev/null @@ -1,371 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package docking.util; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.*; - -import javax.swing.Icon; -import javax.swing.ImageIcon; - -import resources.MultiIcon; -import resources.ResourceManager; -import resources.icons.EmptyIcon; -import resources.icons.ScaledImageIcon; - -/** - * An icon that allows sub-icons to be added at key perimeter locations. Each position can - * be manipulated independently, adding and removing icons as desired. Additionally, - * each position can be toggled enabled or disabled, or visible or invisible. - */ -public class BadgedIcon implements Icon { - - /* - * The top-edge horizontal positions move up 20% from origin - * The middle horizontal positions are at origin+30% - * The bottom-edge horizontal positions are at origin+60% - * - * The left-edge vertical positions move left 20% from origin - * The middle vertical positions are at origin+30% - * The right-edge vertical positions are at origin+60% - * - */ - public enum BadgePosition { - TopLeft(-.2, -.2), - TopMiddle(.3, -.2), - TopRight(.6, -.2), - - LeftMiddle(-.2, .3), - Center(.3, .3), - RightMiddle(.6, .3), - - BottomLeft(-.2, .6), - BottomMiddle(.3, .6), - BottomRight(.6, .6); - - private final double horizontalDisplacementFactor; - private final double verticalDisplacementFactor; - - private BadgePosition(double hdf, double vdf) { - horizontalDisplacementFactor = hdf; - verticalDisplacementFactor = vdf; - } - - public double getHorizontalDisplacementFactor() { - return horizontalDisplacementFactor; - } - - public double getVerticalDisplacementFactor() { - return verticalDisplacementFactor; - } - - } - - private Map badgeMap = new EnumMap<>(BadgePosition.class); - private Map badgeEnablement = new EnumMap<>(BadgePosition.class); - private Map badgeVisibility = new EnumMap<>(BadgePosition.class); - - private static double BADGE_HSCALE_FACTOR = .75; - private static double BADGE_VSCALE_FACTOR = .75; - - // if the icon hasn't changed, this will help in painting... - private Icon cachedThis = null; - - private Icon base; - - private int height; - private int width; - private boolean enabled; - - public BadgedIcon(Icon baseIcon) { - this(baseIcon, true); - } - - public BadgedIcon(Icon baseIcon, boolean enabled) { - this(baseIcon, enabled, baseIcon.getIconWidth(), baseIcon.getIconHeight()); - } - - public BadgedIcon(Icon baseIcon, boolean enabled, int width, int height) { - - Objects.requireNonNull(baseIcon, "Base Icon must not be null"); - - this.base = baseIcon; - this.width = width; - this.height = height; - this.enabled = enabled; - - initDefaultBadges(); - - cachedThis = null; - } - - private static MultiIcon getEmptyIcon(int width, int height, boolean enabled) { - return new MultiIcon(new EmptyIcon(width, height), !enabled); - } - - private void initDefaultBadges() { - for (BadgePosition pos : BadgePosition.values()) { - - badgeMap.put(pos, getEmptyIcon(width, height, enabled)); - badgeEnablement.put(pos, true); - badgeVisibility.put(pos, true); - } - } - - /** - * Add an icon at the specified location - * @param badge The icon - * @param position Where to place the image - * @return a reference to this object - */ - public BadgedIcon addBadge(Icon badge, BadgePosition position) { - - badgeMap.get(position).addIcon(badge); - - height = Math.max(height, badge.getIconHeight()); - width = Math.max(width, badge.getIconWidth()); - - cachedThis = null; - - return this; - } - - public BadgedIcon addScaledBadge(Icon icon, int newWidth, int newHeight, - BadgePosition position) { - - Icon badge = ResourceManager.getScaledIcon(icon, width, height); - - badgeMap.get(position).addIcon(badge); - - height = Math.max(height, badge.getIconHeight()); - width = Math.max(width, badge.getIconWidth()); - - cachedThis = null; - - return this; - } - - /** - * Replace the existing icon with the provided icon at the specified location - * @param badge The icon - * @param position Where to place the image - * @return a reference to this object - */ - public BadgedIcon setBadge(Icon badge, BadgePosition position) { - MultiIcon multi = null; - if (badge == null) { - badge = getEmptyIcon(width, height, enabled); - } - multi = new MultiIcon(badge, enabled, width, height); - badgeMap.put(position, multi); - - cachedThis = null; - - return this; - } - - /** - * Remove the badge from the specified location - * @param position Where to place the image - * @return a reference to this object - */ - public BadgedIcon removeBadge(BadgePosition position) { - setBadge(null, position); - return this; - } - - /** - * Set the enablement of the badge at the specified location - * @param position Which icon to modify - * @param enabled True if the image should be shown 'enabled', false otherwise - * @see BadgedIcon#isBadgeEnabled(BadgePosition) - */ - public void setBadgeEnabled(BadgePosition position, boolean enabled) { - if (isBadgeEnabled(position) == enabled) { - return; - } - badgeEnablement.put(position, enabled); - cachedThis = null; - } - - /** - * Get the enablement status of the badge at the specified location - * @param position Which icon to enquire about - * @return True if the badge is enabled, false otherwise - * @see BadgedIcon#setBadgeEnabled(BadgePosition, boolean) - */ - public boolean isBadgeEnabled(BadgePosition position) { - return badgeEnablement.get(position); - } - - /** - * Set the visibility status of the badge at the specified location - * @param position Which icon to modify - * @param visible True if the badge should be visible, false otherwise - * @see #isBadgeVisible(BadgePosition) - */ - public void setBadgeVisisble(BadgePosition position, boolean visible) { - if (isBadgeVisible(position) == visible) { - return; - } - badgeVisibility.put(position, visible); - - cachedThis = null; - } - - /** - * Get the visibility status of the badge at the specified location - * @param position Which icon to enquire about - * @return True if the badge is visible, false otherwise - * @see #setBadgeVisisble(BadgePosition, boolean) - */ - public boolean isBadgeVisible(BadgePosition position) { - return badgeVisibility.get(position); - } - - /** - * @see javax.swing.Icon#getIconHeight() - */ - @Override - public int getIconHeight() { - return height; - } - - /** - * @see javax.swing.Icon#getIconWidth() - */ - @Override - public int getIconWidth() { - return width; - } - - /** - * Determine the overall enablement appearance state. - * @return true if the if the entire icon is rendered as 'enabled'; false otherwise. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Set the 'enabled' appearance of the entire icon. - * Preserves the underlying enablement state of badges, though the entire icon - * looks disabled if setEnabled(true) is called. - * @param enabled - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * Return array of Icons that were added to this BadgedIcon. - */ - public Icon[] getBadges(BadgePosition pos) { - MultiIcon badge = badgeMap.get(pos); - return badge.getIcons(); - } - - private Dimension getBadgeDimension() { - return new Dimension((int) (width * BADGE_HSCALE_FACTOR), - (int) (height * BADGE_VSCALE_FACTOR)); - } - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - - if (cachedThis != null) { - cachedThis.paintIcon(c, g, x, y); - } - else { - Dimension badgeSize = getBadgeDimension(); - doPaintIcon(c, g, x, y, badgeSize); - } - - if (!enabled) { - // Alpha blend to background - Color bgColor = c.getBackground(); - g.setColor(new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 128)); - g.fillRect(x, y, width, height); - } - - } - - private void doPaintIcon(Component c, Graphics g, int x, int y, Dimension badgeSize) { - BufferedImage cached = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - Graphics gc = cached.getGraphics(); - - base.paintIcon(c, gc, x, y); - - for (BadgePosition pos : BadgePosition.values()) { - if (!isBadgeVisible(pos)) { - continue; - } - - MultiIcon icon = badgeMap.get(pos); - - Icon scaled = new ScaledImageIcon(icon, badgeSize.width, badgeSize.height); - - Point badgePaintLoc = getBadgePaintLocation(pos, badgeSize); - - int badgeX = x + badgePaintLoc.x; - int badgeY = y + badgePaintLoc.y; - - scaled.paintIcon(c, gc, badgeX, badgeY); - - if (!isBadgeEnabled(pos)) { - // Alpha blend to background - Color bgColor = c.getBackground(); - gc.setColor( - new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 128)); - gc.fillRect(badgeX, badgeY, badgeSize.width, badgeSize.height); - } - } - - cachedThis = new ImageIcon(cached); - - cachedThis.paintIcon(c, g, x, y); - } - - private static Point getBadgePaintLocation(BadgePosition pos, Dimension badgeSize) { - - double dx = pos.getHorizontalDisplacementFactor(); - double dy = pos.getVerticalDisplacementFactor(); - - Point p = new Point((int) (dx * badgeSize.width), (int) (dy * badgeSize.height)); - - return p; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + getIconNames() + "]"; - } - - private String getIconNames() { - - StringBuffer buffy = new StringBuffer(); - - for (BadgePosition pos : BadgePosition.values()) { - MultiIcon mi = badgeMap.get(pos); - buffy.append(pos).append("[").append(mi.toString()).append("]"); - buffy.append(", "); - } - - return buffy.toString(); - } - -} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/image/Callout.java b/Ghidra/Framework/Docking/src/main/java/docking/util/image/Callout.java index db51026361..5ee71aeda1 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/image/Callout.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/util/image/Callout.java @@ -21,11 +21,12 @@ import java.awt.geom.RectangularShape; import java.awt.image.BufferedImage; import java.awt.image.VolatileImage; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.image.ImageUtils; public class Callout { - private static final Color CALLOUT_SHAPE_COLOR = new Color(0xB5, 0xDE, 0x2F); + private static final Color CALLOUT_SHAPE_COLOR = Palette.getColor("color.palette.palegreen"); private static final int CALLOUT_BORDER_PADDING = 20; public Image createCallout(CalloutComponentInfo calloutInfo) { @@ -111,13 +112,13 @@ public class Callout { // // Debug // -// g2d.setColor(Color.RED); +// g2d.setColor(Palette.RED); // g2d.draw(fullBounds); // -// g2d.setColor(Color.CYAN); +// g2d.setColor(Palette.CYAN); // g2d.draw(calloutBounds); // -// g2d.setColor(Color.BLUE); +// g2d.setColor(Palette.BLUE); // g2d.draw(cBounds); // return image; @@ -189,7 +190,7 @@ public class Callout { createCalloutImage(calloutInfo, componentLocation, calloutBounds, calloutDrawingArea); DropShadow dropShadow = new DropShadow(); - Image shadow = dropShadow.createDrowShadow(calloutImage, 40); + Image shadow = dropShadow.createDropShadow(calloutImage, 40); // // Create our final image and draw into it the callout image and its shadow @@ -214,7 +215,8 @@ public class Callout { bottomPadding = overlap; } - image = ImageUtils.padImage(image, Color.WHITE, topPadding, 0, rightPadding, bottomPadding); + image = + ImageUtils.padImage(image, Palette.WHITE, topPadding, 0, rightPadding, bottomPadding); Graphics g = image.getGraphics(); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); @@ -228,30 +230,30 @@ public class Callout { // // Debug // -// g2d.setColor(Color.RED); +// g2d.setColor(Palette.RED); // g2d.draw(fullBounds); // -// g2d.setColor(Color.CYAN); +// g2d.setColor(Palette.CYAN); // g2d.draw(calloutBounds); // -// g2d.setColor(Color.BLUE); +// g2d.setColor(Palette.BLUE); // g2d.draw(componentBounds); // -// g2d.setColor(Color.MAGENTA); +// g2d.setColor(Palette.MAGENTA); // g2d.draw(completeBounds); // -// g2d.setColor(Color.GRAY); +// g2d.setColor(Palette.GRAY); // g2d.draw(dropShadowBounds); // // Point cLocation = componentBounds.getLocation(); // Point convertedCLocation = calloutInfo.convertPointToParent(cLocation); -// g2d.setColor(Color.PINK); +// g2d.setColor(Palette.PINK); // componentBounds.setLocation(convertedCLocation); // g2d.draw(componentBounds); // // Point convertedFBLocation = calloutInfo.convertPointToParent(fullBounds.getLocation()); // fullBounds.setLocation(convertedFBLocation); -// g2d.setColor(Color.ORANGE); +// g2d.setColor(Palette.ORANGE); // g2d.draw(fullBounds); return image; @@ -404,7 +406,7 @@ public class Callout { // render the clip shape into the image g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g.setColor(Color.WHITE); + g.setColor(Palette.WHITE); g.fill(imageShape); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/image/DropShadow.java b/Ghidra/Framework/Docking/src/main/java/docking/util/image/DropShadow.java index 8d1a2da847..cc9831507c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/image/DropShadow.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/util/image/DropShadow.java @@ -23,9 +23,11 @@ import java.awt.image.*; import javax.swing.JFrame; import javax.swing.JPanel; +import generic.theme.GThemeDefaults.Colors.Palette; + public class DropShadow { - private Color shadowColor = new Color(0x000000); + private Color shadowColor = Palette.BLACK; private float shadowOpacity = 0.85f; public static void main(String[] args) { @@ -40,7 +42,7 @@ public class DropShadow { @Override protected void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; - Color background = Color.WHITE; + Color background = Palette.WHITE; g.setColor(background); Dimension size = getSize(); g.fillRect(0, 0, size.width, size.height); @@ -59,14 +61,14 @@ public class DropShadow { g2d.setComposite(AlphaComposite.Src); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setColor(Color.WHITE); + g2d.setColor(Palette.WHITE); g2d.fillOval(size.width / 4, size.height / 4, size.width / 2, size.height / 2); // Using ScrAtop uses the alpha value as a coverage for each pixel stored in // the destination. For the areas outside the clip shape, the destination alpha will // be zero, so nothing is rendered in those areas. g2d.setComposite(AlphaComposite.SrcAtop); - g2d.setPaint(new GradientPaint(0, 0, Color.RED, 0, size.height, Color.YELLOW)); + g2d.setPaint(new GradientPaint(0, 0, Palette.RED, 0, size.height, Palette.YELLOW)); g2d.fillRect(0, 0, size.width, size.height); g2d.dispose(); @@ -77,7 +79,7 @@ public class DropShadow { graphics.dispose(); image = bufferedImage; - shadow = ds.createDrowShadow(bufferedImage, 5); + shadow = ds.createDropShadow(bufferedImage, 5); // } @@ -206,7 +208,7 @@ public class DropShadow { return subject; } - public Image createDrowShadow(BufferedImage image, int shadowSize) { + public Image createDropShadow(BufferedImage image, int shadowSize) { BufferedImage subject = prepareImage(image, shadowSize); // BufferedImage shadow = diff --git a/Ghidra/Framework/Docking/src/main/java/docking/util/image/ToolIconURL.java b/Ghidra/Framework/Docking/src/main/java/docking/util/image/ToolIconURL.java index 90bd9d75d3..432acc2a53 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/util/image/ToolIconURL.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/util/image/ToolIconURL.java @@ -21,8 +21,8 @@ import java.util.Hashtable; import javax.swing.ImageIcon; -import generic.Images; import resources.ResourceManager; +import resources.icons.UnresolvedIcon; /** * Container class for an icon and its location. If the location is @@ -65,7 +65,7 @@ public class ToolIconURL implements Comparable { */ public ToolIconURL(String location) { if (location == null) { - location = Images.BOMB; + location = ResourceManager.BOMB; } this.location = location; @@ -76,7 +76,7 @@ public class ToolIconURL implements Comparable { // is it absolute, or in resources by the given path? baseIcon = ResourceManager.loadImage(iconLocation); - if (baseIcon == ResourceManager.getDefaultIcon()) { + if (baseIcon instanceof UnresolvedIcon) { // ...must not be, look for it in our 'special' locations baseIcon = loadFromKnownImageResources(iconLocation); } @@ -143,8 +143,7 @@ public class ToolIconURL implements Comparable { return image; } - return ResourceManager.getScaledIcon(unscaledIcon, SMALL_ICON_SIZE, - SMALL_ICON_SIZE); + return ResourceManager.getScaledIcon(unscaledIcon, SMALL_ICON_SIZE, SMALL_ICON_SIZE); } private ImageIcon getLargeIcon(ImageIcon unscaledIcon) { @@ -167,12 +166,11 @@ public class ToolIconURL implements Comparable { // O.K., we will scale the icon. However, if it is the default icon, we know we have // a 'large' version of that. - if (unscaledIcon == ResourceManager.getDefaultIcon()) { - return ResourceManager.loadImage(Images.BIG_BOMB); + if (unscaledIcon instanceof UnresolvedIcon) { + return ResourceManager.loadImage(ResourceManager.BIG_BOMB); } - return ResourceManager.getScaledIcon(unscaledIcon, LARGE_ICON_SIZE, - LARGE_ICON_SIZE); + return ResourceManager.getScaledIcon(unscaledIcon, LARGE_ICON_SIZE, LARGE_ICON_SIZE); } private ImageIcon findCompatibleImageForSize(String imagePath, int desiredSize) { @@ -191,11 +189,7 @@ public class ToolIconURL implements Comparable { name += location.substring(dotIndex); } - ImageIcon image = getImageIcon(name); - if (image != null) { - return image; - } - return null; + return getImageIcon(name); } private String stripSizeOffName(String name) { @@ -217,12 +211,8 @@ public class ToolIconURL implements Comparable { } private ImageIcon getImageIcon(String name) { - ImageIcon image = ResourceManager.loadImage(name); - ImageIcon defaultIcon = ResourceManager.getDefaultIcon(); - if (image == defaultIcon) { - if (!name.startsWith("images")) { - return getImageIcon("images/" + name); - } + ImageIcon image = ResourceManager.findIcon(name); + if (image instanceof UnresolvedIcon) { return null; } return image; @@ -289,16 +279,8 @@ public class ToolIconURL implements Comparable { * @param name name of the icon */ private ImageIcon loadFromKnownImageResources(String name) { - // first look in special location for tool icons String filename = "defaultTools/images/" + name; - ImageIcon image = ResourceManager.loadImage(filename); - - // if we can't find the icon in the special tool icon location, then look in general images. - if (image == ResourceManager.getDefaultIcon()) { - filename = "images/" + name; - image = ResourceManager.loadImage(filename); - } - return image; + return ResourceManager.loadImage(filename); } private void checkAnimated(ImageIcon imgIcon) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java index 48c057437f..e7e201fd91 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/AbstractGCellRenderer.java @@ -22,6 +22,8 @@ import javax.swing.JComponent; import javax.swing.border.Border; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; /** * A common base class for list and table renderer objects, unifying the Ghidra look and feel. @@ -31,8 +33,8 @@ import docking.widgets.label.GDHtmlLabel; * */ public abstract class AbstractGCellRenderer extends GDHtmlLabel { - - private static final Color ALTERNATE_BACKGROUND_COLOR = new Color(237, 243, 254); + private static final Color BACKGROUND_COLOR = new GColor("color.bg.table.row"); + private static final Color ALT_BACKGROUND_COLOR = new GColor("color.bg.table.row.alt"); /** Allows the user to disable alternating row colors on JLists and JTables */ private static final String DISABLE_ALTERNATING_ROW_COLORS_PROPERTY = @@ -56,7 +58,7 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel { public AbstractGCellRenderer() { noFocusBorder = BorderFactory.createEmptyBorder(0, 5, 0, 5); Border innerBorder = BorderFactory.createEmptyBorder(0, 4, 0, 4); - Border outerBorder = BorderFactory.createLineBorder(Color.YELLOW, 1); + Border outerBorder = BorderFactory.createLineBorder(Palette.YELLOW, 1); focusBorder = BorderFactory.createCompoundBorder(outerBorder, innerBorder); setBorder(noFocusBorder); @@ -118,7 +120,7 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel { super.setFont(f); defaultFont = f; fixedWidthFont = new Font("monospaced", defaultFont.getStyle(), defaultFont.getSize()); - boldFont = new Font(defaultFont.getName(), Font.BOLD, defaultFont.getSize()); + boldFont = f.deriveFont(Font.BOLD); } protected void superSetFont(Font font) { @@ -156,7 +158,7 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel { } protected Color getDefaultBackgroundColor() { - return Color.WHITE; + return BACKGROUND_COLOR; } protected Color getBackgroundColorForRow(int row) { @@ -164,7 +166,7 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel { if ((row & 1) == 1) { return getDefaultBackgroundColor(); } - return ALTERNATE_BACKGROUND_COLOR; + return ALT_BACKGROUND_COLOR; } // ================================================================================================== diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DefaultDropDownSelectionDataModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DefaultDropDownSelectionDataModel.java index b519d905f3..3fa2908d21 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DefaultDropDownSelectionDataModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DefaultDropDownSelectionDataModel.java @@ -27,7 +27,7 @@ public class DefaultDropDownSelectionDataModel implements DropDownTextFieldDa protected List data; - private Comparator comparator; + protected Comparator comparator; private DataToStringConverter searchConverter; private DataToStringConverter descriptionConverter; private ListCellRenderer renderer = diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownMultiSelectionTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownMultiSelectionTextField.java index 332a22d177..b97b8a329c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownMultiSelectionTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownMultiSelectionTextField.java @@ -100,7 +100,7 @@ public class DropDownMultiSelectionTextField extends DropDownSelectionTextFie previewList = new JList<>(); } previewList.setOpaque(true); - previewList.setBackground(TOOLTIP_WINDOW_BGCOLOR); + previewList.setBackground(PREVIEW_WINDOW_BGCOLOR); previewList.setFocusable(false); previewList.setModel(new DefaultListModel()); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownTextField.java index 336a087f7a..d4db3281a9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DropDownTextField.java @@ -28,6 +28,8 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.label.GDHtmlLabel; import docking.widgets.list.GList; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import generic.util.WindowUtilities; import ghidra.util.StringUtilities; import ghidra.util.SystemUtilities; @@ -61,7 +63,7 @@ public class DropDownTextField extends JTextField implements GComponent { private static final int DEFAULT_MAX_UPDATE_DELAY = 2000; private static final int MIN_HEIGHT = 300; private static final int MIN_WIDTH = 200; - protected static final Color TOOLTIP_WINDOW_BGCOLOR = new Color(255, 255, 225); + protected static final Color PREVIEW_WINDOW_BGCOLOR = Colors.BACKGROUND; private JWindow toolTipWindow; // delayed initialization for parenting private JWindow matchingWindow; // delayed initialization for parenting @@ -154,7 +156,7 @@ public class DropDownTextField extends JTextField implements GComponent { protected void setPreviewPaneAttributes() { previewLabel = new GDHtmlLabel(); previewLabel.setOpaque(true); - previewLabel.setBackground(TOOLTIP_WINDOW_BGCOLOR); + previewLabel.setBackground(PREVIEW_WINDOW_BGCOLOR); previewLabel.setVerticalAlignment(SwingConstants.TOP); previewLabel.setFocusable(false); } @@ -341,7 +343,7 @@ public class DropDownTextField extends JTextField implements GComponent { updateWindowLocation(); showMatchingWindow(); - getPreviewPaneComponent().setBackground(TOOLTIP_WINDOW_BGCOLOR); + getPreviewPaneComponent().setBackground(PREVIEW_WINDOW_BGCOLOR); toolTipWindow.setVisible(hasPreview()); } } @@ -573,7 +575,9 @@ public class DropDownTextField extends JTextField implements GComponent { matchingWindow.setFocusable(false); JScrollPane scrollPane = new JScrollPane(); scrollPane.setBorder( - BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.GRAY, Color.BLACK)); + BorderFactory.createBevelBorder(BevelBorder.RAISED, + new GColor("color.border.bevel.highlight"), + new GColor("color.border.bevel.shadow"))); scrollPane.setFocusable(false); scrollPane.getVerticalScrollBar().setFocusable(false); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/EmptyBorderButton.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/EmptyBorderButton.java index 8eb0260bba..084fdab51e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/EmptyBorderButton.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/EmptyBorderButton.java @@ -24,7 +24,7 @@ import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import ghidra.docking.util.DockingWindowsLookAndFeelUtils; +import ghidra.docking.util.LookAndFeelUtils; import resources.ResourceManager; /** @@ -45,8 +45,8 @@ public class EmptyBorderButton extends JButton { /** * An empty border. */ - public static final Border NO_BUTTON_BORDER = new EmptyBorder( - RAISED_BUTTON_BORDER.getBorderInsets(new JButton())); + public static final Border NO_BUTTON_BORDER = + new EmptyBorder(RAISED_BUTTON_BORDER.getBorderInsets(new JButton())); /** * A lowered border beveled border. @@ -123,7 +123,7 @@ public class EmptyBorderButton extends JButton { // Mac OSX LNF doesn't give us rollover callbacks, so we have to add a mouse listener to // do the work - if (DockingWindowsLookAndFeelUtils.isUsingAquaUI(getUI())) { + if (LookAndFeelUtils.isUsingAquaUI(getUI())) { addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java index 48a911fe3d..e81bd263d4 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/PopupWindow.java @@ -26,6 +26,7 @@ import javax.swing.*; import javax.swing.Timer; import docking.widgets.shapes.*; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.WindowUtilities; import ghidra.util.bean.GGlassPane; import ghidra.util.bean.GGlassPanePainter; @@ -337,7 +338,7 @@ public class PopupWindow { Point p = new Point(r.getLocation()); SwingUtilities.convertPointFromScreen(p, glassPane); - Color c = new Color(50, 50, 200, 125); + Color c = Palette.LAVENDER; g.setColor(c); g.fillRect(p.x, p.y, r.width, r.height); } @@ -346,7 +347,7 @@ public class PopupWindow { if (sourceEvent != null) { Point p = sourceEvent.getPoint(); p = SwingUtilities.convertPoint(sourceEvent.getComponent(), p.x, p.y, glassPane); - g.setColor(Color.RED); + g.setColor(Palette.RED); int offset = 10; g.fillRect(p.x - offset, p.y - offset, (offset * 2), (offset * 2)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/SelectFromListDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java similarity index 87% rename from Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/SelectFromListDialog.java rename to Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java index b1236c7a6f..2f6f77bb51 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/SelectFromListDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SelectFromListDialog.java @@ -13,11 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.formats.gfilesystem; +package docking.widgets; import java.awt.BorderLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.List; import java.util.function.Function; @@ -25,7 +23,6 @@ import javax.swing.*; import docking.DialogComponentProvider; import docking.DockingWindowManager; -import docking.widgets.MultiLineLabel; import docking.widgets.list.ListPanel; import ghidra.util.SystemUtilities; @@ -45,13 +42,13 @@ public class SelectFromListDialog extends DialogComponentProvider { * @param list list of object of type T * @param title title of dialog * @param prompt prompt shown above list - * @param toStringFunc func that converts a T into a String. + * @param toStringFunction function that converts a T into a String. * @return the chosen T object, or null if dialog canceled. */ public static T selectFromList(List list, String title, String prompt, - Function toStringFunc) { + Function toStringFunction) { SelectFromListDialog dialog = - new SelectFromListDialog<>(title, prompt, list, toStringFunc); + new SelectFromListDialog<>(title, prompt, list, toStringFunction); SystemUtilities.runSwingNow(() -> dialog.doSelect()); return dialog.actionComplete ? dialog.getSelectedObject() : null; } @@ -92,6 +89,10 @@ public class SelectFromListDialog extends DialogComponentProvider { return selectedObject; } + public void setSelectedObject(T obj) { + listPanel.setSelectedValue(obj); + } + private void doSelect() { selectedObject = null; actionComplete = false; @@ -120,12 +121,7 @@ public class SelectFromListDialog extends DialogComponentProvider { listPanel.setListModel(listModel); listPanel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); listPanel.setSelectedIndex(0); - listPanel.setDoubleClickActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - okCallback(); - } - }); + listPanel.setDoubleClickActionListener(e -> okCallback()); JPanel workPanel = new JPanel(new BorderLayout()); MultiLineLabel mll = new MultiLineLabel("\n" + prompt + ":"); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java index d45552dfef..07132bf7d1 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/autocomplete/TextFieldAutocompleter.java @@ -31,6 +31,7 @@ import javax.swing.text.Caret; import docking.DockingUtils; import docking.DockingUtils.TreeTraversalResult; import docking.widgets.textfield.TextFieldLinker; +import generic.theme.GColor; import generic.util.WindowUtilities; import ghidra.util.task.SwingUpdateManager; @@ -131,9 +132,13 @@ public class TextFieldAutocompleter { // Prepare all the swing components (except the window) { content.setBorder( - BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.LIGHT_GRAY, Color.GRAY)); + BorderFactory.createBevelBorder(BevelBorder.RAISED, + new GColor("color.border.bevel.highlight"), + new GColor("color.border.bevel.shadow"))); scrollPane.setBorder( - BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.LIGHT_GRAY, Color.GRAY)); + BorderFactory.createBevelBorder(BevelBorder.RAISED, + new GColor("color.border.bevel.highlight"), + new GColor("color.border.bevel.shadow"))); //content.setFocusable(false); scrollPane.getVerticalScrollBar().setFocusable(false); @@ -1094,7 +1099,7 @@ public class TextFieldAutocompleter { dual.setVisible(true); - AutocompletionModel model = new AutocompletionModel() { + AutocompletionModel model = new AutocompletionModel<>() { Set strings = new HashSet<>(Arrays.asList(new String[] { "Test", "Testing", "Another", "Yet another", "Yet still more", "Yet still even more", "Yetis, yo" })); @@ -1110,7 +1115,7 @@ public class TextFieldAutocompleter { return matching; } }; - TextFieldAutocompleter auto = new TextFieldAutocompleter(model) { + TextFieldAutocompleter auto = new TextFieldAutocompleter<>(model) { @Override protected String getPrefix(JTextField field) { return dual.getTextBeforeCursor(field); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/conditiontestpanel/ConditionTestPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/conditiontestpanel/ConditionTestPanel.java index b3d0966fc9..b11a64651d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/conditiontestpanel/ConditionTestPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/conditiontestpanel/ConditionTestPanel.java @@ -30,17 +30,21 @@ import docking.widgets.EmptyBorderButton; import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GDHtmlLabel; import docking.widgets.label.GDLabel; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.util.HTMLUtilities; import ghidra.util.exception.CancelledException; import ghidra.util.layout.PairLayout; import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitorComponent; -import resources.ResourceManager; +import resources.Icons; public class ConditionTestPanel extends JPanel { - static final Icon ERROR_ICON = ResourceManager.loadImage("images/edit-delete.png"); - static final Icon WARNING_ICON = ResourceManager.loadImage("images/dialog-warning.png"); - static final Icon PASSED_ICON = ResourceManager.loadImage("images/checkmark_green.gif"); + + private static final GIcon RUN_ICON = new GIcon("icon.run"); + static final Icon ERROR_ICON = Icons.ERROR_ICON; + static final Icon WARNING_ICON = Icons.WARNING_ICON; + static final Icon PASSED_ICON = new GIcon("icon.checkmark.green"); private ConditionTestModel conditionTestModel; private TaskMonitorComponent taskMonitor; private List testPanelList = new ArrayList<>(); @@ -121,12 +125,12 @@ public class ConditionTestPanel extends JPanel { private void updateOverallProgress() { overallProgressBar.setMaxProgress(conditionTestModel.getTestCount()); overallProgressBar.setProgress(conditionTestModel.getCompletedTestCount()); - Color color = Color.GREEN; + Color color = Palette.GREEN; if (conditionTestModel.getErrorCount() > 0) { - color = Color.RED; + color = Palette.RED; } else if (conditionTestModel.getWarningCount() > 0) { - color = Color.YELLOW; + color = Palette.YELLOW; } overallProgressBar.setColor(color); } @@ -190,7 +194,7 @@ public class ConditionTestPanel extends JPanel { private Component createRunAndSummaryPanel() { JPanel panel = new JPanel(new BorderLayout()); - JButton runButton = new EmptyBorderButton(ResourceManager.loadImage("images/play.png")); + JButton runButton = new EmptyBorderButton(RUN_ICON); runButton.addActionListener(e -> conditionTestModel.runTests(taskMonitor)); JPanel buttonPanel = new JPanel(new BorderLayout()); buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 0)); @@ -261,7 +265,7 @@ public class ConditionTestPanel extends JPanel { ConditionTestPanel ctPanel = new ConditionTestPanel(list); frame.getContentPane().add(ctPanel); frame.pack(); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setVisible(true); } @@ -364,7 +368,7 @@ public class ConditionTestPanel extends JPanel { public TestPanel(ConditionTester conditionTest) { super(new PairLayout()); backgroundColor = getBackground(); - selectedColor = Color.LIGHT_GRAY; + selectedColor = Palette.LIGHT_GRAY; this.test = conditionTest; checkbox = new GCheckBox(); checkbox.setSelected(true); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java index da402f4c5d..b7bfb1848e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/MultiLineInputDialog.java @@ -25,6 +25,7 @@ import docking.DialogComponentProvider; import docking.DockingUtils; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.framework.OperatingSystem; import ghidra.framework.Platform; @@ -87,7 +88,7 @@ public class MultiLineInputDialog extends DialogComponentProvider { Font smallerFont = font.deriveFont(12F); Font smallItalicFont = smallerFont.deriveFont(Font.ITALIC); hintLabel.setFont(smallItalicFont); - hintLabel.setForeground(Color.LIGHT_GRAY); + hintLabel.setForeground(Messages.HINT); dataPanel.add(messageLabel, BorderLayout.NORTH); dataPanel.add(new JScrollPane(inputTextArea), BorderLayout.CENTER); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java index 4d17046b8e..3bb62a7ff5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java @@ -15,7 +15,7 @@ */ package docking.widgets.fieldpanel; -import static docking.widgets.EventTrigger.INTERNAL_ONLY; +import static docking.widgets.EventTrigger.*; import java.awt.*; import java.awt.event.*; @@ -38,8 +38,9 @@ import docking.widgets.fieldpanel.listener.*; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexScrollListener; import docking.widgets.indexedscrollpane.IndexedScrollable; -import ghidra.util.Msg; -import ghidra.util.SystemUtilities; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Messages; +import ghidra.util.*; public class FieldPanel extends JPanel implements IndexedScrollable, LayoutModelListener, ChangeListener { @@ -51,7 +52,7 @@ public class FieldPanel extends JPanel private boolean inFocus; protected BackgroundColorModel backgroundColorModel = - new DefaultBackgroundColorModel(Color.WHITE); + new DefaultBackgroundColorModel(new GColor("color.bg.fieldpanel")); protected PaintContext paintContext = new PaintContext(); private AnchoredLayoutHandler layoutHandler; @@ -415,7 +416,6 @@ public class FieldPanel extends JPanel */ public void setBackgroundColor(Color c) { backgroundColorModel.setDefaultBackgroundColor(c); - paintContext.setDefaultBackgroundColor(c); } public Color getBackgroundColor(BigInteger index) { @@ -1152,10 +1152,8 @@ public class FieldPanel extends JPanel } private Color blend(Color primary, Color secondary) { - int red = (primary.getRed() * 3 + secondary.getRed()) / 4; - int green = (primary.getGreen() * 3 + secondary.getGreen()) / 4; - int blue = (primary.getBlue() * 3 + secondary.getBlue()) / 4; - return new Color(red, green, blue); + + return ColorUtils.blend(primary, secondary, 0.75); } private void paintLayoutBackground(Graphics g, Rectangle rect, AnchoredLayout layout, @@ -1185,7 +1183,7 @@ public class FieldPanel extends JPanel Color defaultBackgroundColor = backgroundColorModel.getDefaultBackgroundColor(); g.setColor(defaultBackgroundColor); g.fillRect(r.x, layout.getYPos() - layout.getHeight(), r.width, layout.getHeight()); - g.setColor(Color.RED); + g.setColor(Messages.ERROR); GraphicsUtils.drawString(this, g, "Error Painting Field", r.x, layout.getYPos()); Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); } @@ -1238,8 +1236,7 @@ public class FieldPanel extends JPanel if (layout == null) { return null; } - Rectangle r = - layout.getCursorRect(location.fieldNum, location.row, location.col); + Rectangle r = layout.getCursorRect(location.fieldNum, location.row, location.col); return r.getLocation(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/EmptyTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/EmptyTextField.java index 0cbd444a36..a0d7006016 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/EmptyTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/EmptyTextField.java @@ -23,6 +23,7 @@ import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; import docking.widgets.fieldpanel.support.DefaultRowColLocation; import docking.widgets.fieldpanel.support.RowColLocation; +import generic.theme.GThemeDefaults.Colors.Palette; /** * A Text field that is blank. @@ -55,6 +56,7 @@ public class EmptyTextField implements Field { /** * Returns true if the cursor is allowed past the last character. This * field always returns false since there is no text. + * @returns true if the cursor is allowed past the last character */ public boolean isAllowCursorAtEnd() { return false; @@ -168,6 +170,7 @@ public class EmptyTextField implements Field { * @param color the new foreground color. */ public void setForeground(Color color) { + // cannot change foreground } /** @@ -178,7 +181,7 @@ public class EmptyTextField implements Field { * was called. */ public Color getForeground() { - return Color.WHITE; + return Palette.NO_COLOR; } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleImageField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleImageField.java index 6db617874d..beeec5dbe9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleImageField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleImageField.java @@ -17,20 +17,20 @@ package docking.widgets.fieldpanel.field; import java.awt.*; -import javax.swing.ImageIcon; -import javax.swing.JComponent; +import javax.swing.*; import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; import docking.widgets.fieldpanel.support.DefaultRowColLocation; import docking.widgets.fieldpanel.support.RowColLocation; +import resources.ResourceManager; /** * Field to display an image. */ public class SimpleImageField implements Field { - protected ImageIcon icon; + protected ImageIcon imageIon; protected FontMetrics metrics; protected int startX; protected int width; @@ -47,7 +47,7 @@ public class SimpleImageField implements Field { * @param startY the starting y coordinate of the field. * @param width the width of the field. */ - public SimpleImageField(ImageIcon icon, FontMetrics metrics, int startX, int startY, + public SimpleImageField(Icon icon, FontMetrics metrics, int startX, int startY, int width) { this(icon, metrics, startX, startY, width, false); } @@ -61,13 +61,13 @@ public class SimpleImageField implements Field { * @param width the width of the field. * @param center flag to center the image in the field. */ - public SimpleImageField(ImageIcon icon, FontMetrics metrics, int startX, int startY, int width, + public SimpleImageField(Icon icon, FontMetrics metrics, int startX, int startY, int width, boolean center) { this.heightAbove = metrics.getMaxAscent() + metrics.getLeading(); this.height = heightAbove + metrics.getMaxDescent(); - this.icon = icon; + this.imageIon = ResourceManager.getImageIcon(icon); this.metrics = metrics; this.startX = startX; this.width = width; @@ -161,7 +161,7 @@ public class SimpleImageField implements Field { @Override public int getPreferredWidth() { - return icon.getIconWidth(); + return imageIon.getIconWidth(); } @Override @@ -189,28 +189,28 @@ public class SimpleImageField implements Field { public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc, int rowHeight) { - if (icon == null) { + if (imageIon == null) { return; } - int tmpWidth = icon.getIconWidth(); - int tmpHeight = icon.getIconHeight(); + int tmpWidth = imageIon.getIconWidth(); + int tmpHeight = imageIon.getIconHeight(); int xoffset = 0; int yoffset = 0; // if we are centering the image, then compute the offsets // if (center) { - if (width > icon.getIconWidth()) { - xoffset = width / 2 - icon.getIconWidth() / 2; + if (width > imageIon.getIconWidth()) { + xoffset = width / 2 - imageIon.getIconWidth() / 2; } - if (height > icon.getIconHeight()) { - yoffset = height / 2 - icon.getIconHeight() / 2; + if (height > imageIon.getIconHeight()) { + yoffset = height / 2 - imageIon.getIconHeight() / 2; } } // check to make sure that we are not going to draw outside the - // max rectagle + // max rectangle // if (tmpWidth > width) { tmpWidth = width; @@ -221,8 +221,10 @@ public class SimpleImageField implements Field { // draw the image, scaling to fit inside specified rectangle // - g.drawImage(icon.getImage(), startX + xoffset, -heightAbove + yoffset, tmpWidth, tmpHeight, - icon.getImageObserver()); + + g.drawImage(imageIon.getImage(), startX + xoffset, -heightAbove + yoffset, tmpWidth, + tmpHeight, + null); if (cursorLoc != null) { g.setColor(context.getCursorColor()); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/StrutFieldElement.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/StrutFieldElement.java index 9cc3ad8838..b99aa51978 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/StrutFieldElement.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/StrutFieldElement.java @@ -21,6 +21,7 @@ import java.awt.Graphics; import javax.swing.JComponent; import docking.widgets.fieldpanel.support.RowColLocation; +import generic.theme.GThemeDefaults.Colors; /** * Used to force a clip to happen by using this field with space characters and size that far @@ -68,7 +69,7 @@ public class StrutFieldElement implements FieldElement { @Override public Color getColor(int charIndex) { - return Color.BLACK; + return Colors.FOREGROUND; } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/ColorRangeMap.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/ColorRangeMap.java index f3ffe7b8f9..37fc2d63ba 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/ColorRangeMap.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/ColorRangeMap.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +15,10 @@ */ package docking.widgets.fieldpanel.internal; -import ghidra.util.datastruct.*; - import java.awt.Color; +import ghidra.util.ColorUtils; +import ghidra.util.datastruct.*; public class ColorRangeMap { private RangeMap map; @@ -30,7 +29,7 @@ public class ColorRangeMap { public ColorRangeMap() { map = new RangeMap(); valueRange = map.getValueRange(0); - + } public void color(long start, long end, Color c) { @@ -38,14 +37,17 @@ public class ColorRangeMap { map.paintRange(start, end, colorValue); valueRange = map.getValueRange(0); } + public void clear(long start, long end) { map.paintRange(start, end, 0); valueRange = map.getValueRange(0); } + public void clear() { map.clear(); valueRange = map.getValueRange(0); } + public Color getColor(long index, Color defaultColor) { if (!valueRange.contains(index)) { valueRange = map.getValueRange(index); @@ -56,18 +58,20 @@ public class ColorRangeMap { } return getColor(valueRange.getValue()); } - private Color getColor(int colorValue) { - if (lastColorValue == colorValue) { + + private Color getColor(int rgba) { + if (lastColorValue == rgba) { return lastColor; } - lastColorValue = colorValue; - lastColor = new Color(colorValue); + lastColorValue = rgba; + lastColor = ColorUtils.getColor(rgba); return lastColor; } + public ColorRangeMap copy() { ColorRangeMap newMap = new ColorRangeMap(); IndexRangeIterator it = map.getIndexRangeIterator(-1); - while(it.hasNext()) { + while (it.hasNext()) { IndexRange ir = it.next(); int colorValue = map.getValue(ir.getStart()); newMap.map.paintRange(ir.getStart(), ir.getEnd(), colorValue); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/PaintContext.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/PaintContext.java index 04dd4c04b0..fb90b3ad23 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/PaintContext.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/PaintContext.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,18 +17,20 @@ package docking.widgets.fieldpanel.internal; import java.awt.Color; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.util.ColorUtils; + /** * Miscellaneous information needed by fields to paint. */ public class PaintContext { - private Color defaultBackground; private Color background; private Color foreground; private Color selectionColor; private Color highlightColor; private Color selectedHighlightColor; - private Color printColor; private Color cursorColor; private Color focusedCursorColor; @@ -43,20 +44,18 @@ public class PaintContext { * Create a new PaintContext with default color values. */ public PaintContext() { - defaultBackground = Color.white; - background = Color.white; - foreground = Color.black; - selectionColor = new Color(180, 255, 180); - highlightColor = new Color(255, 255, 150); - selectedHighlightColor = Color.green; - focusedCursorColor = Color.RED; + background = new GColor("color.bg.fieldpanel"); + foreground = new GColor("color.fg.fieldpanel"); + selectionColor = new GColor("color.bg.fieldpanel.selection"); + highlightColor = new GColor("color.bg.fieldpanel.highlight"); + selectedHighlightColor = new GColor("color.bg.fieldpanel.selection.and.highlight"); + focusedCursorColor = new GColor("color.cursor.focused"); + notFocusedCursorColor = new GColor("color.cursor.unfocused"); cursorColor = focusedCursorColor; - invisibleCursorColor = new Color(255, 0, 0, 1); - notFocusedCursorColor = Color.PINK; + invisibleCursorColor = Palette.NO_COLOR; } public PaintContext(PaintContext other) { - defaultBackground = other.defaultBackground; background = other.background; foreground = other.foreground; selectionColor = other.selectionColor; @@ -66,19 +65,11 @@ public class PaintContext { focusedCursorColor = other.focusedCursorColor; notFocusedCursorColor = other.notFocusedCursorColor; invisibleCursorColor = other.invisibleCursorColor; - printColor = other.printColor; - } - - /** - * Returns the current default background color setting that is used when - * there is no special background color or highlight or selection. - */ - public final Color getDefaultBackground() { - return defaultBackground; } /** * Returns the current background color setting. + * @return the current background color setting. */ public final Color getBackground() { return background; @@ -86,6 +77,7 @@ public class PaintContext { /** * Returns the current foreground color setting. + * @return the current foreground color setting. */ public final Color getForeground() { return foreground; @@ -93,27 +85,31 @@ public class PaintContext { /** * Returns the current selection color setting. + * @return the current selection color setting. */ public final Color getSelectionColor() { return selectionColor; } /** - * Returns the current selection color setting. + * Returns the current highlight color setting. + * @return the current highlight color setting. */ public final Color getHighlightColor() { return highlightColor; } /** - * Returns the current selection color setting. + * Returns the current selected highlight color setting. + * @return the current selected highlight color setting. */ public final Color getSelectedHighlightColor() { return selectedHighlightColor; } /** - * Returns the current cursor color setting. + * Returns the current cursor color. + * @return the current cursor color. */ public final Color getCursorColor() { return cursorColor; @@ -133,22 +129,8 @@ public class PaintContext { adjustSelectedHighlightColor(); } - public void setDefaultBackgroundColor(Color c) { - defaultBackground = c; - } - - /** - * Returns true if the current background color matches the default background color. - */ - public final boolean isDefaultBackground() { - return defaultBackground.equals(background); - } - private void adjustSelectedHighlightColor() { - int red = (selectionColor.getRed() + highlightColor.getRed()) / 2; - int green = (selectionColor.getGreen() + highlightColor.getGreen()) / 2; - int blue = (selectionColor.getBlue() + highlightColor.getBlue()) / 2; - selectedHighlightColor = new Color(red, green, blue); + selectedHighlightColor = ColorUtils.blend(selectionColor, highlightColor, 0.5); } public void setBackgroundColor(Color c) { @@ -161,7 +143,7 @@ public class PaintContext { public void setCursorColor(Color c) { cursorColor = c; - invisibleCursorColor = new Color(c.getRed(), c.getGreen(), c.getBlue(), 1); + invisibleCursorColor = Palette.NO_COLOR; } public boolean cursorHidden() { @@ -192,10 +174,6 @@ public class PaintContext { return notFocusedCursorColor; } - public void setPrintColor(Color c) { - printColor = c; - } - public void setPrinting(boolean b) { printing = b; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java index c2655a40eb..07c8b8bb92 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java @@ -28,12 +28,13 @@ import docking.widgets.fieldpanel.listener.IndexMapper; import docking.widgets.fieldpanel.listener.LayoutModelListener; import docking.widgets.fieldpanel.support.*; import docking.widgets.indexedscrollpane.IndexedScrollPane; +import generic.theme.GThemeDefaults.Colors; public class TestBigLayoutModel implements LayoutModel { private static final Highlight[] NO_HIGHLIGHTS = new Highlight[0]; private static final HighlightFactory hlFactory = (field, text, cursorTextOffset) -> NO_HIGHLIGHTS; - ArrayList listeners = new ArrayList(); + ArrayList listeners = new ArrayList<>(); FontMetrics fm; // BigInteger numIndexes = BigInteger.valueOf(1000000000000000L); @@ -83,9 +84,10 @@ public class TestBigLayoutModel implements LayoutModel { } String text = name + ": This is line " + index + " More text to make line longer abcdefghijklmnopqrstuvwxyzabcdefghijk"; - FieldElement fe1 = new TextFieldElement(new AttributedString(text, Color.BLACK, fm), 0, 0); + FieldElement fe1 = + new TextFieldElement(new AttributedString(text, Colors.FOREGROUND, fm), 0, 0); FieldElement fe2 = - new TextFieldElement(new AttributedString("More text", Color.BLACK, fm), 0, 0); + new TextFieldElement(new AttributedString("More text", Colors.FOREGROUND, fm), 0, 0); SingleRowLayout layout = new SingleRowLayout(new ClippingTextField(20, 300, fe1, hlFactory), new ClippingTextField(330, 100, fe2, hlFactory)); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java index 31023aa684..470b915ebb 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java @@ -31,6 +31,8 @@ import docking.widgets.AutoLookup; import docking.widgets.label.GDLabel; import docking.widgets.list.GList; import docking.widgets.list.GListAutoLookup; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.util.exception.AssertException; class DirectoryList extends GList implements GhidraFileChooserDirectoryModelIf { @@ -184,12 +186,12 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod }); listEditor = new JPanel(new BorderLayout()); - listEditor.setBorder(BorderFactory.createLineBorder(Color.GRAY)); + listEditor.setBorder(BorderFactory.createLineBorder(Java.BORDER)); listEditor.add(listEditorLabel, BorderLayout.WEST); listEditor.add(listEditorField, BorderLayout.CENTER); - listEditor.setBackground(Color.WHITE); + listEditor.setBackground(Colors.BACKGROUND); listEditorField.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); add(listEditor); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileChooserToggleButton.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileChooserToggleButton.java index f6ffbd1f08..243b6a1d34 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileChooserToggleButton.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileChooserToggleButton.java @@ -15,7 +15,6 @@ */ package docking.widgets.filechooser; -import java.awt.Color; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; @@ -23,58 +22,56 @@ import java.io.File; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; + +import generic.theme.GThemeDefaults.Colors; public class FileChooserToggleButton extends JToggleButton { private static final long serialVersionUID = 1L; - static final Border RAISED_BORDER = BorderFactory.createCompoundBorder( - BorderFactory.createRaisedBevelBorder(), - BorderFactory.createEmptyBorder(1,1,1,1)); + static final Border RAISED_BORDER = BorderFactory.createCompoundBorder( + BorderFactory.createRaisedBevelBorder(), + BorderFactory.createEmptyBorder(1, 1, 1, 1)); - static final Border NO_BORDER = new EmptyBorder(RAISED_BORDER.getBorderInsets(new JButton())); + static final Border NO_BORDER = new EmptyBorder(RAISED_BORDER.getBorderInsets(new JButton())); - static final Border LOWERED_BORDER = BorderFactory.createCompoundBorder( - BorderFactory.createLoweredBevelBorder(), - BorderFactory.createEmptyBorder(1,1,1,1)); + static final Border LOWERED_BORDER = BorderFactory.createCompoundBorder( + BorderFactory.createLoweredBevelBorder(), + BorderFactory.createEmptyBorder(1, 1, 1, 1)); public FileChooserToggleButton(String text) { super(text); initBorder(); } - + public FileChooserToggleButton(Action action) { super(action); initBorder(); } private void initBorder() { - setForeground(Color.WHITE); - setOpaque(true); + setForeground(Colors.BACKGROUND); + setOpaque(true); setHorizontalTextPosition(SwingConstants.CENTER); setVerticalTextPosition(SwingConstants.BOTTOM); - clearBorder(); - + clearBorder(); + // prevents the WinXP LNF from painting its awkward borders - setContentAreaFilled( false ); - + setContentAreaFilled(false); + // changes the border on hover and click addMouseListener(new ButtonMouseListener()); - + // works in conjunction with the mouse listener to properly set the border - addChangeListener( new ChangeListener() { - public void stateChanged( ChangeEvent e ) { - if ( isSelected() ) { - setBorder( LOWERED_BORDER ); - } - else { - setBorder( NO_BORDER ); - } - } - } ); - - setFocusable( false ); // this prevents the focus box from being drawn over the button + addChangeListener(e -> { + if (isSelected()) { + setBorder(LOWERED_BORDER); + } + else { + setBorder(NO_BORDER); + } + }); + + setFocusable(false); // this prevents the focus box from being drawn over the button } void clearBorder() { @@ -83,52 +80,52 @@ public class FileChooserToggleButton extends JToggleButton { /** Returns the directory with which this button is associated. */ File getFile() { - return null; + return null; } private class ButtonMouseListener extends MouseAdapter { private boolean inside = false; private Border defaultBorder; - + @Override - public void mouseEntered(MouseEvent me) { - if ( isSelected() ) { - return; - } - - defaultBorder = getBorder(); + public void mouseEntered(MouseEvent me) { + if (isSelected()) { + return; + } + + defaultBorder = getBorder(); setBorder(RAISED_BORDER); inside = true; } @Override - public void mouseExited(MouseEvent me) { - if ( isSelected() ) { - return; - } - + public void mouseExited(MouseEvent me) { + if (isSelected()) { + return; + } + inside = false; restoreBorder(); } @Override - public void mousePressed(MouseEvent e) { - if ( isSelected() ) { - return; - } - + public void mousePressed(MouseEvent e) { + if (isSelected()) { + return; + } + if (e.getButton() == MouseEvent.BUTTON1) { setBorder(LOWERED_BORDER); } } @Override - public void mouseReleased(MouseEvent e) { - if ( isSelected() ) { - return; - } - + public void mouseReleased(MouseEvent e) { + if (isSelected()) { + return; + } + if (inside) { setBorder(RAISED_BORDER); } @@ -136,14 +133,14 @@ public class FileChooserToggleButton extends JToggleButton { restoreBorder(); } } - - private void restoreBorder() { - if ( defaultBorder != null ) { - setBorder(defaultBorder); - } - else { - setBorder( NO_BORDER ); - } - } - } + + private void restoreBorder() { + if (defaultBorder != null) { + setBorder(defaultBorder); + } + else { + setBorder(NO_BORDER); + } + } + } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java index 7675176475..4914f6594b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java @@ -24,6 +24,7 @@ import javax.swing.event.ChangeEvent; import javax.swing.table.TableCellEditor; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Java; import ghidra.util.Msg; import ghidra.util.filechooser.GhidraFileChooserModel; @@ -100,12 +101,7 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor { // make sure the name field gets the focus, not the container @Override public void requestFocus() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - nameField.requestFocus(); - } - }); + SwingUtilities.invokeLater(() -> nameField.requestFocus()); } }; @@ -115,7 +111,7 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor { // match the spacing of non-editing cells editor.setBorder( BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0), - BorderFactory.createLineBorder(Color.GRAY))); + BorderFactory.createLineBorder(Java.BORDER))); } private void handleDoubleClick(Point p) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java index f38f9d0c3c..9a30edb1de 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java @@ -15,17 +15,16 @@ */ package docking.widgets.filechooser; +import java.awt.*; +import java.awt.event.*; +import java.io.File; +import java.io.FileFilter; import java.util.*; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.awt.*; -import java.awt.event.*; -import java.io.File; -import java.io.FileFilter; - import javax.swing.*; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; @@ -37,8 +36,8 @@ import docking.widgets.combobox.GComboBox; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; import docking.widgets.list.GListCellRenderer; -import ghidra.framework.OperatingSystem; -import ghidra.framework.Platform; +import generic.theme.GColor; +import generic.theme.GIcon; import ghidra.framework.preferences.Preferences; import ghidra.util.*; import ghidra.util.exception.AssertException; @@ -49,8 +48,7 @@ import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.TaskMonitor; import ghidra.util.worker.Job; import ghidra.util.worker.Worker; -import resources.*; -import resources.icons.TranslateIcon; +import resources.Icons; import util.CollectionUtils; import util.HistoryList; @@ -73,8 +71,10 @@ import util.HistoryList; public class GhidraFileChooser extends DialogComponentProvider implements FileFilter { static final String UP_BUTTON_NAME = "UP_BUTTON"; - private static final Color FOREROUND_COLOR = Color.BLACK; - private static final Color BACKGROUND_COLOR = Color.WHITE; + private static final Color FOREROUND_COLOR = new GColor("color.fg.filechooser"); + private static final Color BACKGROUND_COLOR = new GColor("color.bg.filechooser"); + private static final Color SHORTCUT_BACKGROUND_COLOR = + new GColor("color.bg.filechooser.shortcut"); static final String PREFERENCES_PREFIX = "G_FILE_CHOOSER"; private static final String WIDTH_PREFERENCE_PREFIX = PREFERENCES_PREFIX + ".WIDTH."; private static final String HEIGHT_PREFERENCE_PREFIX = PREFERENCES_PREFIX + ".HEIGHT."; @@ -94,37 +94,20 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi private static final int PAD = 5; - private static Icon refreshIcon = Icons.REFRESH_ICON; - private static Icon backIcon = ResourceManager.loadImage("images/left.png"); - private static Icon forwardIcon = ResourceManager.loadImage("images/right.png"); - private static Icon detailsIcon = ResourceManager.loadImage("images/table.png"); - private static Icon optionsIcon = ResourceManager.loadImage("images/document-properties.png"); - private static Icon newFolderIcon = null; - private static Icon upIcon = null; - static { - if (Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS || - Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.LINUX) { + private static final Icon ICON_BACK = new GIcon("icon.left"); + private static final Icon ICON_FORWARD = new GIcon("icon.right"); + private static final Icon ICON_UP = new GIcon("icon.up"); + private static final Icon ICON_DETAILS = new GIcon("icon.table"); + private static final Icon ICON_OPTIONS = new GIcon("icon.properties"); + private static final Icon ICON_NEW_FOLDER = new GIcon("icon.folder.new"); - newFolderIcon = getIcon("FileChooser.newFolderIcon"); - upIcon = getIcon("FileChooser.upFolderIcon"); - } - if (newFolderIcon == null) { - newFolderIcon = ResourceManager.loadImage("images/folder_add.png"); - } - if (upIcon == null) { - upIcon = ResourceManager.loadImage("images/up.png"); - } - } + // 32 pixel side-bar icons + private static final Icon ICON_MY_COMPUTER = new GIcon("icon.filechooser.places.my.computer"); + private static final Icon ICON_DESKTOP = new GIcon("icon.filechooser.places.desktop"); + private static final Icon ICON_HOME = new GIcon("icon.filechooser.places.home"); + private static final Icon ICON_RECENT = new GIcon("icon.filechooser.places.recent"); - private static Icon getIcon(String iconName) { - try { - return UIManager.getIcon(iconName); - } - catch (Exception e) { - // we tried; just return null - } - return null; - } + // base and overlay? /** Instruction to display only files. */ public static final int FILES_ONLY = 0; @@ -308,7 +291,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi } }; myComputerButton.setName("MY_COMPUTER_BUTTON"); - myComputerButton.setIcon(ResourceManager.loadImage("images/computer.png")); + myComputerButton.setIcon(ICON_MY_COMPUTER); myComputerButton.addActionListener(e -> updateMyComputer()); myComputerButton.setForeground(FOREROUND_COLOR); @@ -319,7 +302,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi } }; desktopButton.setName("DESKTOP_BUTTON"); - desktopButton.setIcon(ResourceManager.loadImage("images/desktop.png")); + desktopButton.setIcon(ICON_DESKTOP); desktopButton.addActionListener(e -> updateDesktop()); desktopButton.setForeground(FOREROUND_COLOR); desktopButton.setEnabled(fileChooserModel.getDesktopDirectory() != null); @@ -331,7 +314,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi } }; homeButton.setName("HOME_BUTTON"); - homeButton.setIcon(ResourceManager.loadImage("images/user-home.png")); + homeButton.setIcon(ICON_HOME); homeButton.addActionListener(e -> updateHome()); homeButton.setForeground(FOREROUND_COLOR); @@ -342,12 +325,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi } }; recentButton.setName("RECENT_BUTTON"); - Icon baseIcon = ResourceManager.loadImage("images/inode-directory.png"); - Icon overlayIcon = ResourceManager.loadImage("images/edit-undo.png"); - MultiIcon multiIcon = new MultiIcon(baseIcon); - multiIcon.addIcon(new TranslateIcon(overlayIcon, 6, 10)); - - recentButton.setIcon(multiIcon); + recentButton.setIcon(ICON_RECENT); recentButton.addActionListener(e -> updateRecent()); recentButton.setForeground(FOREROUND_COLOR); @@ -366,7 +344,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(BorderFactory.createLoweredBevelBorder()); - panel.setBackground(BACKGROUND_COLOR.darker()); + panel.setBackground(SHORTCUT_BACKGROUND_COLOR); panel.add(shortCutPanel, BorderLayout.NORTH); return panel; } @@ -500,19 +478,19 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi } private JButton[] buildNavigationButtons() { - backButton = new EmptyBorderButton(backIcon); + backButton = new EmptyBorderButton(ICON_BACK); backButton.setName("BACK_BUTTON"); backButton.setEnabled(false); backButton.setToolTipText("Go to last folder visited"); backButton.addActionListener(e -> goBack()); - forwardButton = new EmptyBorderButton(forwardIcon); + forwardButton = new EmptyBorderButton(ICON_FORWARD); forwardButton.setName("FORWARD_BUTTON"); forwardButton.setEnabled(false); forwardButton.setToolTipText("Go to previous folder visited"); forwardButton.addActionListener(e -> goForward()); - upLevelButton = new EmptyBorderButton(upIcon); + upLevelButton = new EmptyBorderButton(ICON_UP); upLevelButton.setName(UP_BUTTON_NAME); upLevelButton.setToolTipText("Up one level"); upLevelButton.addActionListener(e -> goUpOneDirectoryLevel()); @@ -522,17 +500,17 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi private JButton[] buildNonNavigationButtons() { - newFolderButton = new EmptyBorderButton(newFolderIcon); + newFolderButton = new EmptyBorderButton(ICON_NEW_FOLDER); newFolderButton.setName("NEW_BUTTON"); newFolderButton.setToolTipText("Create new folder"); newFolderButton.addActionListener(e -> createNewFolder()); - refreshButton = new EmptyBorderButton(refreshIcon); + refreshButton = new EmptyBorderButton(Icons.REFRESH_ICON); refreshButton.setName("REFRESH_BUTTON"); refreshButton.setToolTipText("Rescan current directory"); refreshButton.addActionListener(e -> rescanCurrentDirectory()); - detailsButton = new EmptyBorderToggleButton(detailsIcon); + detailsButton = new EmptyBorderToggleButton(ICON_DETAILS); detailsButton.setName("DETAILS_BUTTON"); detailsButton.setToolTipText("Show details"); detailsButton.addActionListener(e -> { @@ -540,7 +518,7 @@ public class GhidraFileChooser extends DialogComponentProvider implements FileFi doSetShowDetails(!showDetails); }); - optionsButton = new EmptyBorderButton(optionsIcon); + optionsButton = new EmptyBorderButton(ICON_OPTIONS); optionsButton.setName("OPTIONS_BUTTON"); optionsButton.setToolTipText("File Chooser Options"); optionsButton.addActionListener(e -> { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java index 7399a6c139..aca78d5940 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java @@ -15,19 +15,18 @@ */ package docking.widgets.filechooser; +import java.io.File; +import java.io.FileFilter; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; -import java.io.File; -import java.io.FileFilter; - import javax.swing.Icon; -import javax.swing.ImageIcon; import javax.swing.filechooser.FileSystemView; +import generic.theme.GIcon; import ghidra.util.filechooser.GhidraFileChooserModel; -import resources.ResourceManager; +import resources.Icons; import utility.function.Callback; /** @@ -35,10 +34,8 @@ import utility.function.Callback; * */ public class LocalFileChooserModel implements GhidraFileChooserModel { - private static final ImageIcon PROBLEM_FILE_ICON = - ResourceManager.loadImage("images/unknown.gif"); - private static final ImageIcon PENDING_ROOT_ICON = - ResourceManager.loadImage("images/famfamfam_silk_icons_v013/drive.png"); + private static final Icon PROBLEM_FILE_ICON = Icons.WARNING_ICON; + private static final Icon PENDING_ROOT_ICON = new GIcon("icon.drive"); private static final FileSystemRootInfo FS_ROOT_INFO = new FileSystemRootInfo(); private static final FileSystemView FS_VIEW = FileSystemView.getFileSystemView(); @@ -160,8 +157,9 @@ public class LocalFileChooserModel implements GhidraFileChooserModel { return src.renameTo(dest); } - //--------------------------------------------------------------------------------------------- - +//================================================================================================= +// Inner Classes +//================================================================================================= /** * Handles querying / caching information about file system root locations. *

diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterOptions.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterOptions.java index ac2bf6a943..20191a8af7 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterOptions.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterOptions.java @@ -23,16 +23,16 @@ import javax.swing.Icon; import org.jdom.Element; +import generic.theme.GIcon; import resources.MultiIcon; -import resources.ResourceManager; import resources.icons.TranslateIcon; public class FilterOptions { - private static final Icon CONTAINS_ICON = ResourceManager.loadImage("images/page_code.png"); - private static final Icon STARTS_WITH_ICON = ResourceManager.loadImage("images/page_go.png"); - private static final Icon EXACT_MATCH_ICON = ResourceManager.loadImage("images/page_green.png"); - private static final Icon REG_EX_ICON = ResourceManager.loadImage("images/page_excel.png"); - private static final Icon NOT_ICON = ResourceManager.loadImage("images/bullet_delete.png"); + private static final Icon CONTAINS_ICON = new GIcon("icon.filter.options.contains"); + private static final Icon STARTS_WITH_ICON = new GIcon("icon.filter.options.starts.with"); + private static final Icon EXACT_MATCH_ICON = new GIcon("icon.filter.options.exact"); + private static final Icon REG_EX_ICON = new GIcon("icon.filter.options.regex"); + private static final Icon NOT_ICON = new GIcon("icon.filter.options.not"); final static Map DELIMITER_NAME_MAP = new HashMap<>(20); @@ -325,8 +325,13 @@ public class FilterOptions { char delim = getDelimitingCharacter(); String delimName = DELIMITER_NAME_MAP.get(delim); - buf.append("'").append(delim).append("'").append("  (").append( - delimName).append(")"); + buf.append("'") + .append(delim) + .append("'") + .append("  (") + .append( + delimName) + .append(")"); buf.append(""); buf.append(""); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java index e6ad4df80d..8749b021c0 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java @@ -23,6 +23,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import docking.DockingUtils; +import generic.theme.GColor; import ghidra.util.SystemUtilities; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; @@ -42,11 +43,14 @@ public class FilterTextField extends JPanel { private static final long MINIMUM_TIME_BETWEEN_FLASHES_MS = 5000; private static final int FLASH_FREQUENCY_MS = 250; - private static Color FLASH_BACKGROUND_COLOR = Color.WHITE; - private static Color FILTERED_BACKGROUND_COLOR = Color.YELLOW; - /*package*/ static Color UNEDITABLE_BACKGROUND_COLOR = Color.LIGHT_GRAY; + private static Color FLASH_FOREGROUND_COLOR = new GColor("color.fg"); + private static Color FILTERED_BACKGROUND_COLOR = new GColor("color.bg.filterfield"); + private static Color FILTERED_FOREGROUND_COLOR = new GColor("color.fg.filterfield"); - private Color noFlashColor; + /*package*/ static Color UNEDITABLE_BACKGROUND_COLOR = new GColor("color.bg.uneditable"); + + private Color noFlashBgColor; + private Color noFlashFgColor; /** Signals the last flash time (used to prevent excessive flashing) */ private long lastFlashTime = 0; @@ -153,11 +157,18 @@ public class FilterTextField extends JPanel { flashTimer.restart(); } - private Color getDefaultBackgroundColor() { - if (noFlashColor == null) { - noFlashColor = textField.getBackground(); // lazy init to default bg color + private Color getDefaultBgColor() { + if (noFlashBgColor == null) { + noFlashBgColor = textField.getBackground(); // lazy init to default bg color } - return noFlashColor; + return noFlashBgColor; + } + + private Color getDefaultFgColor() { + if (noFlashFgColor == null) { + noFlashFgColor = textField.getForeground(); // lazy init to default fg color + } + return noFlashFgColor; } /** @@ -209,28 +220,36 @@ public class FilterTextField extends JPanel { public void setEditable(boolean b) { textField.setEditable(b); - updateBackgroundColor(); + updateColor(); } - private void updateBackgroundColor() { + private void updateColor() { // this is purposely done here (before the isEditable() check below) in order to make // sure that the default color has been properly initialized - Color defaultBackgroundColor = getDefaultBackgroundColor(); + Color defaultBackgroundColor = getDefaultBgColor(); + Color defaultFgColor = getDefaultFgColor(); Color bgColor = UNEDITABLE_BACKGROUND_COLOR; + Color fgColor = getDefaultFgColor(); if (isEditable() && isEnabled()) { bgColor = hasText ? FILTERED_BACKGROUND_COLOR : defaultBackgroundColor; + fgColor = hasText ? FILTERED_FOREGROUND_COLOR : defaultFgColor; } doSetBackground(bgColor); + doSetForeground(fgColor); } - private void contrastBackground() { - Color contrastColor = FLASH_BACKGROUND_COLOR; - if (textField.getBackground() == FLASH_BACKGROUND_COLOR) { - contrastColor = FILTERED_BACKGROUND_COLOR; + private void contrastColors() { + Color contrastBg = noFlashBgColor; + Color contrastFg = FLASH_FOREGROUND_COLOR; + if (textField.getBackground() == noFlashBgColor) { + contrastBg = FILTERED_BACKGROUND_COLOR; + contrastFg = FILTERED_FOREGROUND_COLOR; } - doSetBackground(contrastColor); + + doSetBackground(contrastBg); + doSetForeground(contrastFg); } public String getText() { @@ -307,6 +326,10 @@ public class FilterTextField extends JPanel { textField.setBackground(c); } + /*package*/ void doSetForeground(Color c) { + textField.setForeground(c); + } + /*package*/ JLabel getClearLabel() { return clearLabel; } @@ -333,7 +356,7 @@ public class FilterTextField extends JPanel { updateFocusFlashing(); - updateBackgroundColor(); + updateColor(); if (fireEvent) { fireFilterChanged(text); @@ -434,7 +457,7 @@ public class FilterTextField extends JPanel { @Override public void actionPerformed(ActionEvent event) { if (flashCount < MAX_FLASH_COUNT) { - contrastBackground(); + contrastColors(); flashCount++; } else { @@ -452,7 +475,7 @@ public class FilterTextField extends JPanel { @Override public void stop() { super.stop(); - updateBackgroundColor(); // set to the proper non-flashing color + updateColor(); // set to the proper non-flashing color flashCount = 0; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ResetTranslationAction.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ResetTranslationAction.java index beaf8911e9..a2627efdd5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ResetTranslationAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ResetTranslationAction.java @@ -15,20 +15,20 @@ */ package docking.widgets.imagepanel.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.MenuData; import docking.action.ToolBarData; import docking.widgets.imagepanel.ImagePanel; -import resources.ResourceManager; +import generic.theme.GIcon; /** * An action to re-center the image on a NavigableImagePanel. */ public class ResetTranslationAction extends ImagePanelDockingAction { - private static final ImageIcon RECENTER_ICON = ResourceManager.loadImage("images/tag.png"); + private static final Icon RECENTER_ICON = new GIcon("icon.widget.imagepanel.reset"); public ResetTranslationAction(String owner, ImagePanel imagePanel) { super("Recenter", owner, imagePanel); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java index 0dbd110bc1..1dd5f15769 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/SaveImageAction.java @@ -30,7 +30,7 @@ import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.imagepanel.ImagePanel; import generic.util.image.ImageUtils; import ghidra.util.Msg; -import resources.ResourceManager; +import resources.Icons; /** * An action to save the image from a NavigableImagePanel to a file. @@ -51,7 +51,7 @@ public class SaveImageAction extends ImagePanelDockingAction { super("Export Image", owner, imagePanel); setPopupMenuData(new MenuData(new String[] { "Export Image As..." }, "io")); - setToolBarData(new ToolBarData(ResourceManager.loadImage("images/disk_save_as.png"))); + setToolBarData(new ToolBarData(Icons.SAVE_AS_ICON)); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomInAction.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomInAction.java index 3b6cc11014..17a0f0e16c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomInAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomInAction.java @@ -15,27 +15,27 @@ */ package docking.widgets.imagepanel.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.MenuData; import docking.action.ToolBarData; import docking.widgets.imagepanel.ImagePanel; -import resources.ResourceManager; +import generic.theme.GIcon; /** * An action to zoom the image on a NavigableImagePanel. */ public class ZoomInAction extends ImagePanelDockingAction { - private static final ImageIcon ZOOM_IN_ICON = ResourceManager.loadImage("images/zoom_in.png"); + private static final Icon ICON = new GIcon("icon.widget.imagepanel.zoom.in"); public ZoomInAction(String owner, ImagePanel imagePanel) { super("Zoom In", owner, imagePanel); setPopupMenuData(new MenuData(new String[] { "Zoom in" }, "view")); - setToolBarData(new ToolBarData(ZOOM_IN_ICON)); + setToolBarData(new ToolBarData(ICON)); } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomOutAction.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomOutAction.java index 3a1d7194c7..303648a033 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomOutAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomOutAction.java @@ -15,20 +15,20 @@ */ package docking.widgets.imagepanel.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.MenuData; import docking.action.ToolBarData; import docking.widgets.imagepanel.ImagePanel; -import resources.ResourceManager; +import generic.theme.GIcon; /** * An action to de-zoom the image on a NavigableImagePanel. */ public class ZoomOutAction extends ImagePanelDockingAction { - private static final ImageIcon ZOOM_OUT_ICON = ResourceManager.loadImage("images/zoom_out.png"); + private static final Icon ZOOM_OUT_ICON = new GIcon("icon.widget.imagepanel.zoom.out"); public ZoomOutAction(String owner, ImagePanel imagePanel) { super("Zoom Out", owner, imagePanel); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomResetAction.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomResetAction.java index 69c6675788..9996e49c24 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomResetAction.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/imagepanel/actions/ZoomResetAction.java @@ -15,19 +15,19 @@ */ package docking.widgets.imagepanel.actions; -import javax.swing.ImageIcon; +import javax.swing.Icon; import docking.ActionContext; import docking.action.ToolBarData; import docking.widgets.imagepanel.ImagePanel; -import resources.ResourceManager; +import generic.theme.GIcon; /** * An action to reset the zoom of a NavigableImagePanel. */ public class ZoomResetAction extends ImagePanelDockingAction { - private static final ImageIcon ZOOM_ICON = ResourceManager.loadImage("images/zoom.png"); + private static final Icon ZOOM_ICON = new GIcon("icon.widget.imagepanel.reset"); public ZoomResetAction(String owner, ImagePanel imagePanel) { super("Reset Zoom", owner, imagePanel); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java index 5b62739d92..3052b152d6 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/GListCellRenderer.java @@ -22,6 +22,7 @@ import java.util.function.Function; import javax.swing.*; import docking.widgets.AbstractGCellRenderer; +import generic.theme.GThemeDefaults.Colors.Palette; /** * Provides a common implementation of a list renderer, for use in both JList and JComboBox. @@ -94,7 +95,7 @@ public class GListCellRenderer extends AbstractGCellRenderer implements ListC dropLocation.getIndex() == index); // @formatter:on if (isDropRow) { - setBackground(Color.CYAN); + setBackground(Palette.CYAN); } else { setBackground(getOSDependentBackgroundColor(list, index)); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java index d4a79ab86e..3e0735d353 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/list/ListPanel.java @@ -56,10 +56,9 @@ public class ListPanel extends JPanel { scrollpane = new JScrollPane(list); - // the next two lines of code cause the scroll bar not to - // work properly - //list.setBorder(emptyborder); - //scrollpane.setBorder(compoundborder); + // the next two lines of code cause the scroll bar not to work properly + // list.setBorder(emptyborder); + // scrollpane.setBorder(compoundborder); add(scrollpane, BorderLayout.CENTER); @@ -108,14 +107,15 @@ public class ListPanel extends JPanel { /** * Returns true if no list items are selected. + * @return true if no list items are selected. */ public boolean isSelectionEmpty() { return list.isSelectionEmpty(); } /** - * Returns the first selected value in the list or null if nothing - * is selected. + * Returns the first selected value in the list or null if nothing is selected. + * @return the first selected value in the list or null if nothing is selected. */ public Object getSelectedValue() { return list.getSelectedValue(); @@ -123,6 +123,7 @@ public class ListPanel extends JPanel { /** * Get the index of the selected item in the list. + * @return the index of the selected item in the list. */ public int getSelectedIndex() { return list.getSelectedIndex(); @@ -146,6 +147,7 @@ public class ListPanel extends JPanel { /** * Returns an array of all the selected items. + * @return an array of all the selected items. */ public Object[] getSelectedValues() { return list.getSelectedValues(); @@ -160,12 +162,16 @@ public class ListPanel extends JPanel { list.clearSelection(); } + /** + * Sets the list data + * @param data the data + */ public void setListData(Object[] data) { list.setListData(data); } /** - * Sets a ListModel for the internal Jlist to use. + * Sets a list model for the internal list to use. * @param listModel the list model to use. */ public void setListModel(ListModel listModel) { @@ -175,6 +181,7 @@ public class ListPanel extends JPanel { /** * Get the list model for the list. + * @return the list model for the list. */ public ListModel getListModel() { return (list.getModel()); @@ -182,6 +189,7 @@ public class ListPanel extends JPanel { /** * Return the JList component. + * @return the JList component. */ public JList getList() { return list; @@ -201,10 +209,12 @@ public class ListPanel extends JPanel { * means no one is to be notified. */ public void setListSelectionListener(ListSelectionListener listener) { - if (listSelectionListener != null) + if (listSelectionListener != null) { list.removeListSelectionListener(listSelectionListener); - if (listener != null) + } + if (listener != null) { list.addListSelectionListener(listener); + } listSelectionListener = listener; } @@ -236,7 +246,8 @@ public class ListPanel extends JPanel { * in the list. */ public void issueWarning() { - JOptionPane.showMessageDialog(null, DEFAULT_WARNING, "Warning", JOptionPane.WARNING_MESSAGE); + JOptionPane.showMessageDialog(null, DEFAULT_WARNING, "Warning", + JOptionPane.WARNING_MESSAGE); } /** diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java index 08761ababf..609e234a28 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java @@ -29,12 +29,13 @@ import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.table.*; import generic.jar.ResourceFile; +import generic.theme.GThemeDefaults.Colors.Tables; import generic.util.Path; import ghidra.framework.options.SaveState; import ghidra.framework.preferences.Preferences; import ghidra.util.filechooser.GhidraFileChooserModel; import ghidra.util.filechooser.GhidraFileFilter; -import resources.ResourceManager; +import resources.Icons; /** * Component that has a table to show pathnames; the panel includes buttons to control @@ -52,7 +53,6 @@ public class PathManager { private JButton downButton; private JButton addButton; private JButton removeButton; - private Color selectionColor; private GhidraFileChooser fileChooser; private String preferenceForLastSelectedDir = Preferences.LAST_IMPORT_DIRECTORY; private String title = "Select File"; @@ -102,8 +102,8 @@ public class PathManager { /** * Add a new file path and set its enablement - * @param file - * @param enabled + * @param file the file whose path to use + * @param enabled true if enabled * @return true if the enabled path did not already exist */ public boolean addPath(ResourceFile file, boolean enabled) { @@ -127,9 +127,6 @@ public class PathManager { return true; } - /** - * Set the paths. - */ public void setPaths(List paths) { pathModel.setPaths(paths); } @@ -164,29 +161,27 @@ public class PathManager { private void create(List paths) { panel = new JPanel(new BorderLayout(5, 5)); - selectionColor = new Color(204, 204, 255); - if (allowOrdering) { - upButton = new JButton(ResourceManager.loadImage("images/up.png")); + upButton = new JButton(Icons.UP_ICON); upButton.setName("UpArrow"); upButton.setToolTipText("Move the selected path up in list"); upButton.addActionListener(e -> up()); upButton.setFocusable(false); - downButton = new JButton(ResourceManager.loadImage("images/down.png")); + downButton = new JButton(Icons.DOWN_ICON); downButton.setName("DownArrow"); downButton.setToolTipText("Move the selected path down in list"); downButton.addActionListener(e -> down()); downButton.setFocusable(false); } - addButton = new JButton(ResourceManager.loadImage("images/Plus.png")); + addButton = new JButton(Icons.ADD_ICON); addButton.setName("AddPath"); addButton.setToolTipText("Display file chooser to select files to add"); addButton.addActionListener(e -> add()); addButton.setFocusable(false); - removeButton = new JButton(ResourceManager.loadImage("images/edit-delete.png")); + removeButton = new JButton(Icons.DELETE_ICON); removeButton.setName("RemovePath"); removeButton.setToolTipText("Remove selected path(s) from list"); removeButton.addActionListener(e -> remove()); @@ -215,8 +210,6 @@ public class PathManager { pathTable = new GTable(pathModel); pathTable.setName("PATH_TABLE"); - pathTable.setSelectionBackground(selectionColor); - pathTable.setSelectionForeground(Color.BLACK); pathTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); //make the 'enabled' column very skinny... @@ -240,7 +233,8 @@ public class PathManager { if (column == PathManagerModel.COLUMN_PATH) { Path path = (Path) value; if (!isValidPath(path)) { - renderer.setForeground(Color.RED); + renderer.setForeground(data.isSelected() ? Tables.FG_ERROR_SELECTED + : Tables.FG_ERROR_UNSELECTED); } } return renderer; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java index 97ad8a24f5..f2702d5f91 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathnameTablePanel.java @@ -27,10 +27,12 @@ import docking.widgets.OptionDialog; import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.table.*; +import generic.theme.GIcon; +import generic.theme.GThemeDefaults.Colors.Tables; import ghidra.framework.preferences.Preferences; import ghidra.util.filechooser.GhidraFileChooserModel; import ghidra.util.filechooser.GhidraFileFilter; -import resources.ResourceManager; +import resources.Icons; import utility.function.Callback; /** @@ -38,14 +40,10 @@ import utility.function.Callback; * the order of the paths, and to add and remove paths. The add button brings up a * file chooser. Call the setFileChooser() method to control how the file chooser should * behave. If the table entries should not be edited, call setEditingEnabled(false). - * - * - * */ public class PathnameTablePanel extends JPanel { - private static final long serialVersionUID = 1L; - private static final Icon RESET_ICON = ResourceManager.loadImage("images/trash-empty.png"); + private static final Icon RESET_ICON = new GIcon("icon.widget.pathmanager.reset"); private JTable pathnameTable; private PathnameTableModel tableModel; @@ -54,7 +52,6 @@ public class PathnameTablePanel extends JPanel { private JButton addButton; private JButton removeButton; private JButton resetButton; - private Color selectionColor; private GhidraFileChooser fileChooser; private String preferenceForLastSelectedDir = Preferences.LAST_IMPORT_DIRECTORY; private String title = "Select File"; @@ -134,9 +131,6 @@ public class PathnameTablePanel extends JPanel { this.addToTop = addToTop; } - /** - * Return paths in the table. - */ public String[] getPaths() { String[] paths = new String[tableModel.getRowCount()]; for (int i = 0; i < paths.length; i++) { @@ -145,16 +139,10 @@ public class PathnameTablePanel extends JPanel { return paths; } - /** - * Set the paths. - */ public void setPaths(String[] paths) { tableModel.setPaths(paths); } - /** - * Get the table in this path name panel. - */ public JTable getTable() { return pathnameTable; } @@ -168,21 +156,20 @@ public class PathnameTablePanel extends JPanel { } private void create() { - selectionColor = new Color(204, 204, 255); - upButton = new JButton(ResourceManager.loadImage("images/up.png")); + upButton = new JButton(Icons.UP_ICON); upButton.setName("UpArrow"); upButton.setToolTipText("Move the selected path up in list"); upButton.addActionListener(e -> up()); - downButton = new JButton(ResourceManager.loadImage("images/down.png")); + downButton = new JButton(Icons.DOWN_ICON); downButton.setName("DownArrow"); downButton.setToolTipText("Move the selected path down in list"); downButton.addActionListener(e -> down()); - addButton = new JButton(ResourceManager.loadImage("images/Plus.png")); + addButton = new JButton(Icons.ADD_ICON); addButton.setName("AddPath"); addButton.setToolTipText("Display file chooser to select files to add"); addButton.addActionListener(e -> add()); - removeButton = new JButton(ResourceManager.loadImage("images/edit-delete.png")); + removeButton = new JButton(Icons.DELETE_ICON); removeButton.setName("RemovePath"); removeButton.setToolTipText("Remove selected path(s) from list"); removeButton.addActionListener(e -> remove()); @@ -222,8 +209,6 @@ public class PathnameTablePanel extends JPanel { pathnameTable.setShowGrid(false); pathnameTable.setPreferredScrollableViewportSize(new Dimension(330, 200)); - pathnameTable.setSelectionBackground(selectionColor); - pathnameTable.setSelectionForeground(Color.BLACK); pathnameTable.setTableHeader(null); pathnameTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); JScrollPane scrollPane = new JScrollPane(pathnameTable); @@ -265,10 +250,7 @@ public class PathnameTablePanel extends JPanel { public Component getTableCellRendererComponent(GTableCellRenderingData data) { JLabel label = (JLabel) super.getTableCellRendererComponent(data); - - JTable table = data.getTable(); Object value = data.getValue(); - boolean isSelected = data.isSelected(); String pathName = (String) value; @@ -282,8 +264,10 @@ public class PathnameTablePanel extends JPanel { } label.setText(pathName.toString()); - Color fg = isSelected ? table.getSelectionForeground() : table.getForeground(); - label.setForeground(!fileExists ? Color.RED : fg); + if (!fileExists) { + label.setForeground(data.isSelected() ? Tables.FG_ERROR_SELECTED + : Tables.FG_ERROR_UNSELECTED); + } return label; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tabbedpane/DockingTabRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tabbedpane/DockingTabRenderer.java index f17ad35135..82b564489d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tabbedpane/DockingTabRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tabbedpane/DockingTabRenderer.java @@ -20,9 +20,10 @@ import java.awt.event.*; import javax.swing.*; +import docking.CloseIcon; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GDLabel; -import resources.ResourceManager; +import generic.theme.GColor; /** * A widget that can be used to render an icon, title and close button for JTabbedPane. You would @@ -31,10 +32,7 @@ import resources.ResourceManager; public class DockingTabRenderer extends JPanel { private static final int MAX_TITLE_LENGTH = 25; - private Icon EMPTY_ICON = - ResourceManager.getScaledIcon(ResourceManager.loadImage("images/close16.gif"), 8, 8); - private Icon CLOSE_ICON = - ResourceManager.getScaledIcon(ResourceManager.loadImage("images/close16.gif"), 8, 8); + private Icon CLOSE_ICON = new CloseIcon(true, new GColor("color.fg.button")); private JLabel titleLabel; private JLabel iconLabel; @@ -56,9 +54,9 @@ public class DockingTabRenderer extends JPanel { setTitle(tabTitle, fullTitle); closeButton.setToolTipText("Close " + tabTitle); - closeButton.setIcon(EMPTY_ICON); // no icon until we rollover the tab closeButton.setFocusable(false); closeButton.addActionListener(closeListener); + closeButton.setIcon(CLOSE_ICON); closeButton.setRolloverIcon(CLOSE_ICON); JPanel container = new JPanel(); @@ -84,20 +82,10 @@ public class DockingTabRenderer extends JPanel { titleLabel.addMouseListener(eventForwardingListener); titleLabel.addMouseMotionListener(eventForwardingListener); - // listeners to know when to hide our close button (from the tabbed pane) - final ButtonIconSwapperMouseListener iconListener = - new ButtonIconSwapperMouseListener(tabbedPane); - installIconListener(container, tabbedPane, iconListener); - - // listeners to know when to hide our close button (from this panel) - addMouseListener(iconListener); - addMouseMotionListener(iconListener); - - installMouseForwardingListenerWorkaround(tabbedPane, iconListener); + installMouseForwardingListenerWorkaround(tabbedPane); } - private void installMouseForwardingListenerWorkaround(final JTabbedPane tabbedPane, - final ButtonIconSwapperMouseListener iconListener) { + private void installMouseForwardingListenerWorkaround(final JTabbedPane tabbedPane) { forwardingListener = new TabContainerForwardingMouseListener(tabbedPane); @@ -114,20 +102,14 @@ public class DockingTabRenderer extends JPanel { boolean isDisplayable = isDisplayable(); if (isDisplayable) { // remove and add in order to prevent duplicate adding - myParent.removeMouseListener(iconListener); - myParent.removeMouseMotionListener(iconListener); myParent.removeMouseListener(forwardingListener); myParent.removeMouseMotionListener(forwardingListener); - myParent.addMouseListener(iconListener); - myParent.addMouseMotionListener(iconListener); myParent.addMouseListener(forwardingListener); myParent.addMouseMotionListener(forwardingListener); hierarchyListener = this; } else if (hierarchyListener != null) { - myParent.removeMouseListener(iconListener); - myParent.removeMouseMotionListener(iconListener); myParent.removeMouseListener(forwardingListener); myParent.removeMouseMotionListener(forwardingListener); @@ -145,20 +127,6 @@ public class DockingTabRenderer extends JPanel { return title; } - // add listeners to the tabbed pane so that the icon for closing appears (and disappears) as - // needed - private void installIconListener(Container container, JTabbedPane tabbedPane, - ButtonIconSwapperMouseListener iconListener) { - Component[] components = container.getComponents(); - for (Component component : components) { - component.addMouseListener(iconListener); - } - - tabbedPane.addMouseListener(iconListener); - // we need this due to the gaps between the renderer and the tabbed pane - tabbedPane.addMouseMotionListener(iconListener); - } - public void installRenameAction(MouseListener listener) { this.renameListener = listener; } @@ -193,57 +161,6 @@ public class DockingTabRenderer extends JPanel { // Inner Classes //================================================================================================== - /** - * A class to hide/show the close button's icon to make it appear that the button is hidden - * and removed. - */ - private class ButtonIconSwapperMouseListener extends MouseAdapter { - - private final JTabbedPane tabbedPane; - - ButtonIconSwapperMouseListener(JTabbedPane tabbedPane) { - this.tabbedPane = tabbedPane; - } - - private void updateButton(MouseEvent e) { - Point point = e.getPoint(); - Point tabbedPaneRelativePoint = - SwingUtilities.convertPoint(e.getComponent(), point, tabbedPane); - int x = tabbedPaneRelativePoint.x; - int y = tabbedPaneRelativePoint.y; - int tabIndex = tabbedPane.indexAtLocation(x, y); - if (tabIndex < 0) { - // no tab for the given point (can happen when over the tabbed pane, but not - // over any tab) - closeButton.setIcon(EMPTY_ICON); - return; - } - - Component tabComponent = tabbedPane.getTabComponentAt(tabIndex); - if (SwingUtilities.isDescendingFrom(closeButton, tabComponent)) { - closeButton.setIcon(CLOSE_ICON); - } - else { - closeButton.setIcon(EMPTY_ICON); - } - } - - @Override - public void mouseMoved(MouseEvent e) { - updateButton(e); - } - - @Override - public void mouseEntered(MouseEvent e) { - updateButton(e); - } - - @Override - public void mouseExited(MouseEvent e) { - closeButton.setIcon(EMPTY_ICON); - } - } - /** * A class designed to listen for mouse events on this renderer component which it will then * forward on to the given component. diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java index 49c52d80fd..6791b12215 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java @@ -201,4 +201,18 @@ public class GFilterTable extends JPanel { public void setFiterText(String text) { filterPanel.setFilterText(text); } + + public int getRow(Point point) { + return table.rowAtPoint(point); + } + + public int getColumn(Point point) { + return table.columnAtPoint(point); + } + + public Object getCellValue(Point point) { + int row = getRow(point); + int col = getColumn(point); + return table.getValueAt(row, col); + } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java index 5f30524cb5..904735753a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java @@ -38,11 +38,12 @@ import docking.widgets.AutoLookup; import docking.widgets.OptionDialog; import docking.widgets.dialogs.SettingsDialog; import docking.widgets.filechooser.GhidraFileChooser; +import generic.theme.GIcon; import ghidra.docking.settings.*; import ghidra.framework.preferences.Preferences; import ghidra.util.*; import ghidra.util.exception.AssertException; -import resources.ResourceManager; +import resources.Icons; /** * A sub-class of JTable that provides navigation and auto-lookup. @@ -74,6 +75,7 @@ import resources.ResourceManager; */ public class GTable extends JTable { + private static final GIcon ICON_SPREADSHEET = new GIcon("icon.spreadsheet"); private static final KeyStroke COPY_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C, CONTROL_KEY_MODIFIER_MASK); private static final KeyStroke COPY_COLUMN_KEY_STROKE = @@ -1279,7 +1281,7 @@ public class GTable extends JTable { //@formatter:off copyAction.setPopupMenuData(new MenuData( new String[] { "Copy", "Copy" }, - ResourceManager.loadImage("images/page_white_copy.png"), + Icons.COPY_ICON, actionMenuGroup, NO_MNEMONIC, Integer.toString(subGroupIndex++) ) @@ -1300,7 +1302,7 @@ public class GTable extends JTable { copyCurrentColumnAction.setPopupMenuData(new MenuData( new String[] { "Copy", "Copy Current Column" }, - ResourceManager.loadImage("images/page_white_copy.png"), + Icons.COPY_ICON, actionMenuGroup, NO_MNEMONIC, Integer.toString(subGroupIndex++) @@ -1320,7 +1322,7 @@ public class GTable extends JTable { //@formatter:off copyColumnsAction.setPopupMenuData(new MenuData( new String[] { "Copy", "Copy Columns..." }, - ResourceManager.loadImage("images/page_white_copy.png"), + Icons.COPY_ICON, actionMenuGroup, NO_MNEMONIC, Integer.toString(subGroupIndex++) @@ -1339,7 +1341,7 @@ public class GTable extends JTable { //@formatter:off exportAction.setPopupMenuData(new MenuData( new String[] { "Export", GTableToCSV.TITLE + "..." }, - ResourceManager.loadImage("images/application-vnd.oasis.opendocument.spreadsheet-template.png"), + ICON_SPREADSHEET, actionMenuGroup, NO_MNEMONIC, Integer.toString(subGroupIndex++) @@ -1359,7 +1361,7 @@ public class GTable extends JTable { //@formatter:off exportColumnsAction.setPopupMenuData(new MenuData( new String[] { "Export", "Export Columns to CSV..." }, - ResourceManager.loadImage("images/application-vnd.oasis.opendocument.spreadsheet-template.png"), + ICON_SPREADSHEET, actionMenuGroup, NO_MNEMONIC, Integer.toString(subGroupIndex++) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java index 53331bade1..19f3339b70 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableCellRenderer.java @@ -28,6 +28,8 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableModel; import docking.widgets.AbstractGCellRenderer; +import generic.theme.GColor; +import generic.theme.Gui; import ghidra.docking.settings.*; import ghidra.util.*; import ghidra.util.exception.AssertException; @@ -47,6 +49,8 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe protected static final FloatingPointPrecisionSettingsDefinition FLOATING_POINT_PRECISION_SETTING = FloatingPointPrecisionSettingsDefinition.DEF; + private static final Color BG_DRAG = new GColor("color.bg.table.row.drag"); + private static DecimalFormat decimalFormat; private static Map decimalFormatCache; @@ -54,7 +58,13 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe * Constructs a new GTableCellRenderer. */ public GTableCellRenderer() { - + // When the Look And Feel changes, renderers are not auto updated because they + // are not part of the component tree. So listen for a change to the Look And Feel. + Gui.addThemeListener(e -> { + if (e.isLookAndFeelChanged()) { + updateUI(); + } + }); } /** @@ -155,7 +165,7 @@ public class GTableCellRenderer extends AbstractGCellRenderer implements TableCe setForegroundColor(table, model, value); if (row == dropRow) { - setBackground(Color.CYAN); + setBackground(BG_DRAG); } else { setBackground(getOSDependentBackgroundColor(table, row)); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java index 6839eaa01f..a230b8f752 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java @@ -37,6 +37,7 @@ import docking.widgets.label.GDLabel; import docking.widgets.table.columnfilter.ColumnBasedTableFilter; import docking.widgets.table.columnfilter.ColumnFilterSaveManager; import docking.widgets.table.constraint.dialog.ColumnFilterDialog; +import generic.theme.GIcon; import ghidra.framework.options.PreferenceState; import ghidra.util.HelpLocation; import ghidra.util.Msg; @@ -46,7 +47,6 @@ import ghidra.util.exception.AssertException; import ghidra.util.task.SwingUpdateManager; import help.HelpService; import resources.Icons; -import resources.ResourceManager; import utilities.util.reflection.ReflectionUtilities; import utility.function.Callback; @@ -112,8 +112,8 @@ public class GTableFilterPanel extends JPanel { public static final String FILTER_TEXTFIELD_NAME = "filter.panel.textfield"; private static final String FILTER_STATE = "FILTER_STATE"; private static final String FILTER_EXTENSION = ".FilterExtension"; - private static final Icon FILTER_ON_ICON = ResourceManager.loadImage("images/filter_on.png"); - private static final Icon FILTER_OFF_ICON = ResourceManager.loadImage("images/filter_off.png"); + private static final Icon FILTER_ON_ICON = new GIcon("icon.widget.filterpanel.filter.on"); + private static final Icon FILTER_OFF_ICON = new GIcon("icon.widget.filterpanel.filter.off"); private static final Icon APPLY_FILTER_ICON = Icons.OPEN_FOLDER_ICON; private static final Icon CLEAR_FILTER_ICON = Icons.DELETE_ICON; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java index e606960e1f..ef68cfe6f2 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java @@ -23,6 +23,7 @@ import javax.swing.table.*; import docking.DockingWindowManager; import docking.widgets.table.columnfilter.ColumnBasedTableFilter; +import generic.theme.GIcon; import ghidra.util.HTMLUtilities; import ghidra.util.HelpLocation; import help.HelpService; @@ -38,11 +39,11 @@ public class GTableHeader extends JTableHeader { /** This is the cursor used by BasicTableHeaderUI to tell the user they can resize a column */ private static final Cursor RESIZE_CURSOR = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR); - private static final int HELP_ICON_HEIGHT = 8; + public static final int HELP_ICON_HEIGHT = 8; private static final Icon HELP_ICON = ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/info_small.png"), HELP_ICON_HEIGHT, HELP_ICON_HEIGHT); + new GIcon("icon.widget.table.header.help"), HELP_ICON_HEIGHT, HELP_ICON_HEIGHT); private static final Icon HELP_HOVERED_ICON = - ResourceManager.getScaledIcon(ResourceManager.loadImage("images/info_small_hover.png"), + ResourceManager.getScaledIcon(new GIcon("icon.widget.table.header.help.hovered"), HELP_ICON_HEIGHT, HELP_ICON_HEIGHT); private final GTable gTable; @@ -206,7 +207,7 @@ public class GTableHeader extends JTableHeader { } if (columnFilterToolTip != null) { - ttBuilder.append("
Filters:


Filters: cellWidth) { return column.getHeaderValue().toString(); } - if (component instanceof GTableHeaderRenderer) { - GTableHeaderRenderer gthr = (GTableHeaderRenderer) component; - if (gthr.isTextOccluded()) { - return column.getHeaderValue().toString(); - } - } // handle the case where the user has specifically added a tooltip string if (component instanceof JComponent) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeaderRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeaderRenderer.java index 778efa2426..1e80335dff 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeaderRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeaderRenderer.java @@ -17,96 +17,151 @@ package docking.widgets.table; import java.awt.*; import java.awt.font.TextAttribute; -import java.awt.geom.Rectangle2D; import java.text.AttributedString; import javax.swing.*; -import javax.swing.border.*; +import javax.swing.border.Border; import javax.swing.table.*; -import docking.widgets.label.GDLabel; +import generic.theme.*; import resources.*; import resources.icons.EmptyIcon; import resources.icons.TranslateIcon; -/** - * The header renderer for GhidraTable. - * If the table model implements SortedTableModel, then - * an icon will be displayed in the header of the currently sorted - * column representing ascending and descending order. - */ -public class GTableHeaderRenderer extends JPanel implements TableCellRenderer { +public class GTableHeaderRenderer extends DefaultTableCellRenderer { + + private static final Color SORT_NUMBER_FG_COLOR = new GColor("color.fg"); + private static final int PADDING_FOR_COLUMN_NUMBER = 10; - - private static final Color PRIMARY_SORT_GRADIENT_START = new Color(205, 227, 244); - private static final Color PRIMARY_SORT_GRADIENT_END = new Color(126, 186, 233); - private static final Color DEFAULT_GRADIENT_START = Color.WHITE; - private static final Color DEFAULT_GRADIENT_END = new Color(215, 215, 215); - private static final Icon UP_ICON = ResourceManager.getScaledIcon(Icons.SORT_ASCENDING_ICON, 14, 14); private static final Icon DOWN_ICON = ResourceManager.getScaledIcon(Icons.SORT_DESCENDING_ICON, 14, 14); private static final int DEFAULT_MIN_HEIGHT = UP_ICON.getIconHeight(); + private static final Icon EMPTY_ICON = new EmptyIcon(0, 0); private static final Icon FILTER_ICON = - ResourceManager.getScaledIcon(ResourceManager.loadImage("images/filter_off.png"), 12, 12); + ResourceManager.getScaledIcon(new GIcon("icon.widget.filterpanel.filter.off"), 12, 12); - private JLabel textLabel = new GDLabel(); - private JLabel iconLabel = new GDLabel(); - private Icon helpIcon = null; - private CustomPaddingBorder customBorder; + private static final Icon PENDING_ICON = new GIcon("icon.widget.table.header.pending"); + + private Icon primaryIcon = EMPTY_ICON; + private Icon helpIcon = EMPTY_ICON; protected boolean isPaintingPrimarySortColumn; - public GTableHeaderRenderer() { - super(); + private TableCellRenderer delegate; - textLabel.setHorizontalTextPosition(SwingConstants.LEFT); - iconLabel.setHorizontalAlignment(SwingConstants.RIGHT); + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { - textLabel.setBorder(createOSSpecificBorder()); + JTableHeader header = table.getTableHeader(); + delegate = header.getDefaultRenderer(); - setLayout(new BorderLayout()); - add(textLabel, BorderLayout.CENTER); - add(iconLabel, BorderLayout.EAST); + Component rendererComponent = + delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - // controls spacing on multiple platforms - customBorder = new CustomPaddingBorder(); - setBorder(customBorder); + int modelIndex = table.convertColumnIndexToModel(column); + TableModel model = table.getModel(); + VariableColumnTableModel variableModel = VariableColumnTableModel.from(model); + if (variableModel != null) { + String text = variableModel.getColumnDisplayName(modelIndex); + if (rendererComponent instanceof JLabel) { + ((JLabel) rendererComponent).setText(text); + } + } + + primaryIcon = getIcon(model, modelIndex); + helpIcon = getHelpIcon(table, column); + + return this; } @Override - // overridden to paint our help icon over the other components - protected void paintChildren(Graphics g) { - super.paintChildren(g); - paintHelpIcon(g); + public void setBounds(int x, int y, int w, int h) { + super.setBounds(x, y, w, h); + ((Component) delegate).setBounds(x, y, w, h); } - private void paintHelpIcon(Graphics g) { - if (helpIcon == null) { - return; + @Override + public void paint(Graphics g) { + + JLabel label = (JLabel) delegate; + String text = label.getText(); + String clippedText = checkForClipping(label, text); + if (!text.equals(clippedText)) { + label.setText(clippedText); } - Point paintPoint = getHelpIconLocation(); - helpIcon.paintIcon(this, g, paintPoint.x, paintPoint.y); + label.paint(g); + + // paint our items after the delegate call so that we paint on top + super.paint(g); + } + + private String checkForClipping(JLabel label, String text) { + + Point helpPoint = getHelpIconLocation(); + int padding = 10; + int iconStartX = helpPoint.x - primaryIcon.getIconWidth() - padding; + + FontMetrics metrics = label.getFontMetrics(label.getFont()); + int horizontalAlignment = label.getHorizontalAlignment(); + Rectangle bounds = label.getBounds(); + int availableWidth = iconStartX + primaryIcon.getIconWidth(); + if (horizontalAlignment == CENTER) { + availableWidth = iconStartX - padding; + } + + String clippedText = SwingUtilities.layoutCompoundLabel( + label, + metrics, + text, + primaryIcon, + label.getVerticalAlignment(), + label.getHorizontalAlignment(), + label.getVerticalTextPosition(), + label.getHorizontalTextPosition(), + new Rectangle(0, 0, availableWidth, bounds.height), + new Rectangle(iconStartX, 0, primaryIcon.getIconWidth(), bounds.height), + new Rectangle(0, 0, iconStartX, bounds.height), + label.getIconTextGap()); + return clippedText; + } + + @Override + protected void paintChildren(Graphics g) { + + // The help icon paints at the end of the cell; place the main icon to the left of that + Point helpPoint = getHelpIconLocation(); + int offset = 4; + int x = helpPoint.x - primaryIcon.getIconWidth() - offset; + int y = getIconStartY(primaryIcon.getIconHeight()); + primaryIcon.paintIcon(this, g, x, y); + + helpIcon.paintIcon(this, g, helpPoint.x, helpPoint.y); } private Point getHelpIconLocation() { + + int right = getWidth(); + int offset = 2; + int helpIconWidth = GTableHeader.HELP_ICON_HEIGHT; + // we want the icon on the right-hand size of the header, at the top - int primaryWidth = iconLabel.getWidth(); - int overlayWidth = helpIcon.getIconWidth(); - - // this point is relative to the iconLabel... - Point paintPoint = new Point(primaryWidth - overlayWidth, 0); - - // ...make the point relative to the parent (this renderer) - return SwingUtilities.convertPoint(iconLabel, paintPoint, this); + int x = right - helpIconWidth - offset; + int y = offset; // down a bit + return new Point(x, y); } @Override // overridden to enforce a minimum height for the icon we use public Dimension getPreferredSize() { Dimension preferredSize = super.getPreferredSize(); + if (delegate != null) { + return ((Component) delegate).getPreferredSize(); + } + Border currentBorder = getBorder(); int minHeight = DEFAULT_MIN_HEIGHT; if (currentBorder != null) { @@ -117,47 +172,19 @@ public class GTableHeaderRenderer extends JPanel implements TableCellRenderer { return preferredSize; } - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, - boolean hasFocus, int row, int column) { - - isPaintingPrimarySortColumn = false; // reset - Icon icon = null; - String text = (value == null) ? "" : value.toString(); - - JTableHeader header = table.getTableHeader(); - setForeground(header.getForeground()); - setFont(header.getFont()); - - // remap the column index to the models column index - int modelIndex = table.convertColumnIndexToModel(column); - TableModel model = table.getModel(); - - icon = getIcon(model, modelIndex); - - VariableColumnTableModel variableModel = VariableColumnTableModel.from(model); - if (variableModel != null) { - text = variableModel.getColumnDisplayName(modelIndex); - } - updateHelpIcon(table, column, icon); - iconLabel.setIcon(icon); - textLabel.setText(text); - - setOuterBorder(customBorder, column); - - setOpaque(false); - return this; - } - private Icon getIcon(TableModel model, int columnModelIndex) { Icon icon = null; if (model instanceof SortedTableModel) { icon = getSortIcon(icon, columnModelIndex, model); } if (isColumnFiltered(model, columnModelIndex)) { - icon = combineIcons(icon, FILTER_ICON); + icon = combineIcons(FILTER_ICON, icon); } - return icon; + + if (icon != null) { + return icon; + } + return EMPTY_ICON; } private Icon combineIcons(Icon icon1, Icon icon2) { @@ -167,9 +194,16 @@ public class GTableHeaderRenderer extends JPanel implements TableCellRenderer { if (icon2 == null) { return icon1; } - MultiIcon icon = new MultiIcon(new EmptyIcon(28, 14)); - icon.addIcon(icon2); - icon.addIcon(new TranslateIcon(icon1, 14, 0)); + + int padding = 2; + int w1 = icon1.getIconWidth(); + int w2 = icon2.getIconWidth(); + int h1 = icon1.getIconHeight(); + int fullWidth = w1 + padding + w2; + MultiIcon icon = new MultiIcon(new EmptyIcon(fullWidth, h1)); + icon.addIcon(icon1); + int rightShift = w1 + padding; + icon.addIcon(new TranslateIcon(icon2, rightShift, 0)); return icon; } @@ -185,66 +219,26 @@ public class GTableHeaderRenderer extends JPanel implements TableCellRenderer { return tableFilter.hasColumnFilter(columnModelIndex); } - private void setOuterBorder(CustomPaddingBorder border, int column) { - if (paintAquaHeaders()) { - if (column == 0) { - customBorder.setOuterBorder(new NoSidesLineBorder(Color.GRAY)); - return; - } - customBorder.setOuterBorder(new NoRightSideLineBorder(Color.GRAY)); - } - else { - customBorder.setOuterBorder(UIManager.getBorder("TableHeader.cellBorder")); - } - } + private Icon getHelpIcon(JTable table, int currentColumnIndex) { - private boolean paintAquaHeaders() { - return true; - // For now we always use the custom --it actually makes the various LaFs look nicer - // return DockingWindowsLookAndFeelUtils.isUsingAquaUI(getUI()); - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - Paint backgroundColor = getBackgroundPaint(); - Paint oldPaint = g2d.getPaint(); - - g2d.setPaint(backgroundColor); - g2d.fillRect(0, 0, getWidth(), getHeight()); - - g2d.setPaint(oldPaint); - super.paintComponent(g); - } - - protected Paint getBackgroundPaint() { - if (isPaintingPrimarySortColumn) { - return new GradientPaint(0, 0, PRIMARY_SORT_GRADIENT_START, 0, getHeight() - 11, - PRIMARY_SORT_GRADIENT_END, true); - } - return new GradientPaint(0, 0, DEFAULT_GRADIENT_START, 0, getHeight() - 11, - DEFAULT_GRADIENT_END, true); - } - - private void updateHelpIcon(JTable table, int currentColumnIndex, Icon icon) { JTableHeader tableHeader = table.getTableHeader(); if (!(tableHeader instanceof GTableHeader)) { - helpIcon = null; - return; + return EMPTY_ICON; } GTableHeader tooltipTableHeader = (GTableHeader) tableHeader; int hoveredColumnIndex = tooltipTableHeader.getHoveredHeaderColumnIndex(); if (hoveredColumnIndex != currentColumnIndex) { - helpIcon = null; - return; + return EMPTY_ICON; } - helpIcon = tooltipTableHeader.getHelpIcon(); + Icon icon = tooltipTableHeader.getHelpIcon(); + if (icon != null) { + return icon; + } + return EMPTY_ICON; } - // checked before this method is called private Icon getSortIcon(Icon icon, int realIndex, TableModel model) { SortedTableModel sortedModel = (SortedTableModel) model; TableSortState columnSortStates = sortedModel.getTableSortState(); @@ -298,81 +292,41 @@ public class GTableHeaderRenderer extends JPanel implements TableCellRenderer { } if (isPendingSort) { - icon = ResourceManager.loadImage("images/hourglass.png"); + icon = PENDING_ICON; } return icon; } - /** - * Returns true if sorted in ascending order, false if descending. - * @return true if sorted in ascending order, false if descending - */ - public boolean isSortedAscending() { - return iconLabel.getIcon() == UP_ICON; - } + private int getIconStartY(int iconHeight) { - boolean isTextOccluded() { - return textLabel.getPreferredSize().getWidth() > textLabel.getWidth(); - } - - private Border createOSSpecificBorder() { - if (paintAquaHeaders()) { - return new EmptyBorder(1, 2, 1, 2); - } - return new EmptyBorder(0, 2, 0, 2); + int height = getHeight(); + int middle = height / 2; + int halfHeight = iconHeight / 2; + int y = middle - halfHeight; + return y; } //================================================================================================== // Inner Classes //================================================================================================== - private class CustomPaddingBorder extends CompoundBorder { - private CustomPaddingBorder() { - insideBorder = createOSSpecificBorder(); - } - - void setOuterBorder(Border border) { - outsideBorder = border; - } - } - - private class NoRightSideLineBorder extends LineBorder { - NoRightSideLineBorder(Color color) { - super(color); - } - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - // take advantage of our clipping by telling our parent to paint at a point that will - // be clipped - super.paintBorder(c, g, x, y, width + 1, height); - } - } - - private class NoSidesLineBorder extends LineBorder { - NoSidesLineBorder(Color color) { - super(color); - } - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - // take advantage of our clipping by telling our parent to paint at a point that will - // be clipped - super.paintBorder(c, g, x - 1, y, width + 5, height); - } - } - private class NumberPainterIcon implements Icon { + private static final String FONT_ID = "font.table.header.number"; private final int iconWidth; + private int numberWidth; private final int iconHeight; private final String numberText; public NumberPainterIcon(int width, int height, String numberText) { - iconWidth = width; - iconHeight = height; + this.iconWidth = width; + this.iconHeight = height; this.numberText = numberText; + + Font font = Gui.getFont(FONT_ID); + FontMetrics fontMetrics = getFontMetrics(font); + numberWidth = fontMetrics.stringWidth(numberText); } @Override @@ -382,35 +336,34 @@ public class GTableHeaderRenderer extends JPanel implements TableCellRenderer { @Override public int getIconWidth() { - return iconWidth; + return iconWidth + numberWidth; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { - int fontSize = 12; - String fontFamily = "arial"; - Font font = new Font(fontFamily, Font.BOLD, fontSize); + + Font font = Gui.getFont(FONT_ID); g.setFont(font); FontMetrics fontMetrics = g.getFontMetrics(); - Rectangle2D stringBounds = fontMetrics.getStringBounds(numberText, g); - int numberWidth = (int) stringBounds.getWidth(); int numberHeight = fontMetrics.getAscent(); - int insetPadding = 2; + int padding = 2; // draw the number on the right... - int startX = x + (iconWidth - numberWidth) - insetPadding; + int startX = x + (iconWidth - numberWidth) + padding; - // ...and in the upper portion - int textBaseline = numberHeight; + // ...and at the same start y as the sort icon + int iconY = getIconStartY(iconHeight); + int textBaseline = iconY + numberHeight - padding; AttributedString as = new AttributedString(numberText); - as.addAttribute(TextAttribute.FOREGROUND, Color.BLACK); + as.addAttribute(TextAttribute.FOREGROUND, SORT_NUMBER_FG_COLOR); as.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); - as.addAttribute(TextAttribute.FAMILY, fontFamily); - as.addAttribute(TextAttribute.SIZE, (float) fontSize); + as.addAttribute(TextAttribute.FAMILY, font.getFamily()); + as.addAttribute(TextAttribute.SIZE, font.getSize2D()); g.drawString(as.getIterator(), startX, textBaseline); + } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/SelectColumnsDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/SelectColumnsDialog.java index 81fdb60f37..0e971b22ad 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/SelectColumnsDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/SelectColumnsDialog.java @@ -23,9 +23,12 @@ import javax.swing.*; import javax.swing.table.*; import docking.DialogComponentProvider; +import generic.theme.GColor; import ghidra.util.HelpLocation; public class SelectColumnsDialog extends DialogComponentProvider { + + private static final Color BG_NON_DEFAULT = new GColor("color.fg.disabled"); private static final String DISCOVERED_TABLE_COLUMN_NAME = "Non-default"; private GTable ghidraTable; @@ -150,6 +153,7 @@ public class SelectColumnsDialog extends DialogComponentProvider { //================================================================================================== private class ColumnSelectorStringRenderer extends GTableCellRenderer { + @Override public Component getTableCellRendererComponent(GTableCellRenderingData data) { @@ -164,7 +168,7 @@ public class SelectColumnsDialog extends DialogComponentProvider { TableColumnWrapper tableColumnWrapper = columnList.get(row); if (!tableColumnWrapper.isDefault()) { - c.setBackground(c.getBackground().darker()); + c.setBackground(BG_NON_DEFAULT); c.setOpaque(true); } @@ -188,7 +192,7 @@ public class SelectColumnsDialog extends DialogComponentProvider { TableColumnWrapper tableColumnWrapper = columnList.get(row); if (!tableColumnWrapper.isDefault()) { - c.setBackground(c.getBackground().darker()); + c.setBackground(BG_NON_DEFAULT); c.setOpaque(true); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/TableUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/TableUtils.java index 8e21218f3e..4b17fc608c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/TableUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/TableUtils.java @@ -41,8 +41,7 @@ public class TableUtils { * @return the string value; null if no value can be fabricated */ public static String getTableCellStringValue(RowObjectTableModel model, - ROW_OBJECT rowObject, - int column) { + ROW_OBJECT rowObject, int column) { // note: this call can be slow when columns dynamically calculate values from the database Object value = model.getColumnValueForRow(rowObject, column); @@ -87,12 +86,13 @@ public class TableUtils { private static String getRenderedColumnValue(RowObjectTableModel model, Object columnValue, int columnIndex) { - if (!(model instanceof DynamicColumnTableModel)) { + TableModel unwrappedModel = RowObjectTableModel.unwrap(model); + if (!(unwrappedModel instanceof DynamicColumnTableModel)) { return null; } DynamicColumnTableModel columnBasedModel = - (DynamicColumnTableModel) model; + (DynamicColumnTableModel) unwrappedModel; GColumnRenderer renderer = getColumnRenderer(columnBasedModel, columnIndex); if (renderer == null) { return null; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnBasedTableFilter.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnBasedTableFilter.java index b3d50e341f..ed062d4222 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnBasedTableFilter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnBasedTableFilter.java @@ -23,6 +23,8 @@ import org.jdom.Element; import docking.widgets.table.*; import docking.widgets.table.constraint.ColumnConstraint; import docking.widgets.table.constraint.TableFilterContext; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.framework.options.SaveState; /** @@ -230,16 +232,19 @@ public class ColumnBasedTableFilter implements TableFilter { // private String getHtmlRepresentation(List> filters) { StringBuilder buf = new StringBuilder(); - buf.append(""); + buf.append("
"); buf.append(""); // The first row has an empty first column // so that additional rows can display an "AND" buf.append(""); + GColor gray = Palette.GRAY; + String grayHex = gray.toHexString(); for (int i = 1; i < filters.size(); i++) { - buf.append(""); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnConstraintSet.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnConstraintSet.java index 10bf9394b9..83beeb1d71 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnConstraintSet.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/columnfilter/ColumnConstraintSet.java @@ -22,6 +22,8 @@ import org.apache.commons.collections4.CollectionUtils; import docking.widgets.table.DiscoverableTableUtils; import docking.widgets.table.RowObjectTableModel; import docking.widgets.table.constraint.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.framework.options.SaveState; /** @@ -178,25 +180,30 @@ public class ColumnConstraintSet { * Returns an HTML representation of this constraint set in a tabular form. It will be used * inside the HTML representation of the entire filter. See {@link ColumnBasedTableFilter#getHtmlRepresentation()} * for a description of the table format. + * @return the html */ String getHtmlRepresentation() { - StringBuilder builder = new StringBuilder(); - builder.append("
"); buf.append(filters.get(0).getHtmlRepresentation()); buf.append("
" + filters.get(i).getLogicOperation() + - " "); + buf.append("
"); + buf.append(filters.get(i).getLogicOperation()); + buf.append(" "); buf.append(filters.get(i).getHtmlRepresentation()); buf.append("
"); - builder.append(""); - builder.append(""); + StringBuilder buf = new StringBuilder(); + buf.append("
"); - builder.append(model.getColumnName(columnIndex)); - builder.append(" "); - builder.append(""); - builder.append(getHtmlRepresentation(constraints.get(0))); - builder.append("
"); + buf.append(""); + buf.append(""); + + GColor gray = Palette.GRAY; + String grayHex = gray.toHexString(); for (int i = 1; i < constraints.size(); i++) { - builder.append(""); - builder.append(""); + buf.append(""); + buf.append(""); } - builder.append("
"); + buf.append(model.getColumnName(columnIndex)); + buf.append(" "); + buf.append(""); + buf.append(getHtmlRepresentation(constraints.get(0))); + buf.append("
or"); - builder.append(getHtmlRepresentation(constraints.get(i))); - builder.append("
or"); + buf.append(getHtmlRepresentation(constraints.get(i))); + buf.append("
"); - return builder.toString(); + buf.append(""); + return buf.toString(); } private String getHtmlRepresentation(ColumnConstraint columnConstraint) { @@ -209,7 +216,7 @@ public class ColumnConstraintSet { if (quoteValue) { buf.append("\""); } - buf.append(""); + buf.append(""); buf.append(columnConstraint.getConstraintValueString()); buf.append(""); if (quoteValue) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterArchiveDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterArchiveDialog.java index 48e3434878..c9de6cdf51 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterArchiveDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterArchiveDialog.java @@ -115,8 +115,8 @@ public class ColumnFilterArchiveDialog extends DialogComponentProvider { private JComponent buildFilterList() { JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(BorderFactory.createTitledBorder( - BorderFactory.createEmptyBorder(19, 0, 0, 5), "Filter Names")); + panel.setBorder(BorderFactory + .createTitledBorder(BorderFactory.createEmptyBorder(19, 0, 0, 5), "Filter Names")); jList = new JList<>(); jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -136,22 +136,22 @@ public class ColumnFilterArchiveDialog extends DialogComponentProvider { } private JComponent buildActionPanel() { - ImageIcon icon = Icons.DELETE_ICON; + Icon icon = Icons.DELETE_ICON; removeSelectedFiltersButton = new JButton("Remove", icon); removeSelectedFiltersButton.setEnabled(false); removeSelectedFiltersButton.addActionListener(e -> removeSelectedFilter()); - JPanel buttonPanel = new JPanel(new BorderLayout()); - buttonPanel.add(removeSelectedFiltersButton, BorderLayout.EAST); + JPanel panel = new JPanel(new BorderLayout()); + panel.add(removeSelectedFiltersButton, BorderLayout.EAST); - return buttonPanel; + return panel; } private Component buildPreviewPanel() { JPanel panel = new JPanel(new BorderLayout()); - panel.setBorder(BorderFactory.createTitledBorder( - BorderFactory.createEmptyBorder(19, 0, 26, 5), "Preview")); + panel.setBorder(BorderFactory + .createTitledBorder(BorderFactory.createEmptyBorder(19, 0, 26, 5), "Preview")); previewLabel = new GDHtmlLabel(); previewLabel.setVerticalAlignment(SwingConstants.TOP); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java index ec0d57c24e..82e9ad055b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialog.java @@ -33,11 +33,13 @@ import docking.widgets.table.GTableFilterPanel; import docking.widgets.table.RowObjectFilterModel; import docking.widgets.table.columnfilter.*; import docking.widgets.table.constrainteditor.ColumnConstraintEditor; +import generic.theme.GThemeDefaults.Colors.Java; +import generic.theme.GThemeDefaults.Colors.Messages; import generic.util.WindowUtilities; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.layout.VerticalLayout; -import resources.ResourceManager; +import resources.Icons; import utility.function.Callback; /** @@ -127,7 +129,7 @@ public class ColumnFilterDialog extends DialogComponentProvider }; saveAction.setHelpLocation(new HelpLocation("Trees", "Save_Filter")); saveAction.setDescription("Save Filter"); - saveAction.setToolBarData(new ToolBarData(ResourceManager.loadImage("images/disk.png"))); + saveAction.setToolBarData(new ToolBarData(Icons.SAVE_ICON)); addAction(saveAction); DockingAction loadAction = new DockingAction("Load", "Filter") { @@ -139,7 +141,7 @@ public class ColumnFilterDialog extends DialogComponentProvider loadAction.setDescription("Load Filter"); loadAction.setHelpLocation(new HelpLocation("Trees", "Load_Filter")); loadAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage("images/openSmallFolder.png"))); + new ToolBarData(Icons.OPEN_FOLDER_ICON)); addAction(loadAction); } @@ -222,13 +224,13 @@ public class ColumnFilterDialog extends DialogComponentProvider JPanel innerPanel = new JPanel(new VerticalLayout(3)); JButton addAndConditionButton = - new JButton("Add AND condition", ResourceManager.loadImage("images/Plus.png")); + new JButton("Add AND condition", Icons.ADD_ICON); addAndConditionButton.addActionListener(e -> addFilterCondition(LogicOperation.AND)); addAndConditionButton.setEnabled(true); JButton addOrConditionButton = - new JButton("Add OR condition", ResourceManager.loadImage("images/Plus.png")); + new JButton("Add OR condition", Icons.ADD_ICON); addOrConditionButton.setHorizontalAlignment(SwingConstants.LEFT); addOrConditionButton.addActionListener(e -> addFilterCondition(LogicOperation.OR)); @@ -369,7 +371,7 @@ public class ColumnFilterDialog extends DialogComponentProvider private GLabel createLogicalOperationLabel(LogicOperation op) { GLabel label = new GLabel("<" + op + ">", SwingConstants.CENTER); - label.setForeground(Color.GRAY); + label.setForeground(Messages.HINT); return label; } @@ -381,7 +383,7 @@ public class ColumnFilterDialog extends DialogComponentProvider headerPanel.add(new GLabel("Filter Value", SwingConstants.CENTER)); headerPanel.setBorder(new CompoundBorder( - BorderFactory.createMatteBorder(0, 0, 1, 0, Color.DARK_GRAY.brighter().brighter()), + BorderFactory.createMatteBorder(0, 0, 1, 0, Java.BORDER), BorderFactory.createEmptyBorder(4, 0, 4, 0))); return headerPanel; } @@ -475,5 +477,4 @@ public class ColumnFilterDialog extends DialogComponentProvider } - } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterPanel.java index 77369b4673..d3c1d067dc 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterPanel.java @@ -15,10 +15,9 @@ */ package docking.widgets.table.constraint.dialog; -import java.awt.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.*; import javax.swing.*; import javax.swing.border.BevelBorder; @@ -27,7 +26,9 @@ import docking.widgets.EmptyBorderButton; import docking.widgets.combobox.GhidraComboBox; import docking.widgets.label.GDLabel; import docking.widgets.list.GListCellRenderer; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.layout.VerticalLayout; +import resources.Icons; import resources.ResourceManager; /** @@ -55,7 +56,7 @@ class ColumnFilterPanel extends JPanel { private Component buildButtonPanel() { JPanel panel = new JPanel(new BorderLayout()); - ImageIcon icon = ResourceManager.loadImage("images/Plus.png"); + Icon icon = Icons.ADD_ICON; icon = ResourceManager.getScaledIcon(icon, BUTTON_ICON_SIZE, BUTTON_ICON_SIZE); JButton button = new EmptyBorderButton(icon); @@ -116,7 +117,7 @@ class ColumnFilterPanel extends JPanel { private Component createOrLabel() { JLabel jLabel = new GDLabel("", SwingConstants.CENTER); - jLabel.setForeground(Color.GRAY); + jLabel.setForeground(Messages.HINT); return jLabel; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ConstraintFilterPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ConstraintFilterPanel.java index f663af52a8..175433bbe8 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ConstraintFilterPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ConstraintFilterPanel.java @@ -93,7 +93,7 @@ public class ConstraintFilterPanel extends JPanel { private Component buildButtonPanel() { JPanel panel = new JPanel(new BorderLayout()); - ImageIcon icon = Icons.DELETE_ICON; + Icon icon = Icons.DELETE_ICON; JButton button = new EmptyBorderButton(icon); button.setToolTipText("Delete entry"); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java index 0b2052ffdc..3edcdd670c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AbstractColumnConstraintEditor.java @@ -18,11 +18,12 @@ package docking.widgets.table.constrainteditor; import java.awt.Color; import java.awt.Component; -import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import docking.widgets.table.constraint.ColumnConstraint; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.util.HTMLUtilities; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; @@ -43,9 +44,9 @@ public abstract class AbstractColumnConstraintEditor implements ColumnConstra private boolean validEditorValue = false; /** Color indicating a valid value is defined by the editor widget(s) */ - protected static final Color VALID_INPUT_COLOR = UIManager.getColor("TextField.background"); + protected static final Color VALID_INPUT_COLOR = Colors.BACKGROUND; /** Color indicating a invalid value is defined by the editor widget(s) */ - protected static final Color INVALID_INPUT_COLOR = new Color(255, 0, 51, 40); + protected static final Color INVALID_INPUT_COLOR = new GColor("docking.palette.mistyrose"); /** * Constructor. @@ -206,7 +207,7 @@ public abstract class AbstractColumnConstraintEditor implements ColumnConstra * @return an HTML string suitable for a JLabel. */ protected final static String formatStatus(String message, boolean error) { - Color color = error ? Color.RED : Color.BLACK; + Color color = error ? Colors.ERROR : Colors.FOREGROUND; String messageWithFont = HTMLUtilities.setFont(message, color, 12); String html = HTMLUtilities.wrapAsHTML(messageWithFont); return html; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java index 16ecd266be..fdf607b482 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/AutocompletingStringConstraintEditor.java @@ -31,6 +31,7 @@ import docking.widgets.DropDownTextField; import docking.widgets.DropDownTextFieldDataModel; import docking.widgets.list.GListCellRenderer; import docking.widgets.table.constraint.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.util.HTMLUtilities; /** @@ -214,7 +215,7 @@ public class AutocompletingStringConstraintEditor extends DataLoadingConstraintE private String formatListValue(String value, boolean isSelected) { Matcher matcher = model.lastConstraint.getHighlightMatcher(value); - Color color = isSelected ? Color.YELLOW : Color.MAGENTA; + Color color = isSelected ? Palette.YELLOW : Palette.MAGENTA; StringBuilder sb = new StringBuilder(""); // find and highlight all instances of the user-defined pattern while (matcher.find()) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/DateRangeConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/DateRangeConstraintEditor.java index 2273c4495f..26d29c74fa 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/DateRangeConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/DateRangeConstraintEditor.java @@ -15,7 +15,8 @@ */ package docking.widgets.table.constrainteditor; -import java.awt.*; +import java.awt.Component; +import java.awt.GridLayout; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; @@ -28,6 +29,7 @@ import docking.widgets.table.constraint.ColumnConstraint; import docking.widgets.table.constraint.RangeColumnConstraint; import docking.widgets.table.constraint.provider.DateColumnConstraintProvider; import docking.widgets.textfield.LocalDateTextField; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.layout.VerticalLayout; /** @@ -109,7 +111,7 @@ public class DateRangeConstraintEditor extends AbstractColumnConstraintEditor implements ColumnConstraintEditor JPanel panel = new JPanel(); JLabel errorLabel = new GDHtmlLabel( - "" + HTMLUtilities.bold(HTMLUtilities.colorString(Color.RED, message))); + "" + HTMLUtilities.bold(HTMLUtilities.colorString(Messages.ERROR, message))); panel.add(errorLabel); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/EnumConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/EnumConstraintEditor.java index 580f51a3fc..8855b7f3b7 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/EnumConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/EnumConstraintEditor.java @@ -25,6 +25,7 @@ import docking.widgets.checkbox.GCheckBox; import docking.widgets.label.GDHtmlLabel; import docking.widgets.table.constraint.ColumnConstraint; import docking.widgets.table.constraint.EnumColumnConstraint; +import generic.theme.GThemeDefaults.Colors.Messages; /** * A constraint editor for enumerated-type values; @@ -79,7 +80,7 @@ public class EnumConstraintEditor> extends AbstractColumnConst outerPanel.add(panel, BorderLayout.CENTER); infoLabel = new GDHtmlLabel(""); - infoLabel.setForeground(Color.GRAY); + infoLabel.setForeground(Messages.HINT); infoLabel.setHorizontalAlignment(SwingConstants.CENTER); outerPanel.add(infoLabel, BorderLayout.SOUTH); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerConstraintEditor.java index 764e420392..095869bce4 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerConstraintEditor.java @@ -15,7 +15,8 @@ */ package docking.widgets.table.constrainteditor; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Component; import javax.swing.*; @@ -26,6 +27,7 @@ import docking.widgets.spinner.IntegerSpinner; import docking.widgets.table.constraint.ColumnConstraint; import docking.widgets.table.constraint.SingleValueColumnConstraint; import docking.widgets.textfield.IntegerTextField; +import generic.theme.GThemeDefaults.Colors.Messages; /** * A constraint editor for specifying comparison with a single integer-type value (Byte, Short, @@ -73,7 +75,7 @@ public class IntegerConstraintEditor extends AbstractColumnCon panel.add(spinner.getSpinner(), BorderLayout.CENTER); statusLabel = new GDHtmlLabel(); panel.add(statusLabel, BorderLayout.SOUTH); - statusLabel.setForeground(Color.RED); + statusLabel.setForeground(Messages.ERROR); statusLabel.setHorizontalAlignment(SwingConstants.CENTER); return panel; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerRangeConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerRangeConstraintEditor.java index a8fb1d2826..7a326a4d46 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerRangeConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/IntegerRangeConstraintEditor.java @@ -15,7 +15,8 @@ */ package docking.widgets.table.constrainteditor; -import java.awt.*; +import java.awt.Component; +import java.awt.GridLayout; import java.math.BigInteger; import javax.swing.*; @@ -24,6 +25,7 @@ import docking.widgets.label.GDHtmlLabel; import docking.widgets.spinner.IntegerSpinner; import docking.widgets.table.constraint.ColumnConstraint; import docking.widgets.table.constraint.RangeColumnConstraint; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.layout.VerticalLayout; /** @@ -105,7 +107,7 @@ public class IntegerRangeConstraintEditor panel.add(rangeControlPanel); infoLabel = new GDHtmlLabel(); - infoLabel.setForeground(Color.GRAY); + infoLabel.setForeground(Messages.HINT); infoLabel.setHorizontalAlignment(SwingConstants.CENTER); panel.add(infoLabel); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/StringConstraintEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/StringConstraintEditor.java index d3d048dc6a..a0a493e94a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/StringConstraintEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constrainteditor/StringConstraintEditor.java @@ -15,7 +15,8 @@ */ package docking.widgets.table.constrainteditor; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Component; import javax.swing.*; @@ -23,6 +24,7 @@ import docking.DockingUtils; import docking.widgets.label.GDHtmlLabel; import docking.widgets.table.constraint.ColumnConstraint; import docking.widgets.table.constraint.StringColumnConstraint; +import generic.theme.GThemeDefaults.Colors.Messages; /** * A constraint editor for String-type values. @@ -56,7 +58,7 @@ public class StringConstraintEditor extends AbstractColumnConstraintEditor updateModelFilter()); + Gui.addThemeListener(this); } /** @@ -146,6 +148,13 @@ public class GTree extends JPanel implements BusyListener { threadLocalMonitor.set(monitor); } + @Override + public void themeChanged(ThemeEvent event) { + if (event.isLookAndFeelChanged()) { + model.fireNodeStructureChanged(getModelRoot()); + } + } + /** * Returns the monitor in associated with the GTree for the calling thread. This method is * designed to be used by slow loading nodes that are loading off the Swing thread. Some @@ -1391,6 +1400,7 @@ public class GTree extends JPanel implements BusyListener { public AutoScrollTree(TreeModel model) { super(model); + setBackground(BACKGROUND); scroller = new AutoscrollAdapter(this, 5); setRowHeight(-1);// variable size rows diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/GTreeDragNDropAdapter.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/GTreeDragNDropAdapter.java index efd7d7c7af..c62a786aee 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/GTreeDragNDropAdapter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/GTreeDragNDropAdapter.java @@ -16,10 +16,6 @@ */ package docking.widgets.tree.internal; -import ghidra.framework.OperatingSystem; -import ghidra.framework.Platform; -import ghidra.util.Msg; - import java.awt.*; import java.awt.datatransfer.Transferable; import java.awt.dnd.*; @@ -33,9 +29,15 @@ import javax.swing.SwingUtilities; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; -import docking.widgets.tree.*; +import docking.widgets.tree.GTree; +import docking.widgets.tree.GTreeNode; import docking.widgets.tree.support.GTreeDragNDropHandler; import docking.widgets.tree.support.GTreeNodeTransferable; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.framework.OperatingSystem; +import ghidra.framework.Platform; +import ghidra.util.ColorUtils; +import ghidra.util.Msg; public class GTreeDragNDropAdapter implements DragSourceListener, DragGestureListener, DropTargetListener { @@ -155,13 +157,11 @@ public class GTreeDragNDropAdapter implements DragSourceListener, DragGestureLis // now we will create a fade effect using an alpha composite and a gradient Graphics2D g2 = (Graphics2D) graphics; GradientPaint mask; - Color treeBackground = tree.getBackground(); - Color transparentTreeBackground = - new Color(treeBackground.getRed(), treeBackground.getGreen(), treeBackground.getBlue(), - 100); + Color treeBg = tree.getBackground(); + Color transparentTreeBackground = ColorUtils.withAlpha(treeBg, 100); mask = - new GradientPaint(0, 0, transparentTreeBackground, 0, size.height >> 1, new Color(1.0f, - 1.0f, 1.0f, 0.0f)); + new GradientPaint(0, 0, transparentTreeBackground, 0, size.height >> 1, + Palette.NO_COLOR); g2.setPaint(mask); // Sets the alpha composite @@ -214,14 +214,14 @@ public class GTreeDragNDropAdapter implements DragSourceListener, DragGestureLis private List createSelectionList(TreePath[] selectionPaths) { - List list = new ArrayList(); + List list = new ArrayList<>(); if (selectionPaths == null) { return list; } - for (int i = 0; i < selectionPaths.length; i++) { - list.add((GTreeNode) selectionPaths[i].getLastPathComponent()); + for (TreePath selectionPath : selectionPaths) { + list.add((GTreeNode) selectionPath.getLastPathComponent()); } return list; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeNode.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeNode.java index dca009522b..72d94fa2d9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeNode.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeNode.java @@ -18,11 +18,10 @@ package docking.widgets.tree.internal; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; -import docking.widgets.tree.GTreeNode; -import resources.ResourceManager; +import generic.theme.GIcon; public class InProgressGTreeNode extends GTreeNode { - private static final Icon ICON = ResourceManager.loadImage("images/magnifier.png"); + private static final Icon ICON = new GIcon("icon.search"); public InProgressGTreeNode() { } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeRootNode.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeRootNode.java index b71f3d0331..0bf6197737 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeRootNode.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/internal/InProgressGTreeRootNode.java @@ -18,11 +18,11 @@ package docking.widgets.tree.internal; import javax.swing.Icon; import docking.widgets.tree.GTreeNode; -import resources.ResourceManager; +import generic.theme.GIcon; public class InProgressGTreeRootNode extends GTreeNode { - private static final Icon ICON = ResourceManager.loadImage("images/magnifier.png"); + private static final Icon ICON = new GIcon("icon.search"); @Override public String getName() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeRenderer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeRenderer.java index d373b28dbc..c76a67e2f7 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeRenderer.java @@ -25,11 +25,14 @@ import javax.swing.tree.DefaultTreeCellRenderer; import docking.widgets.GComponent; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; +import generic.theme.GColor; public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent { - private static final Color VALID_DROP_TARGET_COLOR = new Color(200, 200, 255); + private static final Color VALID_DROP_TARGET_COLOR = new GColor("color.bg.tree.drag"); private static final int DEFAULT_MIN_ICON_WIDTH = 22; + private static final Color BACKGROUND_UNSELECTED = new GColor("color.bg.tree"); + private static final Color BACKGROUND_SELECTED = new GColor("color.bg.tree.selected"); private Object dropTarget; private boolean paintDropTarget; @@ -40,6 +43,8 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent public GTreeRenderer() { setHTMLRenderingEnabled(false); + setBackgroundNonSelectionColor(BACKGROUND_UNSELECTED); + setBackgroundSelectionColor(BACKGROUND_SELECTED); } @Override @@ -84,12 +89,12 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent @Override public void setBackgroundSelectionColor(Color newColor) { - super.setBackgroundSelectionColor(fromUiResource(newColor)); + super.setBackgroundSelectionColor(fromUiResource(newColor, "Tree.selectionBackground")); } @Override public void setBackgroundNonSelectionColor(Color newColor) { - super.setBackgroundNonSelectionColor(fromUiResource(newColor)); + super.setBackgroundNonSelectionColor(fromUiResource(newColor, "Tree.textBackground")); } /** @@ -99,11 +104,12 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent * method. * * @param c the source color + * @param defaultKey the GColor key to use if the given color is a ColorUIResource * @return the new color */ - protected Color fromUiResource(Color c) { + protected Color fromUiResource(Color c, String defaultKey) { if (c instanceof ColorUIResource) { - return new Color(c.getRGB()); + return new GColor(defaultKey); } return c; } @@ -140,7 +146,7 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent // Bug Alert!: // We must create a new font here and not use deriveFont(). Using derive font has // bugs when calculating the string width for a bold derived font. - cachedBoldFont = new Font(font.getFamily(), Font.BOLD, font.getSize()); + cachedBoldFont = font.deriveFont(Font.BOLD); } return bold ? cachedBoldFont : cachedDefaultFont; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java b/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java index 3e8d1ba78a..7024d97153 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/wizard/WizardManager.java @@ -27,10 +27,11 @@ import docking.DialogComponentProvider; import docking.DockingWindowManager; import docking.widgets.EmptyBorderButton; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.util.*; import help.Help; import help.HelpService; -import resources.ResourceManager; +import resources.Icons; /** * A dialog that controls the panels for going to "Next" and "Previous" in some @@ -81,6 +82,7 @@ public class WizardManager extends DialogComponentProvider implements WizardPane /** * @see java.awt.Window#dispose() */ + @Override public void dispose() { if (currWizPanel != null) { currWizPanel.removeWizardPanelListener(this); @@ -219,7 +221,7 @@ public class WizardManager extends DialogComponentProvider implements WizardPane : new GDLabel(INIT_TITLE, wizardIcon, SwingConstants.TRAILING)); EmptyBorderButton helpButton = - new EmptyBorderButton(ResourceManager.loadImage("images/information.png")); + new EmptyBorderButton(Icons.INFO_ICON); helpButton.setToolTipText("Help (F1)"); helpButton.addActionListener( e -> DockingWindowManager.getHelpService().showHelp(rootPanel, false, rootPanel)); @@ -471,7 +473,7 @@ if (!visitedMap.containsKey(currWizPanel)) { } titledBorder.setTitleFont(font.deriveFont(10f)); - titledBorder.setTitleColor(Color.BLUE); + titledBorder.setTitleColor(Messages.NORMAL); titledBorder.setTitlePosition(TitledBorder.BOTTOM); titledBorder.setTitleJustification(TitledBorder.TRAILING); diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/DockingWindowsLookAndFeelUtils.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/DockingWindowsLookAndFeelUtils.java deleted file mode 100644 index 9b1e6199e5..0000000000 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/DockingWindowsLookAndFeelUtils.java +++ /dev/null @@ -1,376 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.docking.util; - -import java.awt.Dimension; -import java.awt.Font; -import java.util.*; -import java.util.Map.Entry; - -import javax.swing.*; -import javax.swing.UIManager.LookAndFeelInfo; -import javax.swing.plaf.ComponentUI; - -import ghidra.docking.util.painting.GRepaintManager; -import ghidra.framework.OperatingSystem; -import ghidra.framework.Platform; -import ghidra.framework.preferences.Preferences; -import ghidra.util.*; - -/** - * A utility class to manage LookAndFeel (LaF) settings. - */ -public class DockingWindowsLookAndFeelUtils { - - /** - * Preference name for look and feel for the application. - */ - public final static String LAST_LOOK_AND_FEEL_KEY = "LastLookAndFeel"; - - /** - * Preference name for whether to use inverted colors. - */ - public final static String USE_INVERTED_COLORS_KEY = "LookAndFeel.UseInvertedColors"; - - /** - * Metal is the non-system, generic Java Look and Feel. - */ - public final static String METAL_LOOK_AND_FEEL = "Metal"; - - /** - * Default Look and feel for the current platform. - */ - private final static String SYSTEM_LOOK_AND_FEEL = "System"; - - /** - * The most stable Linux LaF, based on anecdotal observation. - */ - private static final String NIMBUS_LOOK_AND_FEEL = "Nimbus"; - - /** - * The Motif LaF name. - */ - private static final String MOTIF_LOOK_AND_FEEL = "CDE/Motif"; - - private static RepaintManager defaultSwingRepaintManager = null; - - private DockingWindowsLookAndFeelUtils() { - // utils class, cannot create - } - - /** - * Loads settings from {@link Preferences}. - */ - public static void loadFromPreferences() { - - boolean useHistoricalValue = true; - String laf = Preferences.getProperty(LAST_LOOK_AND_FEEL_KEY, getDefaultLookAndFeelName(), - useHistoricalValue); - setLookAndFeel(laf); - - boolean useInvertedColors = getUseInvertedColorsPreference(); - setUseInvertedColors(useInvertedColors); - - // - // Users can change this via the SystemUtilities.FONT_SIZE_OVERRIDE_PROPERTY_NAME - // system property. - // - Integer fontOverride = SystemUtilities.getFontSizeOverrideValue(); - if (fontOverride != null) { - setGlobalFontSizeOverride(fontOverride); - } - } - - /** - * Returns the {@link Preferences} value for whether to use inverted colors when painting. - * @return the {@link Preferences} value for whether to use inverted colors when painting. - */ - public static boolean getUseInvertedColorsPreference() { - boolean useHistoricalValue = true; - String useInvertedColorsString = Preferences.getProperty(USE_INVERTED_COLORS_KEY, - Boolean.FALSE.toString(), useHistoricalValue); - boolean useInvertedColors = Boolean.parseBoolean(useInvertedColorsString); - return useInvertedColors; - } - - /** - * Returns the currently installed LaF. - * @return the currently installed LaF. - */ - public static String getInstalledLookAndFeelName() { - return UIManager.getLookAndFeel().getName(); - } - - /** - * Set the look and feel (LAF) indicated by the string passed in as a parameter. - * The string value can be either the class name of the LAF, as returned by - * LookAndFeelInfo.getClassName() or the name as returned by - * LookAndFeelInfo.getName(). - *

- * Note: to be effective, this call needs to be made before any components have been created - * and shown. - * - * @param lookAndFeelName the string indicating which look and feel is desired (see above) - */ - public static void setLookAndFeel(String lookAndFeelName) { - SystemUtilities.runSwingNow(() -> { - try { - installLookAndFeelByName(lookAndFeelName); - - // some custom values for any given LAF - installGlobalLookAndFeelAttributes(); - installGlobalFontSizeOverride(); - installCustomLookAndFeelActions(); - installPopupMenuSettingsOverride(); - } - catch (Exception exc) { - Msg.error(DockingWindowsLookAndFeelUtils.class, - "Error loading Look and Feel: " + exc, exc); - } - }); - } - - /** - * Returns all installed LaFs. This will vary by OS. - * @return all installed LaFs. - */ - public static List getLookAndFeelNames() { - List list = new ArrayList<>(); - list.add(DockingWindowsLookAndFeelUtils.SYSTEM_LOOK_AND_FEEL); - - LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels(); - for (LookAndFeelInfo info : installedLookAndFeels) { - list.add(info.getName()); - } - return list; - } - - private static void installLookAndFeelByName(String lookAndFeelName) - throws ClassNotFoundException, InstantiationException, IllegalAccessException, - UnsupportedLookAndFeelException { - - String lookAndFeelClassName = findLookAndFeelClassName(lookAndFeelName); - UIManager.setLookAndFeel(lookAndFeelClassName); - fixupLookAndFeelIssues(); - } - - private static String findLookAndFeelClassName(String lookAndFeelName) { - if (lookAndFeelName.equalsIgnoreCase(SYSTEM_LOOK_AND_FEEL)) { - return UIManager.getSystemLookAndFeelClassName(); - } - - LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels(); - for (LookAndFeelInfo info : installedLookAndFeels) { - String className = info.getClassName(); - if (lookAndFeelName.equals(className) || lookAndFeelName.equals(info.getName())) { - return className; - } - } - - Msg.debug(DockingWindowsLookAndFeelUtils.class, - "Unable to find requested Look and Feel: " + lookAndFeelName); - return UIManager.getSystemLookAndFeelClassName(); - } - - public static void setUseInvertedColors(boolean useInvertedColors) { - SystemUtilities.runIfSwingOrPostSwingLater(() -> { - - if (defaultSwingRepaintManager == null) { - defaultSwingRepaintManager = RepaintManager.currentManager(null /*unused*/); - } - - RepaintManager rm = defaultSwingRepaintManager; - if (useInvertedColors) { - rm = new GRepaintManager(); - } - RepaintManager.setCurrentManager(rm); - }); - } - - /** - * Fixes issues in the currently running look and feel. - */ - private static void fixupLookAndFeelIssues() { - LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); - switch (lookAndFeel.getName()) { - case NIMBUS_LOOK_AND_FEEL: - // fix scroll bar grabber disappearing. See https://bugs.openjdk.java.net/browse/JDK-8134828 - // This fix looks like it should not cause harm even if the bug is fixed on the jdk side. - UIDefaults defaults = UIManager.getDefaults(); - defaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30)); - - // (see NimbusDefaults for key values that can be changed here) - break; - case MOTIF_LOOK_AND_FEEL: - - doFixupMissingCopyPasteKeyBindings(); - - // (see MotifDefaults for key values that can be changed here) - break; - } - } - - private static void doFixupMissingCopyPasteKeyBindings() { - - // - // The Motif LaF does not bind copy/paste/cut to Control-C/V/X by default. Rather, they - // only use the COPY/PASTE/CUT keys. The other LaFs bind both shortcuts. - // - - // these prefixes are for text components - String[] UIPrefixValues = - { "TextField", "FormattedTextField", "TextArea", "TextPane", "EditorPane" }; - - setKeyBinding("COPY", "ctrl C", UIPrefixValues); - setKeyBinding("PASTE", "ctrl V", UIPrefixValues); - setKeyBinding("CUT", "ctrl X", UIPrefixValues); - } - - private static void installGlobalLookAndFeelAttributes() { - // Fix up the default fonts that Java 1.5.0 changed to Courier, which looked terrible. - Font f = new Font("Monospaced", Font.PLAIN, 12); - UIManager.put("PasswordField.font", f); - UIManager.put("TextArea.font", f); - - // We like buttons that change on hover, so force that to happen (see Tracker SCR 3966) - UIManager.put("Button.rollover", Boolean.TRUE); - UIManager.put("ToolBar.isRollover", Boolean.TRUE); - } - - private static void installPopupMenuSettingsOverride() { - // Java 1.6 UI consumes MousePressed event when dismissing popup menu - // which prevents application components from getting this event. - UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE); - } - - private static void installGlobalFontSizeOverride() { - - // only set a global size if the property is set - Integer overrideFontInteger = SystemUtilities.getFontSizeOverrideValue(); - if (overrideFontInteger == null) { - return; - } - - setGlobalFontSizeOverride(overrideFontInteger); - } - - private static void installCustomLookAndFeelActions() { - // these prefixes are for text components - String[] UIPrefixValues = - { "TextField", "FormattedTextField", "TextArea", "TextPane", "EditorPane" }; - - DeleteToStartOfWordAction deleteToStartOfWordAction = new DeleteToStartOfWordAction(); - registerAction(deleteToStartOfWordAction, DeleteToStartOfWordAction.KEY_STROKE, - UIPrefixValues); - - DeleteToEndOfWordAction deleteToEndOfWordAction = new DeleteToEndOfWordAction(); - registerAction(deleteToEndOfWordAction, DeleteToEndOfWordAction.KEY_STROKE, UIPrefixValues); - - BeginningOfLineAction beginningOfLineAction = new BeginningOfLineAction(); - registerAction(beginningOfLineAction, BeginningOfLineAction.KEY_STROKE, UIPrefixValues); - - EndOfLineAction endOfLineAction = new EndOfLineAction(); - registerAction(endOfLineAction, EndOfLineAction.KEY_STROKE, UIPrefixValues); - - SelectBeginningOfLineAction selectBeginningOfLineAction = new SelectBeginningOfLineAction(); - registerAction(selectBeginningOfLineAction, SelectBeginningOfLineAction.KEY_STROKE, - UIPrefixValues); - - SelectEndOfLineAction selectEndOfLineAction = new SelectEndOfLineAction(); - registerAction(selectEndOfLineAction, SelectEndOfLineAction.KEY_STROKE, UIPrefixValues); - } - - private static void registerAction(Action action, KeyStroke keyStroke, String[] prefixValues) { - for (String properyPrefix : prefixValues) { - UIDefaults defaults = UIManager.getDefaults(); - Object object = defaults.get(properyPrefix + ".focusInputMap"); - InputMap inputMap = (InputMap) object; - inputMap.put(keyStroke, action); - } - } - - private static void setKeyBinding(String existingKsText, String newKsText, - String[] prefixValues) { - - KeyStroke existingKs = KeyStroke.getKeyStroke(existingKsText); - KeyStroke newKs = KeyStroke.getKeyStroke(newKsText); - - for (String properyPrefix : prefixValues) { - - UIDefaults defaults = UIManager.getDefaults(); - Object object = defaults.get(properyPrefix + ".focusInputMap"); - InputMap inputMap = (InputMap) object; - Object action = inputMap.get(existingKs); - inputMap.put(newKs, action); - } - } - - /** Allows you to globally set the font size (don't use this method!) */ - private static void setGlobalFontSizeOverride(int fontSize) { - UIDefaults defaults = UIManager.getDefaults(); - - Set> set = defaults.entrySet(); - Iterator> iterator = set.iterator(); - while (iterator.hasNext()) { - Entry entry = iterator.next(); - Object key = entry.getKey(); - - if (key.toString().toLowerCase().indexOf("font") != -1) { - Font currentFont = defaults.getFont(key); - if (currentFont != null) { - Font newFont = currentFont.deriveFont((float) fontSize); - UIManager.put(key, newFont); - } - } - } - } - - /** - * Returns the name of the default LookAndFeel for the current OS. - */ - private static String getDefaultLookAndFeelName() { - OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem(); - if (OS == OperatingSystem.LINUX) { - return NIMBUS_LOOK_AND_FEEL; - } - return SYSTEM_LOOK_AND_FEEL; - } - - /** - * Returns true if the given UI object is using the Aqua Look and Feel. - * @param UI the UI to examine. - * @return true if the UI is using Aqua - */ - public static boolean isUsingAquaUI(ComponentUI UI) { - Class clazz = UI.getClass(); - String name = clazz.getSimpleName(); - return name.startsWith("Aqua"); - } - - /** - * Returns true if 'Nimbus' is the current Look and Feel - * @return true if 'Nimbus' is the current Look and Feel - */ - public static boolean isUsingNimbusUI() { - LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); - return NIMBUS_LOOK_AND_FEEL.equals(lookAndFeel.getName()); - } - - public static boolean isUsingMotifUI() { - LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); - return MOTIF_LOOK_AND_FEEL.equals(lookAndFeel.getName()); - } -} diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/LookAndFeelUtils.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/LookAndFeelUtils.java new file mode 100644 index 0000000000..1e9d3a2e9e --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/LookAndFeelUtils.java @@ -0,0 +1,112 @@ +/* ### + * 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 ghidra.docking.util; + +import java.awt.Font; +import java.awt.Taskbar; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; + +import docking.framework.ApplicationInformationDisplayFactory; +import generic.theme.LafType; +import generic.theme.ThemeManager; +import ghidra.framework.preferences.Preferences; +import ghidra.util.SystemUtilities; + +/** + * A utility class to manage LookAndFeel (LaF) settings. + */ +public class LookAndFeelUtils { + + private LookAndFeelUtils() { + // utils class, cannot create + } + + /** + * Loads settings from {@link Preferences}. + */ + public static void installGlobalOverrides() { + + // + // Users can change this via the SystemUtilities.FONT_SIZE_OVERRIDE_PROPERTY_NAME + // system property. + // + Integer fontOverride = SystemUtilities.getFontSizeOverrideValue(); + if (fontOverride != null) { + setGlobalFontSizeOverride(fontOverride); + } + } + + /** Allows you to globally set the font size (don't use this method!) */ + private static void setGlobalFontSizeOverride(int fontSize) { + UIDefaults defaults = UIManager.getDefaults(); + + Set> set = defaults.entrySet(); + Iterator> iterator = set.iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + Object key = entry.getKey(); + + if (key.toString().toLowerCase().indexOf("font") != -1) { + Font currentFont = defaults.getFont(key); + if (currentFont != null) { + Font newFont = currentFont.deriveFont((float) fontSize); + UIManager.put(key, newFont); + } + } + } + } + + public static void performPlatformSpecificFixups() { + // Set the dock icon for macOS + if (Taskbar.isTaskbarSupported()) { + Taskbar taskbar = Taskbar.getTaskbar(); + if (taskbar.isSupported(Taskbar.Feature.ICON_IMAGE)) { + taskbar.setIconImage(ApplicationInformationDisplayFactory.getLargestWindowIcon()); + } + } + } + + /** + * Returns the {@link LafType} for the currently active {@link LookAndFeel} + * @return the {@link LafType} for the currently active {@link LookAndFeel} + */ + public static LafType getLookAndFeelType() { + return ThemeManager.getInstance().getLookAndFeelType(); + } + + /** + * Returns true if the given UI object is using the Aqua Look and Feel. + * @param UI the UI to examine. + * @return true if the UI is using Aqua + */ + public static boolean isUsingAquaUI(ComponentUI UI) { + return ThemeManager.getInstance().isUsingAquaUI(UI); + } + + /** + * Returns true if 'Nimbus' is the current Look and Feel + * @return true if 'Nimbus' is the current Look and Feel + */ + public static boolean isUsingNimbusUI() { + return ThemeManager.getInstance().isUsingNimbusUI(); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/painting/GRepaintManager.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/painting/GRepaintManager.java deleted file mode 100644 index a1e554fd09..0000000000 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/painting/GRepaintManager.java +++ /dev/null @@ -1,173 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.docking.util.painting; - -import java.awt.*; -import java.awt.image.*; - -import javax.swing.RepaintManager; - -import ghidra.util.Msg; -import sun.awt.image.SurfaceManager; - -/** - * A repaint manager that can be plugged-in to Java's {@link RepaintManager} in order to - * change how we paint colors. - * - * @see Graphics2D - */ -public class GRepaintManager extends RepaintManager { - - private VolatileImageWrapper imageWrapper = new VolatileImageWrapper(); - - @Override - public Image getVolatileOffscreenBuffer(Component c, int proposedWidth, int proposedHeight) { - Image image = super.getVolatileOffscreenBuffer(c, proposedWidth, proposedHeight); - - if (!(image instanceof VolatileImage)) { - Msg.debug(this, - "Cannot install Graphics2D color inverter. Non-volatile image found: " + - image.getClass().getName()); - return image; - } - - imageWrapper.setImage((VolatileImage) image); - return imageWrapper; - } - - private class VolatileImageWrapper extends VolatileImage { - - private Graphics2DWrapper wrapper = new Graphics2DWrapper(); - private VolatileImage image = this; - - void setImage(VolatileImage image) { - this.image = image; - SurfaceManager manager = SurfaceManager.getManager(image); - SurfaceManager.setManager(this, manager); - } - - @Override - public Graphics getGraphics() { - Graphics g = image.getGraphics(); - wrapper.setDelegate((Graphics2D) g); - return wrapper; - } - - @Override - public BufferedImage getSnapshot() { - return image.getSnapshot(); - } - - @Override - public int getWidth() { - return image.getWidth(); - } - - @Override - public int getHeight() { - return image.getHeight(); - } - - @Override - public Graphics2D createGraphics() { - return image.createGraphics(); - } - - @Override - public int validate(GraphicsConfiguration gc) { - return image.validate(gc); - } - - @Override - public boolean contentsLost() { - return image.contentsLost(); - } - - @Override - public ImageCapabilities getCapabilities() { - return image.getCapabilities(); - } - - @Override - public int getTransparency() { - if (image == null) { - return super.getTransparency(); - } - return image.getTransparency(); - } - - @Override - public int getWidth(ImageObserver observer) { - return image.getWidth(observer); - } - - @Override - public int hashCode() { - return image.hashCode(); - } - - @Override - public int getHeight(ImageObserver observer) { - return image.getHeight(observer); - } - - @Override - public ImageProducer getSource() { - return image.getSource(); - } - - @Override - public boolean equals(Object obj) { - return image.equals(obj); - } - - @Override - public Object getProperty(String name, ImageObserver observer) { - return image.getProperty(name, observer); - } - - @Override - public Image getScaledInstance(int width, int height, int hints) { - return image.getScaledInstance(width, height, hints); - } - - @Override - public void flush() { - image.flush(); - } - - @Override - public String toString() { - return image.toString(); - } - - @Override - public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { - return image.getCapabilities(gc); - } - - @Override - public void setAccelerationPriority(float priority) { - image.setAccelerationPriority(priority); - } - - @Override - public float getAccelerationPriority() { - return image.getAccelerationPriority(); - } - - } -} diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/painting/Graphics2DWrapper.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/painting/Graphics2DWrapper.java deleted file mode 100644 index 1d6a69b601..0000000000 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/painting/Graphics2DWrapper.java +++ /dev/null @@ -1,573 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.docking.util.painting; - -import java.awt.*; -import java.awt.MultipleGradientPaint.CycleMethod; -import java.awt.RenderingHints.Key; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphVector; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.image.*; -import java.awt.image.renderable.RenderableImage; -import java.text.AttributedCharacterIterator; -import java.util.Map; - -/** - * A simple wrapper object that changes colors passed to {@link Graphics2D}. - */ -public class Graphics2DWrapper extends Graphics2D { - - private Graphics2D delegate; - - public Graphics2DWrapper() { - // delegate set later - } - - private Graphics2DWrapper(Graphics2D delegate) { - setDelegate(delegate); - } - - public void setDelegate(Graphics2D delegate) { - this.delegate = delegate; - - setColor(delegate.getColor()); - setBackground(delegate.getBackground()); - setPaint(delegate.getPaint()); - } - - @Override - public int hashCode() { - return delegate.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return delegate.equals(obj); - } - - @Override - public Graphics create() { - return new Graphics2DWrapper((Graphics2D) delegate.create()); - } - - @Override - public Graphics create(int x, int y, int width, int height) { - return new Graphics2DWrapper((Graphics2D) delegate.create(x, y, width, height)); - } - - @Override - public Color getColor() { - // - // Clients will call this method to later restore this Graphic's color. So, we must - // revert the color or it will get restored incorrectly. - // - Color alt = delegate.getColor(); - Color orig = getComplementaryColor(alt); - return orig; - } - - private static Color getComplementaryColor(Color c) { - - if (c == null) { - return null; - } - - Color alt = new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c.getBlue()); - return alt; - } - - @Override - public void setBackground(Color c) { - Color alt = getComplementaryColor(c); - delegate.setBackground(alt); - } - - @Override - public Color getBackground() { - // - // Clients will call this method to later restore this Graphic's color. So, we must - // revert the color or it will get restored incorrectly. - // - Color alt = delegate.getBackground(); - Color orig = getComplementaryColor(alt); - return orig; - } - - @Override - public void setColor(Color c) { - Color alt = getComplementaryColor(c); - delegate.setColor(alt); - } - - @Override - public Paint getPaint() { - Paint alt = delegate.getPaint(); - - if (alt instanceof Color) { - Color c = (Color) alt; - Color orig = getComplementaryColor(c); - return orig; - } - else if (alt instanceof GradientPaint) { - GradientPaint gp = (GradientPaint) alt; - Color alt1 = getComplementaryColor(gp.getColor1()); - Color alt2 = getComplementaryColor(gp.getColor2()); - GradientPaint orig = - new GradientPaint(gp.getPoint1(), alt1, gp.getPoint2(), alt2, gp.isCyclic()); - return orig; - } - else if (alt instanceof LinearGradientPaint) { - - LinearGradientPaint gp = (LinearGradientPaint) alt; - Color[] colors = gp.getColors(); - float[] fractions = gp.getFractions(); - Point2D start = gp.getStartPoint(); - Point2D end = gp.getEndPoint(); - CycleMethod cycleMethod = gp.getCycleMethod(); - LinearGradientPaint orig = - new LinearGradientPaint(start, end, fractions, colors, cycleMethod); - return orig; - } - else { - // Else case from setPaint() - } - - return alt; - } - - @Override - public void setPaint(Paint paint) { - - if (paint instanceof Color) { - Color c = (Color) paint; - Color alt = getComplementaryColor(c); - delegate.setPaint(alt); - } - else if (paint instanceof GradientPaint) { - GradientPaint gp = (GradientPaint) paint; - Color alt1 = getComplementaryColor(gp.getColor1()); - Color alt2 = getComplementaryColor(gp.getColor2()); - GradientPaint alt = - new GradientPaint(gp.getPoint1(), alt1, gp.getPoint2(), alt2, gp.isCyclic()); - delegate.setPaint(alt); - } - else if (paint instanceof LinearGradientPaint) { - - LinearGradientPaint gp = (LinearGradientPaint) paint; - Color[] colors = gp.getColors(); - float[] fractions = gp.getFractions(); - Point2D start = gp.getStartPoint(); - Point2D end = gp.getEndPoint(); - CycleMethod cycleMethod = gp.getCycleMethod(); - LinearGradientPaint alt = - new LinearGradientPaint(start, end, fractions, colors, cycleMethod); - delegate.setPaint(alt); - } - else { - - System.err.println("G2DWrapper - non-Color Paint: " + paint.getClass().getSimpleName()); - delegate.setPaint(paint); - } - } - - @Override - public void setPaintMode() { - delegate.setPaintMode(); - } - - @Override - public void setXORMode(Color c1) { - delegate.setXORMode(c1); - } - - @Override - public Font getFont() { - return delegate.getFont(); - } - - @Override - public void setFont(Font font) { - delegate.setFont(font); - } - - @Override - public FontMetrics getFontMetrics() { - return delegate.getFontMetrics(); - } - - @Override - public FontMetrics getFontMetrics(Font f) { - return delegate.getFontMetrics(f); - } - - @Override - public Rectangle getClipBounds() { - return delegate.getClipBounds(); - } - - @Override - public void clipRect(int x, int y, int width, int height) { - delegate.clipRect(x, y, width, height); - } - - @Override - public void setClip(int x, int y, int width, int height) { - delegate.setClip(x, y, width, height); - } - - @Override - public Shape getClip() { - return delegate.getClip(); - } - - @Override - public void setClip(Shape clip) { - delegate.setClip(clip); - } - - @Override - public void copyArea(int x, int y, int width, int height, int dx, int dy) { - delegate.copyArea(x, y, width, height, dx, dy); - } - - @Override - public void drawLine(int x1, int y1, int x2, int y2) { - delegate.drawLine(x1, y1, x2, y2); - } - - @Override - public void fillRect(int x, int y, int width, int height) { - delegate.fillRect(x, y, width, height); - } - - @Override - public void drawRect(int x, int y, int width, int height) { - delegate.drawRect(x, y, width, height); - } - - @Override - public void draw3DRect(int x, int y, int width, int height, boolean raised) { - delegate.draw3DRect(x, y, width, height, raised); - } - - @Override - public void clearRect(int x, int y, int width, int height) { - delegate.clearRect(x, y, width, height); - } - - @Override - public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - delegate.drawRoundRect(x, y, width, height, arcWidth, arcHeight); - } - - @Override - public void fill3DRect(int x, int y, int width, int height, boolean raised) { - delegate.fill3DRect(x, y, width, height, raised); - } - - @Override - public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - delegate.fillRoundRect(x, y, width, height, arcWidth, arcHeight); - } - - @Override - public void draw(Shape s) { - delegate.draw(s); - } - - @Override - public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { - return delegate.drawImage(img, xform, obs); - } - - @Override - public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { - delegate.drawImage(img, op, x, y); - } - - @Override - public void drawOval(int x, int y, int width, int height) { - delegate.drawOval(x, y, width, height); - } - - @Override - public void drawRenderedImage(RenderedImage img, AffineTransform xform) { - delegate.drawRenderedImage(img, xform); - } - - @Override - public void fillOval(int x, int y, int width, int height) { - delegate.fillOval(x, y, width, height); - } - - @Override - public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - delegate.drawArc(x, y, width, height, startAngle, arcAngle); - } - - @Override - public void drawRenderableImage(RenderableImage img, AffineTransform xform) { - delegate.drawRenderableImage(img, xform); - } - - @Override - public void drawString(String str, int x, int y) { - delegate.drawString(str, x, y); - } - - @Override - public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { - delegate.fillArc(x, y, width, height, startAngle, arcAngle); - } - - @Override - public void drawString(String str, float x, float y) { - delegate.drawString(str, x, y); - } - - @Override - public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { - delegate.drawPolyline(xPoints, yPoints, nPoints); - } - - @Override - public void drawString(AttributedCharacterIterator iterator, int x, int y) { - delegate.drawString(iterator, x, y); - } - - @Override - public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { - delegate.drawPolygon(xPoints, yPoints, nPoints); - } - - @Override - public void drawString(AttributedCharacterIterator iterator, float x, float y) { - delegate.drawString(iterator, x, y); - } - - @Override - public void drawPolygon(Polygon p) { - delegate.drawPolygon(p); - } - - @Override - public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { - delegate.fillPolygon(xPoints, yPoints, nPoints); - } - - @Override - public void drawGlyphVector(GlyphVector g, float x, float y) { - delegate.drawGlyphVector(g, x, y); - } - - @Override - public void fillPolygon(Polygon p) { - delegate.fillPolygon(p); - } - - @Override - public void fill(Shape s) { - delegate.fill(s); - } - - @Override - public boolean hit(Rectangle rect, Shape s, boolean onStroke) { - return delegate.hit(rect, s, onStroke); - } - - @Override - public void drawChars(char[] data, int offset, int length, int x, int y) { - delegate.drawChars(data, offset, length, x, y); - } - - @Override - public GraphicsConfiguration getDeviceConfiguration() { - return delegate.getDeviceConfiguration(); - } - - @Override - public void setComposite(Composite comp) { - delegate.setComposite(comp); - } - - @Override - public void drawBytes(byte[] data, int offset, int length, int x, int y) { - delegate.drawBytes(data, offset, length, x, y); - } - - @Override - public boolean drawImage(Image img, int x, int y, ImageObserver observer) { - - return delegate.drawImage(img, x, y, observer); - } - - @Override - public void setStroke(Stroke s) { - delegate.setStroke(s); - } - - @Override - public void setRenderingHint(Key hintKey, Object hintValue) { - delegate.setRenderingHint(hintKey, hintValue); - } - - @Override - public Object getRenderingHint(Key hintKey) { - return delegate.getRenderingHint(hintKey); - } - - @Override - public boolean drawImage(Image img, int x, int y, int width, int height, - ImageObserver observer) { - return delegate.drawImage(img, x, y, width, height, observer); - } - - @Override - public void setRenderingHints(Map hints) { - delegate.setRenderingHints(hints); - } - - @Override - public void addRenderingHints(Map hints) { - delegate.addRenderingHints(hints); - } - - @Override - public RenderingHints getRenderingHints() { - return delegate.getRenderingHints(); - } - - @Override - public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { - return delegate.drawImage(img, x, y, bgcolor, observer); - } - - @Override - public void translate(int x, int y) { - delegate.translate(x, y); - } - - @Override - public void translate(double tx, double ty) { - delegate.translate(tx, ty); - } - - @Override - public void rotate(double theta) { - delegate.rotate(theta); - } - - @Override - public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, - ImageObserver observer) { - return delegate.drawImage(img, x, y, width, height, bgcolor, observer); - } - - @Override - public void rotate(double theta, double x, double y) { - delegate.rotate(theta, x, y); - } - - @Override - public void scale(double sx, double sy) { - delegate.scale(sx, sy); - } - - @Override - public void shear(double shx, double shy) { - delegate.shear(shx, shy); - } - - @Override - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, - int sx2, int sy2, ImageObserver observer) { - return delegate.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); - } - - @Override - public void transform(AffineTransform Tx) { - delegate.transform(Tx); - } - - @Override - public void setTransform(AffineTransform Tx) { - delegate.setTransform(Tx); - } - - @Override - public AffineTransform getTransform() { - return delegate.getTransform(); - } - - @Override - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, - int sx2, int sy2, Color bgcolor, ImageObserver observer) { - return delegate.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); - } - - @Override - public Composite getComposite() { - return delegate.getComposite(); - } - - @Override - public Stroke getStroke() { - return delegate.getStroke(); - } - - @Override - public void clip(Shape s) { - delegate.clip(s); - } - - @Override - public FontRenderContext getFontRenderContext() { - return delegate.getFontRenderContext(); - } - - @Override - public void dispose() { - delegate.dispose(); - } - - @Override - public void finalize() { - delegate.finalize(); - } - - @Override - public String toString() { - return delegate.toString(); - } - - @Override - public Rectangle getClipRect() { - return delegate.getClipBounds(); - } - - @Override - public boolean hitClip(int x, int y, int width, int height) { - return delegate.hitClip(x, y, width, height); - } - - @Override - public Rectangle getClipBounds(Rectangle r) { - return delegate.getClipBounds(r); - } - -} diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/ChompingBitsAnimationPanel.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/ChompingBitsAnimationPanel.java index e37b9af018..c06ee2a9af 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/ChompingBitsAnimationPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/ChompingBitsAnimationPanel.java @@ -17,31 +17,34 @@ package ghidra.util.task; import java.awt.BorderLayout; import java.awt.Dimension; -import java.util.ArrayList; import java.util.List; import javax.swing.*; import docking.util.AnimatedIcon; -import resources.ResourceManager; +import generic.theme.GIcon; /** - * Panel that displays an animation of the Ghidra dragon chomping bits. + * Panel that displays an animation of the Ghidra dragon eating bits. */ public class ChompingBitsAnimationPanel extends JPanel { + //@formatter:off + private static final List ICONS = List.of( + new GIcon("icon.task.progress.1"), + new GIcon("icon.task.progress.2"), + new GIcon("icon.task.progress.3"), + new GIcon("icon.task.progress.4"), + new GIcon("icon.task.progress.5"), + new GIcon("icon.task.progress.6"), + new GIcon("icon.task.progress.7") + ); + //@formatter:on + public ChompingBitsAnimationPanel() { setLayout(new BorderLayout()); - - List iconList = new ArrayList<>(); - iconList.add(ResourceManager.loadImage("images/eatbits1.png")); - iconList.add(ResourceManager.loadImage("images/eatbits2.png")); - iconList.add(ResourceManager.loadImage("images/eatbits3.png")); - iconList.add(ResourceManager.loadImage("images/eatbits4.png")); - iconList.add(ResourceManager.loadImage("images/eatbits5.png")); - iconList.add(ResourceManager.loadImage("images/eatbits6.png")); - iconList.add(ResourceManager.loadImage("images/eatbits7.png")); - AnimatedIcon icon = new AnimatedIcon(iconList, 200, 0); + + AnimatedIcon icon = new AnimatedIcon(ICONS, 200, 0); setSize(new Dimension(200, 100)); add(new JLabel(icon)); } diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/HourglassAnimationPanel.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/HourglassAnimationPanel.java index e0f0666c1f..3567663ba4 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/HourglassAnimationPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/HourglassAnimationPanel.java @@ -16,44 +16,44 @@ package ghidra.util.task; import java.awt.BorderLayout; -import java.util.ArrayList; import java.util.List; import javax.swing.*; import docking.util.AnimatedIcon; -import resources.ResourceManager; +import generic.theme.GIcon; /** * Panel that displays an animation of a spinning hourglass */ public class HourglassAnimationPanel extends JPanel { + //@formatter:off + private static final List ICONS = List.of( + new GIcon("icon.task.progress.hourglass.1"), + new GIcon("icon.task.progress.hourglass.2"), + new GIcon("icon.task.progress.hourglass.2"), + new GIcon("icon.task.progress.hourglass.3"), + new GIcon("icon.task.progress.hourglass.3"), + new GIcon("icon.task.progress.hourglass.4"), + new GIcon("icon.task.progress.hourglass.4"), + new GIcon("icon.task.progress.hourglass.5"), + new GIcon("icon.task.progress.hourglass.5"), + new GIcon("icon.task.progress.hourglass.6"), + new GIcon("icon.task.progress.hourglass.6"), + new GIcon("icon.task.progress.hourglass.7"), + new GIcon("icon.task.progress.hourglass.7"), + new GIcon("icon.task.progress.hourglass.8"), + new GIcon("icon.task.progress.hourglass.8"), + new GIcon("icon.task.progress.hourglass.9"), + new GIcon("icon.task.progress.hourglass.10"), + new GIcon("icon.task.progress.hourglass.11") + ); + //@formatter:on + public HourglassAnimationPanel() { - setLayout(new BorderLayout()); - - List iconList = new ArrayList<>(); - iconList.add(ResourceManager.loadImage("images/hourglass24_01.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_02.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_02.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_03.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_03.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_04.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_04.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_05.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_05.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_06.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_06.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_07.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_07.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_08.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_08.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_09.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_10.png")); - iconList.add(ResourceManager.loadImage("images/hourglass24_11.png")); - AnimatedIcon progressIcon = new AnimatedIcon(iconList, 150, 0); - + AnimatedIcon progressIcon = new AnimatedIcon(ICONS, 150, 0); add(new JLabel(progressIcon), BorderLayout.NORTH); } } diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java index 7fa2a23752..c4d9cbcfcc 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java @@ -488,7 +488,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { mainContentPanel.add(progressBarPanel, BorderLayout.CENTER); mainContentPanel.add(progressPanel, BorderLayout.EAST); - ImageIcon icon = Icons.STOP_ICON; + Icon icon = Icons.STOP_ICON; cancelButton = new EmptyBorderButton(icon); cancelButton.setName("CANCEL_TASK"); diff --git a/Ghidra/Framework/Project/src/main/resources/images/check.png b/Ghidra/Framework/Docking/src/main/resources/images/check.png similarity index 100% rename from Ghidra/Framework/Project/src/main/resources/images/check.png rename to Ghidra/Framework/Docking/src/main/resources/images/check.png diff --git a/Ghidra/Features/Base/src/main/resources/images/collapse.gif b/Ghidra/Framework/Docking/src/main/resources/images/collapse.gif similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/collapse.gif rename to Ghidra/Framework/Docking/src/main/resources/images/collapse.gif diff --git a/Ghidra/Framework/Docking/src/main/resources/images/dialog-cancel.png b/Ghidra/Framework/Docking/src/main/resources/images/dialog-cancel.png deleted file mode 100644 index 45f8949bfe..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/resources/images/dialog-cancel.png and /dev/null differ diff --git a/Ghidra/Features/Base/src/main/resources/images/famfamfam_silk_icons_v013/drive.png b/Ghidra/Framework/Docking/src/main/resources/images/drive.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/famfamfam_silk_icons_v013/drive.png rename to Ghidra/Framework/Docking/src/main/resources/images/drive.png diff --git a/Ghidra/Features/Base/src/main/resources/images/expand.gif b/Ghidra/Framework/Docking/src/main/resources/images/expand.gif similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/expand.gif rename to Ghidra/Framework/Docking/src/main/resources/images/expand.gif diff --git a/Ghidra/Features/Base/src/main/resources/images/list-remove.png b/Ghidra/Framework/Docking/src/main/resources/images/list-remove.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/list-remove.png rename to Ghidra/Framework/Docking/src/main/resources/images/list-remove.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/mail-folder-outbox.png b/Ghidra/Framework/Docking/src/main/resources/images/mail-folder-outbox.png new file mode 100644 index 0000000000..63bc71b87c Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/resources/images/mail-folder-outbox.png differ diff --git a/Ghidra/Framework/Docking/src/main/resources/images/mail-receive.png b/Ghidra/Framework/Docking/src/main/resources/images/mail-receive.png new file mode 100644 index 0000000000..ea9eac679f Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/resources/images/mail-receive.png differ diff --git a/Ghidra/Features/Base/src/main/resources/images/play.png b/Ghidra/Framework/Docking/src/main/resources/images/play.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/play.png rename to Ghidra/Framework/Docking/src/main/resources/images/play.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/redo.png b/Ghidra/Framework/Docking/src/main/resources/images/redo.png index 88035efeec..5d6121b821 100644 Binary files a/Ghidra/Framework/Docking/src/main/resources/images/redo.png and b/Ghidra/Framework/Docking/src/main/resources/images/redo.png differ diff --git a/Ghidra/Framework/Docking/src/main/resources/images/reload.png b/Ghidra/Framework/Docking/src/main/resources/images/reload.png deleted file mode 100644 index 1c026d32c3..0000000000 Binary files a/Ghidra/Framework/Docking/src/main/resources/images/reload.png and /dev/null differ diff --git a/Ghidra/Framework/Docking/src/main/resources/images/tag.png b/Ghidra/Framework/Docking/src/main/resources/images/tag.png new file mode 100644 index 0000000000..e093032a77 Binary files /dev/null and b/Ghidra/Framework/Docking/src/main/resources/images/tag.png differ diff --git a/Ghidra/Features/Base/src/main/resources/images/text_lowercase.png b/Ghidra/Framework/Docking/src/main/resources/images/text_lowercase.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/text_lowercase.png rename to Ghidra/Framework/Docking/src/main/resources/images/text_lowercase.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/undo.png b/Ghidra/Framework/Docking/src/main/resources/images/undo.png index edd57f5c15..ee410a9048 100644 Binary files a/Ghidra/Framework/Docking/src/main/resources/images/undo.png and b/Ghidra/Framework/Docking/src/main/resources/images/undo.png differ diff --git a/Ghidra/Features/Base/src/main/resources/images/zoom.png b/Ghidra/Framework/Docking/src/main/resources/images/zoom.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/zoom.png rename to Ghidra/Framework/Docking/src/main/resources/images/zoom.png diff --git a/Ghidra/Features/Base/src/main/resources/images/zoom_in.png b/Ghidra/Framework/Docking/src/main/resources/images/zoom_in.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/zoom_in.png rename to Ghidra/Framework/Docking/src/main/resources/images/zoom_in.png diff --git a/Ghidra/Features/Base/src/main/resources/images/zoom_out.png b/Ghidra/Framework/Docking/src/main/resources/images/zoom_out.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/zoom_out.png rename to Ghidra/Framework/Docking/src/main/resources/images/zoom_out.png diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filter/FilterTextFieldTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filter/FilterTextFieldTest.java index dac917f9d2..f03e18c280 100644 --- a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filter/FilterTextFieldTest.java +++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filter/FilterTextFieldTest.java @@ -15,10 +15,9 @@ */ package docking.widgets.filter; -import static docking.test.AbstractDockingTest.triggerEnter; -import static docking.test.AbstractDockingTest.triggerKey; -import static generic.test.AbstractGTest.sleep; -import static generic.test.AbstractGenericTest.runSwing; +import static docking.test.AbstractDockingTest.*; +import static generic.test.AbstractGTest.*; +import static generic.test.AbstractGenericTest.*; import static org.junit.Assert.*; import java.awt.BorderLayout; @@ -32,6 +31,7 @@ import javax.swing.*; import org.junit.Before; import org.junit.Test; +import generic.test.AbstractGTest; import generic.test.AbstractGenericTest; import utility.function.Callback; @@ -291,7 +291,7 @@ public class FilterTextFieldTest { private void waitForTimer() { Timer timer = filter.getFlashTimer(); - AbstractGenericTest.waitForCondition(() -> { + AbstractGTest.waitForCondition(() -> { boolean running = runSwing(() -> timer.isRunning()); return !running; }, "Timed-out waiting for flash timer to finish"); diff --git a/Ghidra/Framework/Docking/src/test/java/docking/theme/gui/ThemeUtilsTest.java b/Ghidra/Framework/Docking/src/test/java/docking/theme/gui/ThemeUtilsTest.java new file mode 100644 index 0000000000..6d207d7bec --- /dev/null +++ b/Ghidra/Framework/Docking/src/test/java/docking/theme/gui/ThemeUtilsTest.java @@ -0,0 +1,258 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package docking.theme.gui; + +import static org.junit.Assert.*; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.text.ParseException; +import java.util.List; +import java.util.Set; + +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Test; + +import docking.test.AbstractDockingTest; +import docking.widgets.OptionDialog; +import docking.widgets.SelectFromListDialog; +import docking.widgets.dialogs.InputDialog; +import generic.theme.*; +import generic.theme.GThemeDefaults.Colors.Palette; +import generic.theme.builtin.MetalTheme; +import generic.theme.builtin.NimbusTheme; + +public class ThemeUtilsTest extends AbstractDockingTest { + + private Color testColor = Palette.RED; + private ThemeManager themeManager; + + @Before + public void setup() { + themeManager = ThemeManager.getInstance(); + GTheme nimbusTheme = new NimbusTheme(); + GTheme metalTheme = new MetalTheme(); + themeManager.addTheme(nimbusTheme); + themeManager.addTheme(metalTheme); + themeManager.setTheme(nimbusTheme); + + // get rid of any leftover imported themes from previous tests + Set allThemes = themeManager.getAllThemes(); + for (GTheme theme : allThemes) { + if (!(theme instanceof DiscoverableGTheme)) { + themeManager.deleteTheme(theme); + } + } + } + + @Test + public void testImportThemeNonZip() throws IOException { + assertEquals("Nimbus Theme", themeManager.getActiveTheme().getName()); + File themeFile = createThemeFile("Bob"); + ThemeUtils.importTheme(themeManager, themeFile); + assertEquals("Bob", themeManager.getActiveTheme().getName()); + + } + + @Test + public void testImportThemeFromZip() throws IOException { + assertEquals("Nimbus Theme", themeManager.getActiveTheme().getName()); + File themeFile = createZipThemeFile("zippy"); + ThemeUtils.importTheme(themeManager, themeFile); + assertEquals("zippy", themeManager.getActiveTheme().getName()); + } + + @Test + public void testImportThemeWithCurrentChangesCancelled() throws IOException { + assertEquals("Nimbus Theme", themeManager.getActiveTheme().getName()); + themeManager.setColor("Panel.background", testColor); + assertTrue(themeManager.hasThemeChanges()); + + File themeFile = createThemeFile("Bob"); + runSwingLater(() -> ThemeUtils.importTheme(themeManager, themeFile)); + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); + assertNotNull(dialog); + assertEquals("Save Theme Changes?", dialog.getTitle()); + pressButtonByText(dialog, "Cancel"); + waitForSwing(); + assertEquals("Nimbus Theme", themeManager.getActiveTheme().getName()); + } + + @Test + public void testImportThemeWithCurrentChangesSaved() throws IOException { + assertEquals("Nimbus Theme", themeManager.getActiveTheme().getName()); + + // make a change in the current theme, so you get asked to save + themeManager.setColor("Panel.background", testColor); + assertTrue(themeManager.hasThemeChanges()); + + File themeFile = createThemeFile("Bob"); + runSwingLater(() -> ThemeUtils.importTheme(themeManager, themeFile)); + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); + assertNotNull(dialog); + assertEquals("Save Theme Changes?", dialog.getTitle()); + pressButtonByText(dialog, "Yes"); + InputDialog inputDialog = waitForDialogComponent(InputDialog.class); + assertNotNull(inputDialog); + runSwing(() -> inputDialog.setValue("Joe")); + pressButtonByText(inputDialog, "OK"); + waitForSwing(); + assertEquals("Bob", themeManager.getActiveTheme().getName()); + assertNotNull(themeManager.getTheme("Joe")); + } + + @Test + public void testImportThemeWithCurrentChangesThrownAway() throws IOException { + assertEquals("Nimbus Theme", themeManager.getActiveTheme().getName()); + + // make a change in the current theme, so you get asked to save + themeManager.setColor("Panel.background", testColor); + assertTrue(themeManager.hasThemeChanges()); + + File bobThemeFile = createThemeFile("Bob"); + runSwingLater(() -> ThemeUtils.importTheme(themeManager, bobThemeFile)); + + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); + assertNotNull(dialog); + assertEquals("Save Theme Changes?", dialog.getTitle()); + pressButtonByText(dialog, "No"); + waitForSwing(); + assertEquals("Bob", themeManager.getActiveTheme().getName()); + } + + @Test + public void testExportThemeAsZip() throws IOException { + runSwingLater(() -> ThemeUtils.exportTheme(themeManager)); + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); + pressButtonByText(dialog, "Export Zip"); + ExportThemeDialog exportDialog = waitForDialogComponent(ExportThemeDialog.class); + File exportFile = createTempFile("whatever", ".theme.zip"); + runSwing(() -> exportDialog.setOutputFile(exportFile)); + pressButtonByText(exportDialog, "OK"); + waitForSwing(); + assertTrue(exportFile.exists()); + GTheme zipTheme = GTheme.loadTheme(exportFile); + assertEquals("Nimbus Theme", zipTheme.getName()); + } + + @Test + public void testExportThemeAsFile() throws IOException { + runSwingLater(() -> ThemeUtils.exportTheme(themeManager)); + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); + pressButtonByText(dialog, "Export File"); + ExportThemeDialog exportDialog = waitForDialogComponent(ExportThemeDialog.class); + File exportFile = createTempFile("whatever", ".theme"); + runSwing(() -> exportDialog.setOutputFile(exportFile)); + pressButtonByText(exportDialog, "OK"); + waitForSwing(); + assertTrue(exportFile.exists()); + GTheme fileTheme = GTheme.loadTheme(exportFile); + assertEquals("Nimbus Theme", fileTheme.getName()); + } + + @Test + public void testDeleteTheme() throws IOException { + File themeFile = createThemeFile("Bob"); + ThemeUtils.importTheme(themeManager, themeFile); + themeFile = createThemeFile("Joe"); + ThemeUtils.importTheme(themeManager, themeFile); + themeFile = createThemeFile("Lisa"); + ThemeUtils.importTheme(themeManager, themeFile); + + assertNotNull(themeManager.getTheme("Bob")); + assertNotNull(themeManager.getTheme("Joe")); + assertNotNull(themeManager.getTheme("Lisa")); + + runSwingLater(() -> ThemeUtils.deleteTheme(themeManager)); + @SuppressWarnings("unchecked") + SelectFromListDialog dialog = waitForDialogComponent(SelectFromListDialog.class); + runSwing(() -> dialog.setSelectedObject(themeManager.getTheme("Bob"))); + pressButtonByText(dialog, "OK"); + + OptionDialog optionDialog = waitForDialogComponent(OptionDialog.class); + pressButtonByText(optionDialog, "Yes"); + waitForSwing(); + + assertNotNull(themeManager.getTheme("Bob")); + assertNull(themeManager.getTheme("Joe")); + assertNotNull(themeManager.getTheme("Lisa")); + + } + + @Test + public void testParseGroupings() throws ParseException { + String source = "(ab (cd))(ef)(( gh))"; + List results = ThemeValueUtils.parseGroupings(source, '(', ')'); + assertEquals(3, results.size()); + assertEquals("ab (cd)", results.get(0)); + assertEquals("ef", results.get(1)); + assertEquals("( gh)", results.get(2)); + } + + @Test + public void testParseGroupingsWithUnbalancedGroups() { + String source = "(ab (cd))(ef)( gh))"; // note the groupings are unbalanced + try { + ThemeValueUtils.parseGroupings(source, '(', ')'); + fail("Expected parse Exception"); + } + catch (ParseException e) { + //expected + } + } + + @Test + public void testParseGroupingsWhenNoGroupingsExist() { + String source = "xx yy"; // note there are no grouping chars + try { + ThemeValueUtils.parseGroupings(source, '(', ')'); + fail("Expected parse Exception"); + } + catch (ParseException e) { + // expected + } + } + + private File createZipThemeFile(String themeName) throws IOException { + File file = createTempFile("Test_Theme", ".theme.zip"); + GTheme outputTheme = new GTheme(file, themeName, LafType.METAL, false); + outputTheme.addColor(new ColorValue("Panel.Background", testColor)); + new ThemeWriter(outputTheme).writeThemeToZipFile(file); + return file; + } + + private File createThemeFile(String themeName) throws IOException { + String themeData = createThemeDataString(themeName); + File file = createTempFile("Test_Theme", ".theme"); + FileUtils.writeStringToFile(file, themeData, Charset.defaultCharset()); + return file; + } + + private String createThemeDataString(String themeName) { + String themeData = """ + name = THEMENAME + lookAndFeel = Metal + useDarkDefaults = false + [color]Panel.background = #ffcccc + """; + + return themeData.replace("THEMENAME", themeName); + } + +} diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AttributedStringTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AttributedStringTest.java index 139f71623e..682abf7006 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AttributedStringTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AttributedStringTest.java @@ -15,7 +15,7 @@ */ package docking.widgets.fieldpanel; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.awt.*; @@ -24,6 +24,7 @@ import org.junit.Test; import docking.widgets.fieldpanel.field.*; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class AttributedStringTest extends AbstractGenericTest { FontMetrics fm; @@ -45,14 +46,16 @@ public class AttributedStringTest extends AbstractGenericTest { public void testSubstring() { FieldElement[] strings = new FieldElement[] { - new TextFieldElement(new AttributedString("This is string", Color.BLACK, fm), 0, 0), // 14 chars - new TextFieldElement(new AttributedString("to test", Color.RED, fm), 0, 0), // 7 chars - new TextFieldElement(new AttributedString("the substring of ", Color.BLACK, fm), 0, + new TextFieldElement(new AttributedString("This is string", Palette.BLACK, fm), 0, + 0), // 14 chars + new TextFieldElement(new AttributedString("to test", Palette.RED, fm), 0, 0), // 7 chars + new TextFieldElement(new AttributedString("the substring of ", Palette.BLACK, fm), + 0, 0), // 17 chars - new TextFieldElement(new AttributedString(" .... ", Color.BLACK, fm), 0, 0), // 8 chars + new TextFieldElement(new AttributedString(" .... ", Palette.BLACK, fm), 0, 0), // 8 chars new TextFieldElement( - new AttributedString("the CompositeAttributedString", Color.BLUE, fm), 0, 0), // 29 chars - new TextFieldElement(new AttributedString("class.", Color.BLACK, fm), 0, 0) }; + new AttributedString("the CompositeAttributedString", Palette.BLUE, fm), 0, 0), // 29 chars + new TextFieldElement(new AttributedString("class.", Palette.BLACK, fm), 0, 0) }; FieldElement compositeString = new CompositeFieldElement(strings); FieldElement substring = compositeString.substring(0); @@ -83,18 +86,21 @@ public class AttributedStringTest extends AbstractGenericTest { // runtime ArrayIndexOutOfBoundsException 7/11/06 strings = new FieldElement[] { new TextFieldElement( - new AttributedString("This is an annotated comment: ", Color.BLUE, fm), 0, 0), - new TextFieldElement(new AttributedString("RegSetValueExW", Color.BLUE, fm), 0, 0), + new AttributedString("This is an annotated comment: ", Palette.BLUE, fm), 0, 0), + new TextFieldElement(new AttributedString("RegSetValueExW", Palette.BLUE, fm), 0, 0), new TextFieldElement(new AttributedString( - " This is an annotated comment with symbol name: ", Color.RED, fm), 0, 0), - new TextFieldElement(new AttributedString("No symbol: RegSetValueExW", Color.RED, fm), + " This is an annotated comment with symbol name: ", Palette.RED, fm), 0, 0), + new TextFieldElement(new AttributedString("No symbol: RegSetValueExW", Palette.RED, fm), 0, 0), - new TextFieldElement(new AttributedString(" Bad annotation: ", Color.BLUE, fm), 0, 0), + new TextFieldElement(new AttributedString(" Bad annotation: ", Palette.BLUE, fm), 0, + 0), new TextFieldElement( - new AttributedString("Invalid Annotation: {@cowhide smile}:", Color.RED, fm), 0, 0), - new TextFieldElement(new AttributedString(" ", Color.BLUE, fm), 0, 0), - new TextFieldElement(new AttributedString("{@cowhide smile}", Color.BLUE, fm), 0, 0), - new TextFieldElement(new AttributedString("Invalid Annotation: {@sym}", Color.BLUE, fm), + new AttributedString("Invalid Annotation: {@cowhide smile}:", Palette.RED, fm), 0, + 0), + new TextFieldElement(new AttributedString(" ", Palette.BLUE, fm), 0, 0), + new TextFieldElement(new AttributedString("{@cowhide smile}", Palette.BLUE, fm), 0, 0), + new TextFieldElement( + new AttributedString("Invalid Annotation: {@sym}", Palette.BLUE, fm), 0, 0) }; FieldElement compositeString2 = new CompositeFieldElement(strings); diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/ColorRangeMapTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/ColorRangeMapTest.java index 625d8bdd47..21a9123f91 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/ColorRangeMapTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/ColorRangeMapTest.java @@ -15,14 +15,11 @@ */ package docking.widgets.fieldpanel; -import static org.junit.Assert.assertEquals; - -import java.awt.Color; - import org.junit.Test; import docking.widgets.fieldpanel.internal.ColorRangeMap; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class ColorRangeMapTest extends AbstractGenericTest { public ColorRangeMapTest() { @@ -32,31 +29,31 @@ public class ColorRangeMapTest extends AbstractGenericTest { @Test public void testPaint1() { ColorRangeMap map = new ColorRangeMap(); - map.color(10, 10, Color.BLUE); - assertEquals(Color.WHITE, map.getColor(0, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(9, Color.WHITE)); - assertEquals(Color.BLUE, map.getColor(10, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(11, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(100, Color.WHITE)); + map.color(10, 10, Palette.BLUE); + assertColorsEqual(Palette.WHITE, map.getColor(0, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(9, Palette.WHITE)); + assertColorsEqual(Palette.BLUE, map.getColor(10, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(11, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(100, Palette.WHITE)); } @Test public void testCopy() { ColorRangeMap map = new ColorRangeMap(); - map.color(10, 10, Color.BLUE); - assertEquals(Color.WHITE, map.getColor(0, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(9, Color.WHITE)); - assertEquals(Color.BLUE, map.getColor(10, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(11, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(100, Color.WHITE)); + map.color(10, 10, Palette.BLUE); + assertColorsEqual(Palette.WHITE, map.getColor(0, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(9, Palette.WHITE)); + assertColorsEqual(Palette.BLUE, map.getColor(10, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(11, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(100, Palette.WHITE)); map = map.copy(); - assertEquals(Color.WHITE, map.getColor(0, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(9, Color.WHITE)); - assertEquals(Color.BLUE, map.getColor(10, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(11, Color.WHITE)); - assertEquals(Color.WHITE, map.getColor(100, Color.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(0, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(9, Palette.WHITE)); + assertColorsEqual(Palette.BLUE, map.getColor(10, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(11, Palette.WHITE)); + assertColorsEqual(Palette.WHITE, map.getColor(100, Palette.WHITE)); } } diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java index bdd3486d6a..cb594d1302 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.*; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class FlowLayoutTextFieldTest extends AbstractGenericTest { @@ -39,7 +40,7 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest { public void setUp() throws Exception { HighlightFactory factory = (field, text, cursorTextOffset) -> { - return new Highlight[] { new Highlight(4, 4, Color.YELLOW) }; + return new Highlight[] { new Highlight(4, 4, Palette.YELLOW) }; }; Font font = new Font("Times New Roman", 0, 14); @@ -63,12 +64,12 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest { Wow */ - elements.add(new TextFieldElement(new AttributedString("Hello ", Color.BLUE, fm), 0, 0)); + elements.add(new TextFieldElement(new AttributedString("Hello ", Palette.BLUE, fm), 0, 0)); elements.add(new TextFieldElement( - new AttributedString("World ", Color.RED, fm, true, Color.BLUE), 1, 0)); + new AttributedString("World ", Palette.RED, fm, true, Palette.BLUE), 1, 0)); elements.add( - new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0)); - elements.add(new TextFieldElement(new AttributedString("Wow! ", Color.GRAY, fm), 3, 0)); + new TextFieldElement(new AttributedString(CLIPPED_STRING, Palette.GREEN, fm), 2, 0)); + elements.add(new TextFieldElement(new AttributedString("Wow! ", Palette.GRAY, fm), 3, 0)); textField = new FlowLayoutTextField(elements, 100, 100, 3, factory); } diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java index 018e27d818..269b56ff9d 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.*; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class VerticalLayoutTextFieldTest extends AbstractGenericTest { @@ -39,7 +40,7 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest { public void setUp() throws Exception { HighlightFactory factory = (f, text, cursorTextOffset) -> { - return new Highlight[] { new Highlight(4, 4, Color.YELLOW) }; + return new Highlight[] { new Highlight(4, 4, Palette.YELLOW) }; }; Font font = new Font("Times New Roman", 0, 14); @@ -48,12 +49,12 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest { List elements = new ArrayList<>(); - elements.add(new TextFieldElement(new AttributedString("Hello", Color.BLUE, fm), 0, 0)); + elements.add(new TextFieldElement(new AttributedString("Hello", Palette.BLUE, fm), 0, 0)); elements.add(new TextFieldElement( - new AttributedString("World", Color.RED, fm, true, Color.BLUE), 1, 0)); + new AttributedString("World", Palette.RED, fm, true, Palette.BLUE), 1, 0)); elements.add( - new TextFieldElement(new AttributedString(CLIPPED_STRING, Color.GREEN, fm), 2, 0)); - elements.add(new TextFieldElement(new AttributedString("Wow!", Color.GRAY, fm), 3, 0)); + new TextFieldElement(new AttributedString(CLIPPED_STRING, Palette.GREEN, fm), 2, 0)); + elements.add(new TextFieldElement(new AttributedString("Wow!", Palette.GRAY, fm), 3, 0)); field = new VerticalLayoutTextField(elements, 100, 100, 5, factory); } diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/field/CompositeVerticalLayoutTextFieldTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/field/CompositeVerticalLayoutTextFieldTest.java index a010350c23..9f74f137e3 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/field/CompositeVerticalLayoutTextFieldTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/field/CompositeVerticalLayoutTextFieldTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import docking.widgets.fieldpanel.support.*; import generic.test.AbstractGenericTest; +import generic.theme.GThemeDefaults.Colors.Palette; public class CompositeVerticalLayoutTextFieldTest extends AbstractGenericTest { @@ -65,7 +66,7 @@ public class CompositeVerticalLayoutTextFieldTest extends AbstractGenericTest { List elements = new ArrayList<>(); int row = 0; for (String line : lines) { - elements.add(createRow(row++, line, Color.BLUE)); + elements.add(createRow(row++, line, Palette.BLUE)); } List fields = new ArrayList<>(); @@ -83,7 +84,7 @@ public class CompositeVerticalLayoutTextFieldTest extends AbstractGenericTest { List elements = new ArrayList<>(); int row = 0; for (String line : lines) { - elements.add(createRow(row++, line, Color.BLUE)); + elements.add(createRow(row++, line, Palette.BLUE)); } List fields = new ArrayList<>(); @@ -114,12 +115,12 @@ public class CompositeVerticalLayoutTextFieldTest extends AbstractGenericTest { } private TextField wrappedField(int row, String text) { - FieldElement element = createRow(row, text, Color.BLUE); + FieldElement element = createRow(row, text, Palette.BLUE); return new WrappingVerticalLayoutTextField(element, startX, width, maxLines, hlFactory); } private TextField clippedField(int row, String text) { - FieldElement element = createRow(row, text, Color.BLUE); + FieldElement element = createRow(row, text, Palette.BLUE); return new ClippingTextField(startX, width, element, hlFactory); } diff --git a/Ghidra/Framework/Generic/Module.manifest b/Ghidra/Framework/Generic/Module.manifest index 830f7b173e..0533366caf 100644 --- a/Ghidra/Framework/Generic/Module.manifest +++ b/Ghidra/Framework/Generic/Module.manifest @@ -10,3 +10,4 @@ MODULE FILE LICENSE: lib/gson-2.9.0.jar Apache License 2.0 MODULE FILE LICENSE: lib/bcpkix-jdk15on-1.69.jar Bouncy Castle License MODULE FILE LICENSE: lib/bcprov-jdk15on-1.69.jar Bouncy Castle License MODULE FILE LICENSE: lib/bcutil-jdk15on-1.69.jar Bouncy Castle License +MODULE FILE LICENSE: lib/flatlaf-2.6.jar Apache License 2.0 diff --git a/Ghidra/Framework/Generic/build.gradle b/Ghidra/Framework/Generic/build.gradle index 32166290ae..f7d479cf69 100644 --- a/Ghidra/Framework/Generic/build.gradle +++ b/Ghidra/Framework/Generic/build.gradle @@ -38,6 +38,8 @@ dependencies { api 'org.bouncycastle:bcpkix-jdk15on:1.69' // requires bcutil and bcprov api 'org.bouncycastle:bcprov-jdk15on:1.69' api 'org.bouncycastle:bcutil-jdk15on:1.69' + api 'com.formdev:flatlaf:2.6' + compileOnly "junit:junit:4.12" } diff --git a/Ghidra/Framework/Generic/certification.manifest b/Ghidra/Framework/Generic/certification.manifest index d3ec09979e..681485db8d 100644 --- a/Ghidra/Framework/Generic/certification.manifest +++ b/Ghidra/Framework/Generic/certification.manifest @@ -13,6 +13,7 @@ .gitignore||GHIDRA||||END| Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/generic.theme.properties||GHIDRA||||END| src/main/java/ghidra/framework/options/package.html||GHIDRA||||END| src/main/java/ghidra/util/datastruct/package.html||GHIDRA||||END| src/main/java/ghidra/util/graph/attributes/package.html||GHIDRA||||END| @@ -24,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| @@ -35,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| diff --git a/Ghidra/Framework/Generic/data/generic.theme.properties b/Ghidra/Framework/Generic/data/generic.theme.properties new file mode 100644 index 0000000000..8db3c102fb --- /dev/null +++ b/Ghidra/Framework/Generic/data/generic.theme.properties @@ -0,0 +1,71 @@ +[Defaults] + +// Fonts +font.standard = [font]Panel.font +font.bold = font.standard[bold] +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 = edit-delete.png +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] \ No newline at end of file diff --git a/Ghidra/Framework/Generic/src/main/java/generic/test/AbstractGenericTest.java b/Ghidra/Framework/Generic/src/main/java/generic/test/AbstractGenericTest.java index a630722b7d..5d052c3e20 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/test/AbstractGenericTest.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/test/AbstractGenericTest.java @@ -45,6 +45,8 @@ 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; import ghidra.framework.Application; @@ -55,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; @@ -1584,7 +1587,7 @@ public abstract class AbstractGenericTest extends AbstractGTest { } }); // Fix up the default fonts that Java 1.5.0 changed to Courier, which looked terrible. - Font f = new Font("Monospaced", Font.PLAIN, 12); + Font f = Gui.getFont("font.monospaced"); UIManager.put("PasswordField.font", f); UIManager.put("TextArea.font", f); } @@ -2049,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; + } + } diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/AbstractThemeReader.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/AbstractThemeReader.java new file mode 100644 index 0000000000..a6b7bbfc63 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/AbstractThemeReader.java @@ -0,0 +1,307 @@ +/* ### + * 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 generic.theme; + +import java.io.*; +import java.text.ParseException; +import java.util.*; + +import ghidra.util.Msg; + +/** + * Abstract base class for reading theme values either in sections (theme property files) or no + * sections (theme files) + */ +public abstract class AbstractThemeReader { + + private static final String NO_SECTION = "[No Section]"; + private static final String DEFAULTS = "[Defaults]"; + private static final String DARK_DEFAULTS = "[Dark Defaults]"; + + private List errors = new ArrayList<>(); + protected String source; + + protected AbstractThemeReader(String source) { + this.source = source; + } + + /** + * Returns a list of errors found while parsing + * @return a list of errors found while parsing + */ + public List getErrors() { + return errors; + } + + protected void read(Reader reader) throws IOException { + List

sections = readSections(new LineNumberReader(reader)); + for (Section section : sections) { + switch (section.getName()) { + case NO_SECTION: + processNoSection(section); + break; + case DEFAULTS: + processDefaultSection(section); + break; + case DARK_DEFAULTS: + processDarkDefaultSection(section); + break; + default: + error(section.getLineNumber(), + "Encounded unknown theme file section: " + section.getName()); + } + } + + } + + protected abstract void processNoSection(Section section) throws IOException; + + protected abstract void processDefaultSection(Section section) throws IOException; + + protected abstract void processDarkDefaultSection(Section section) throws IOException; + + protected void processValues(GThemeValueMap valueMap, Section section) { + for (String key : section.getKeys()) { + String value = section.getValue(key); + int lineNumber = section.getLineNumber(key); + if (ColorValue.isColorKey(key)) { + ColorValue colorValue = parseColorProperty(key, value, lineNumber); + ColorValue oldValue = valueMap.addColor(colorValue); + reportDuplicateKey(oldValue, lineNumber); + } + else if (FontValue.isFontKey(key)) { + FontValue oldValue = valueMap.addFont(parseFontProperty(key, value, lineNumber)); + reportDuplicateKey(oldValue, lineNumber); + } + else if (IconValue.isIconKey(key)) { + if (!GTheme.JAVA_ICON.equals(value)) { + IconValue oldValue = + valueMap.addIcon(parseIconProperty(key, value, lineNumber)); + reportDuplicateKey(oldValue, lineNumber); + } + } + else { + error(lineNumber, "Can't process property: " + key + " = " + value); + } + } + } + + private void reportDuplicateKey(ThemeValue oldValue, int lineNumber) { + if (oldValue != null) { + error(lineNumber, "Duplicate id found: \"" + oldValue.getId() + "\""); + } + } + + private IconValue parseIconProperty(String key, String value, int lineNumber) { + try { + IconValue parsedValue = IconValue.parse(key, value); + if (parsedValue == null) { + error(lineNumber, "Could not parse Icon value: " + value); + } + return parsedValue; + } + catch (ParseException e) { + error(lineNumber, + "Could not parse Icon value: \"" + value + "\" because: " + e.getMessage()); + } + return null; + } + + private FontValue parseFontProperty(String key, String value, int lineNumber) { + try { + FontValue parsedValue = FontValue.parse(key, value); + if (parsedValue == null) { + error(lineNumber, "Could not parse Font value: " + value); + } + return parsedValue; + } + catch (Exception e) { + error(lineNumber, "Could not parse Font value: " + value + "because " + e.getMessage()); + } + return null; + } + + private ColorValue parseColorProperty(String key, String value, int lineNumber) { + ColorValue parsedValue = ColorValue.parse(key, value); + if (parsedValue == null) { + error(lineNumber, "Could not parse Color value: " + value); + } + return parsedValue; + } + + private List
readSections(LineNumberReader reader) throws IOException { + + List
sections = new ArrayList<>(); + Section currentSection = new Section(NO_SECTION, 0); + sections.add(currentSection); + + String line; + while ((line = reader.readLine()) != null) { + line = removeComments(line); + + if (line.isBlank()) { + continue; + } + + if (isSectionHeader(line)) { + currentSection = new Section(line, reader.getLineNumber()); + sections.add(currentSection); + } + else { + currentSection.add(line, reader.getLineNumber()); + } + } + + return sections; + } + + private String removeComments(String line) { + // remove any trailing comment on line + int commentIndex = line.indexOf("//"); + if (commentIndex >= 0) { + line = line.substring(0, commentIndex); + } + line = line.trim(); + + // clear line if entire line is comment + if (line.startsWith("#")) { + return ""; + } + return line; + } + + private boolean isSectionHeader(String line) { + return line.startsWith("[") && line.endsWith("]"); + } + + protected void error(int lineNumber, String message) { + String msg = + "Error parsing theme file \"" + source + "\" at line: " + lineNumber + ", " + message; + errors.add(msg); + Msg.error(this, msg); + } + + /** + * Represents all the value found in a section of the theme properties file. Sections are + * defined by a line containing just "[section name]" + */ + protected class Section { + + private String name; + private Map properties = new HashMap<>(); + private Map lineNumbers = new HashMap<>(); + private int startLineNumber; + + /** + * Constructor sectionName the section name + * @param sectionName the name of this section + * @param lineNumber the line number in the file where the section started + */ + public Section(String sectionName, int lineNumber) { + this.name = sectionName; + this.startLineNumber = lineNumber; + } + + /** + * Removes the value with the given key + * @param key the key to remove + */ + public void remove(String key) { + properties.remove(key); + } + + /** + * Returns the value for the given key. + * @param key the key to get a value for + * @return the value for the given key + */ + public String getValue(String key) { + return properties.get(key); + } + + /** + * Returns a set of all keys in the section + * @return a set of all keys in the section + */ + public Set getKeys() { + return properties.keySet(); + } + + /** + * Returns the line number in the original file where the key was parsed + * @param key the key to get a line number for + * @return the line number in the original file where the key was parsed + */ + public int getLineNumber(String key) { + return lineNumbers.get(key); + } + + /** + * Returns true if the section is empty. + * @return true if the section is empty. + */ + public boolean isEmpty() { + return properties.isEmpty(); + } + + /** + * Returns the line number in the file where this section began. + * @return the line number in the file where this section began. + */ + public int getLineNumber() { + return startLineNumber; + } + + /** + * Returns the name of this section + * @return the name of this section + */ + public String getName() { + return name; + } + + /** + * Adds a raw line from the file to this section. The line will be parsed into a a + * key-value pair. + * @param line the line to be added/parsed + * @param lineNumber the line number in the file for this line + */ + public void add(String line, int lineNumber) { + int splitIndex = line.indexOf('='); + if (splitIndex < 0) { + error(lineNumber, "Missing required \"=\" for propery line: \"" + line + "\""); + return; + } + String key = line.substring(0, splitIndex).trim(); + String value = line.substring(splitIndex + 1, line.length()).trim(); + if (key.isBlank()) { + error(lineNumber, "Missing key for propery line: \"" + line + "\""); + return; + } + if (value.isBlank()) { + error(lineNumber, "Missing value for propery line: \"" + line + "\""); + return; + } + if (properties.containsKey(key)) { + error(lineNumber, "Duplicate key found in this file!: " + key + "\""); + return; + } + properties.put(key, value); + lineNumbers.put(key, lineNumber); + + } + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/AllValuesChangedThemeEvent.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/AllValuesChangedThemeEvent.java new file mode 100644 index 0000000000..d4e64c0a19 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/AllValuesChangedThemeEvent.java @@ -0,0 +1,76 @@ +/* ### + * 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 generic.theme; + +import javax.swing.LookAndFeel; + +/** + * {@link ThemeEvent} for when a new theme is set or the current theme is reset to its original + * values. + */ +public class AllValuesChangedThemeEvent extends ThemeEvent { + + private boolean lookAndFeelChanged; + + /** + * Constructor + * @param lookAndFeelChanged true if the overall theme was changed which may have caused the + * {@link LookAndFeel} to change + */ + public AllValuesChangedThemeEvent(boolean lookAndFeelChanged) { + this.lookAndFeelChanged = lookAndFeelChanged; + } + + @Override + public boolean isColorChanged(String id) { + return true; + } + + @Override + public boolean isFontChanged(String id) { + return true; + } + + @Override + public boolean isIconChanged(String id) { + return true; + } + + @Override + public boolean isLookAndFeelChanged() { + return lookAndFeelChanged; + } + + @Override + public boolean haveAllValuesChanged() { + return true; + } + + @Override + public boolean hasAnyColorChanged() { + return true; + } + + @Override + public boolean hasAnyFontChanged() { + return true; + } + + @Override + public boolean hasAnyIconChanged() { + return true; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ApplicationThemeManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ApplicationThemeManager.java new file mode 100644 index 0000000000..6e07ea273c --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ApplicationThemeManager.java @@ -0,0 +1,484 @@ +/* ### + * 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 generic.theme; + +import java.awt.Component; +import java.io.File; +import java.util.*; + +import javax.swing.*; +import javax.swing.plaf.ComponentUI; + +import com.formdev.flatlaf.FlatDarkLaf; +import com.formdev.flatlaf.FlatLightLaf; + +import generic.theme.laf.LookAndFeelManager; +import ghidra.util.Msg; +import ghidra.util.classfinder.ClassSearcher; + +/** + * This is the fully functional {@link ThemeManager} that manages themes in a application. To + * activate the theme functionality, Applications (or tests) must call + * {@link ApplicationThemeManager#initialize()} + */ +public class ApplicationThemeManager extends ThemeManager { + private GTheme activeTheme = getDefaultTheme(); + private Set allThemes = null; + + private GThemeValueMap applicationDefaults = new GThemeValueMap(); + private GThemeValueMap applicationDarkDefaults = new GThemeValueMap(); + private GThemeValueMap javaDefaults = new GThemeValueMap(); + private GThemeValueMap systemValues = new GThemeValueMap(); + + protected ThemeFileLoader themeFileLoader = new ThemeFileLoader(); + protected ThemePreferences themePreferences = new ThemePreferences(); + + private Map gColorMap = new HashMap<>(); + private Map gIconMap = new HashMap<>(); + + // stores the original value for ids whose value has changed from the current theme + private GThemeValueMap changedValuesMap = new GThemeValueMap(); + protected LookAndFeelManager lookAndFeelManager; + + /** + * Initialized the Theme and its values for the application. + */ + public static void initialize() { + if (INSTANCE instanceof ApplicationThemeManager) { + Msg.error(ThemeManager.class, "Attempted to initialize theming more than once!"); + return; + } + + ApplicationThemeManager themeManager = new ApplicationThemeManager(); + themeManager.doInitialize(); + } + + protected ApplicationThemeManager() { + // AppliationThemeManagers always replace any other instances + INSTANCE = this; + installInGui(); + } + + protected void doInitialize() { + installFlatLookAndFeels(); + loadThemeDefaults(); + setTheme(themePreferences.load()); + } + + @Override + public void reloadApplicationDefaults() { + loadThemeDefaults(); + buildCurrentValues(); + lookAndFeelManager.resetAll(javaDefaults); + notifyThemeChanged(new AllValuesChangedThemeEvent(false)); + } + + @Override + public void restoreThemeValues() { + buildCurrentValues(); + lookAndFeelManager.resetAll(javaDefaults); + notifyThemeChanged(new AllValuesChangedThemeEvent(false)); + } + + @Override + public void restoreColor(String id) { + if (changedValuesMap.containsColor(id)) { + setColor(changedValuesMap.getColor(id)); + } + } + + @Override + public void restoreFont(String id) { + if (changedValuesMap.containsFont(id)) { + setFont(changedValuesMap.getFont(id)); + } + } + + @Override + public void restoreIcon(String id) { + if (changedValuesMap.containsIcon(id)) { + setIcon(changedValuesMap.getIcon(id)); + } + } + + @Override + public boolean isChangedColor(String id) { + return changedValuesMap.containsColor(id); + } + + @Override + public boolean isChangedFont(String id) { + return changedValuesMap.containsFont(id); + } + + @Override + public boolean isChangedIcon(String id) { + return changedValuesMap.containsIcon(id); + } + + @Override + public void setTheme(GTheme theme) { + if (theme.hasSupportedLookAndFeel()) { + activeTheme = theme; + LafType lafType = theme.getLookAndFeelType(); + lookAndFeelManager = lafType.getLookAndFeelManager(this); + try { + lookAndFeelManager.installLookAndFeel(); + themePreferences.save(theme); + notifyThemeChanged(new AllValuesChangedThemeEvent(true)); + } + catch (Exception e) { + Msg.error(this, "Error setting LookAndFeel: " + lafType.getName(), e); + } + } + currentValues.checkForUnresolvedReferences(); + } + + @Override + public void addTheme(GTheme newTheme) { + loadThemes(); + allThemes.remove(newTheme); + allThemes.add(newTheme); + } + + @Override + public void deleteTheme(GTheme theme) { + File file = theme.getFile(); + if (file != null) { + file.delete(); + } + if (allThemes != null) { + allThemes.remove(theme); + } + } + + @Override + public Set getAllThemes() { + loadThemes(); + return new HashSet<>(allThemes); + } + + @Override + public Set getSupportedThemes() { + loadThemes(); + Set supported = new HashSet<>(); + for (GTheme theme : allThemes) { + if (theme.hasSupportedLookAndFeel()) { + supported.add(theme); + } + } + return supported; + } + + @Override + public GTheme getActiveTheme() { + return activeTheme; + } + + @Override + public LafType getLookAndFeelType() { + return activeTheme.getLookAndFeelType(); + } + + @Override + public GTheme getTheme(String themeName) { + Optional first = + getAllThemes().stream().filter(t -> t.getName().equals(themeName)).findFirst(); + return first.orElse(null); + } + + @Override + public GThemeValueMap getThemeValues() { + GThemeValueMap map = new GThemeValueMap(); + map.load(javaDefaults); + map.load(systemValues); + map.load(applicationDefaults); + if (activeTheme.useDarkDefaults()) { + map.load(applicationDarkDefaults); + } + map.load(activeTheme); + return map; + } + + @Override + public void setFont(FontValue newValue) { + FontValue currentValue = currentValues.getFont(newValue.getId()); + if (newValue.equals(currentValue)) { + return; + } + updateChangedValuesMap(currentValue, newValue); + + currentValues.addFont(newValue); + notifyThemeChanged(new FontChangedThemeEvent(currentValues, newValue)); + + // update all java LookAndFeel fonts affected by this changed + String id = newValue.getId(); + Set changedFontIds = findChangedJavaFontIds(id); + lookAndFeelManager.fontsChanged(changedFontIds); + } + + @Override + public void setColor(ColorValue newValue) { + ColorValue currentValue = currentValues.getColor(newValue.getId()); + if (newValue.equals(currentValue)) { + return; + } + updateChangedValuesMap(currentValue, newValue); + currentValues.addColor(newValue); + notifyThemeChanged(new ColorChangedThemeEvent(currentValues, newValue)); + + // now update the ui + if (lookAndFeelManager != null) { + lookAndFeelManager.colorsChanged(); + } + } + + @Override + public void setIcon(IconValue newValue) { + IconValue currentValue = currentValues.getIcon(newValue.getId()); + if (newValue.equals(currentValue)) { + return; + } + updateChangedValuesMap(currentValue, newValue); + + currentValues.addIcon(newValue); + notifyThemeChanged(new IconChangedThemeEvent(currentValues, newValue)); + + // now update the ui + // update all java LookAndFeel icons affected by this changed + String id = newValue.getId(); + Set changedIconIds = findChangedJavaIconIds(id); + Icon newIcon = newValue.get(currentValues); + lookAndFeelManager.iconsChanged(changedIconIds, newIcon); + } + + @Override + public GColorUIResource getGColorUiResource(String id) { + GColorUIResource gColor = gColorMap.get(id); + if (gColor == null) { + gColor = new GColorUIResource(id); + gColorMap.put(id, gColor); + } + return gColor; + } + + @Override + public GIconUIResource getGIconUiResource(String id) { + + GIconUIResource gIcon = gIconMap.get(id); + if (gIcon == null) { + gIcon = new GIconUIResource(id); + gIconMap.put(id, gIcon); + } + return gIcon; + } + + @Override + public GThemeValueMap getJavaDefaults() { + GThemeValueMap map = new GThemeValueMap(); + map.load(javaDefaults); + return map; + } + + @Override + public GThemeValueMap getApplicationDarkDefaults() { + GThemeValueMap map = new GThemeValueMap(applicationDefaults); + map.load(applicationDarkDefaults); + return map; + } + + @Override + public GThemeValueMap getApplicationLightDefaults() { + GThemeValueMap map = new GThemeValueMap(applicationDefaults); + return map; + } + + /** + * Returns a {@link GThemeValueMap} containing all default values for the current theme. It + * is a combination of application defined defaults and java {@link LookAndFeel} defaults. + * @return the current set of defaults. + */ + public GThemeValueMap getDefaults() { + GThemeValueMap currentDefaults = new GThemeValueMap(javaDefaults); + currentDefaults.load(systemValues); + currentDefaults.load(applicationDefaults); + if (activeTheme.useDarkDefaults()) { + currentDefaults.load(applicationDarkDefaults); + } + return currentDefaults; + } + + /** + * Sets specially defined system UI values. These values are created by the application as a + * convenience for mapping generic concepts to values that differ by Look and Feel. This allows + * clients to use 'system' properties without knowing the actual Look and Feel terms. + * + *

For example, 'system.color.border' defaults to 'controlShadow', but maps to 'nimbusBorder' + * in the Nimbus Look and Feel. + * + * @param map the map + */ + public void setSystemDefaults(GThemeValueMap map) { + systemValues = map; + } + + /** + * Sets the map of Java default UI values. These are the UI values defined by the current Java + * Look and Feel. + * @param map the default theme values defined by the {@link LookAndFeel} + */ + public void setJavaDefaults(GThemeValueMap map) { + javaDefaults = map; + buildCurrentValues(); + GColor.refreshAll(currentValues); + GIcon.refreshAll(currentValues); + } + + @Override + public boolean isUsingAquaUI(ComponentUI UI) { + return activeTheme.getLookAndFeelType() == LafType.MAC; + } + + @Override + public boolean isUsingNimbusUI() { + return activeTheme.getLookAndFeelType() == LafType.NIMBUS; + } + + @Override + public boolean hasThemeChanges() { + return !changedValuesMap.isEmpty(); + } + + @Override + public void registerFont(Component component, String fontId) { + lookAndFeelManager.registerFont(component, fontId); + } + + public boolean isDarkTheme() { + return activeTheme.useDarkDefaults(); + } + + private void installFlatLookAndFeels() { + UIManager.installLookAndFeel(LafType.FLAT_LIGHT.getName(), FlatLightLaf.class.getName()); + UIManager.installLookAndFeel(LafType.FLAT_DARK.getName(), FlatDarkLaf.class.getName()); + } + + private void loadThemeDefaults() { + themeFileLoader.loadThemeDefaultFiles(); + applicationDefaults = themeFileLoader.getDefaults(); + applicationDarkDefaults = themeFileLoader.getDarkDefaults(); + } + + private void buildCurrentValues() { + GThemeValueMap map = new GThemeValueMap(); + + map.load(javaDefaults); + map.load(systemValues); + map.load(applicationDefaults); + if (activeTheme.useDarkDefaults()) { + map.load(applicationDarkDefaults); + } + map.load(activeTheme); + currentValues = map; + changedValuesMap.clear(); + } + + private void loadThemes() { + if (allThemes == null) { + Set set = new HashSet<>(); + set.addAll(findDiscoverableThemes()); + set.addAll(themeFileLoader.loadThemeFiles()); + allThemes = set; + } + } + + private Collection findDiscoverableThemes() { + return ClassSearcher.getInstances(DiscoverableGTheme.class); + } + + private void updateChangedValuesMap(ColorValue currentValue, ColorValue newValue) { + String id = newValue.getId(); + ColorValue originalValue = changedValuesMap.getColor(id); + + // if new value is original value, it is no longer changed, remove it from changed map + if (newValue.equals(originalValue)) { + changedValuesMap.removeColor(id); + } + else if (originalValue == null) { + // first time changed, so current value is original value + changedValuesMap.addColor(currentValue); + } + } + + private void updateChangedValuesMap(FontValue currentValue, FontValue newValue) { + String id = newValue.getId(); + FontValue originalValue = changedValuesMap.getFont(id); + + // if new value is original value, it is no longer changed, remove it from changed map + if (newValue.equals(originalValue)) { + changedValuesMap.removeFont(id); + } + else if (originalValue == null) { + // first time changed, so current value is original value + changedValuesMap.addFont(currentValue); + } + } + + private void updateChangedValuesMap(IconValue currentValue, IconValue newValue) { + String id = newValue.getId(); + IconValue originalValue = changedValuesMap.getIcon(id); + + // if new value is original value, it is no longer changed, remove it from changed map + if (newValue.equals(originalValue)) { + changedValuesMap.removeIcon(id); + } + else if (originalValue == null) { + // first time changed, so current value is original value + changedValuesMap.addIcon(currentValue); + } + } + + private Set findChangedJavaFontIds(String id) { + Set affectedIds = new HashSet<>(); + List fonts = javaDefaults.getFonts(); + for (FontValue fontValue : fonts) { + String fontId = fontValue.getId(); + FontValue currentFontValue = currentValues.getFont(fontId); + if (fontId.equals(id) || currentFontValue.inheritsFrom(id, currentValues)) { + affectedIds.add(fontId); + } + } + return affectedIds; + } + + private Set findChangedJavaIconIds(String id) { + Set affectedIds = new HashSet<>(); + List icons = javaDefaults.getIcons(); + for (IconValue iconValue : icons) { + String iconId = iconValue.getId(); + if (iconId.equals(id) || iconValue.inheritsFrom(id, currentValues)) { + affectedIds.add(iconId); + } + } + return affectedIds; + } + + public void refreshGThemeValues() { + GColor.refreshAll(currentValues); + GIcon.refreshAll(currentValues); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ColorChangedThemeEvent.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ColorChangedThemeEvent.java new file mode 100644 index 0000000000..4f92124123 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ColorChangedThemeEvent.java @@ -0,0 +1,51 @@ +/* ### + * 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 generic.theme; + +/** + * {@link ThemeEvent} for when a color changes for exactly one color id. + */ +public class ColorChangedThemeEvent extends ThemeEvent { + private final ColorValue color; + private final GThemeValueMap values; + + /** + * Constructor + * @param values the set of theme values used to resolve indirect references + * @param color the new {@link ColorValue} for the color id that changed + */ + public ColorChangedThemeEvent(GThemeValueMap values, ColorValue color) { + this.values = values; + this.color = color; + } + + @Override + public boolean isColorChanged(String id) { + if (id.equals(color.getId())) { + return true; + } + ColorValue testValue = values.getColor(id); + if (testValue == null) { + return false; + } + return testValue.inheritsFrom(color.getId(), values); + } + + @Override + public boolean hasAnyColorChanged() { + return true; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ColorValue.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ColorValue.java new file mode 100644 index 0000000000..9c2fdf0318 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ColorValue.java @@ -0,0 +1,157 @@ +/* ### + * 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 generic.theme; + +import java.awt.Color; + +import ghidra.util.Msg; +import ghidra.util.WebColors; +import utilities.util.reflection.ReflectionUtilities; + +/** + * A class for storing {@link Color} values that have a String id (e.g. color.bg.foo) and either + * a concrete color or a reference id which is the String id of another ColorValue that it + * will inherit its color from. So if this class's color value is non-null, the refId will be null + * and if the class's refId is non-null, then the color value will be null. + */ +public class ColorValue extends ThemeValue { + private static final String COLOR_ID_PREFIX = "color."; + private static final String EXTERNAL_PREFIX = "[color]"; + private static final String SYSTEM_COLOR_PREFIX = "system.color"; + + 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 + * be null. Note: if a {@link GColor} is passed in as the value, then this will be an indirect + * ColorValue that inherits its color from the id stored in the GColor. + * @param id the id for this ColorValue + * @param value the {@link Color} to associate with the given id + */ + public ColorValue(String id, Color value) { + super(id, getRefId(value), getRawColor(value)); + } + + /** + * Constructor used when the ColorValue will inherit its color from another ColorValue. The + * color value field will be null. + * @param id the id for this ColorValue + * @param refId the id of another ColorValue that this ColorValue will inherit from + */ + public ColorValue(String id, String refId) { + super(id, refId, null); + } + + @Override + public String getSerializationString() { + String outputId = toExternalId(id); + return outputId + " = " + getSerializedValue(); + } + + /** + * Returns true if the given key string is a valid external key for a color value + * @param key the key string to test + * @return true if the given key string is a valid external key for a color value + */ + public static boolean isColorKey(String key) { + return key.startsWith(COLOR_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX) || + key.startsWith(SYSTEM_COLOR_PREFIX); + } + + /** + * Parses the value string into a color or reference and creates a new ColorValue using + * the given key and the parse results. + * @param key the key to associate the parsed value with + * @param value the color value to parse + * @return a ColorValue with the given key and the parsed value + */ + public static ColorValue parse(String key, String value) { + String id = fromExternalId(key); + if (isColorKey(value)) { + return new ColorValue(id, fromExternalId(value)); + } + Color color = WebColors.getColor(value); + return color == null ? null : new ColorValue(id, color); + } + + @Override + protected ColorValue getReferredValue(GThemeValueMap values, String refId) { + return values.getColor(refId); + } + + @Override + protected Color getUnresolvedReferenceValue(String id, String unresolvedId) { + + Throwable t = ReflectionUtilities.createThrowableWithStackOlderThan(); + StackTraceElement[] trace = t.getStackTrace(); + StackTraceElement[] filtered = + ReflectionUtilities.filterStackTrace(trace, "docking.theme", "classfinder", + "Application", "ghidra.GhidraRun", "java.lang.Class", "java.lang.Thread"); + t.setStackTrace(filtered); + + Msg.error(this, + "Could not resolve indirect color path for \"" + unresolvedId + + "\" for primary id \"" + id + "\", using last resort default", + t); + return LAST_RESORT_DEFAULT; + } + + private static String toExternalId(String internalId) { + if (internalId.startsWith(COLOR_ID_PREFIX) || internalId.startsWith(SYSTEM_COLOR_PREFIX)) { + return internalId; + } + return EXTERNAL_PREFIX + internalId; + } + + private static String fromExternalId(String externalId) { + if (externalId.startsWith(EXTERNAL_PREFIX)) { + return externalId.substring(EXTERNAL_PREFIX.length()); + } + return externalId; + } + + private static Color getRawColor(Color value) { + if (value instanceof GColor) { + return null; + } + return value; + } + + private static String getRefId(Color value) { + if (value instanceof GColor) { + return ((GColor) value).getId(); + } + return null; + } + + private String getSerializedValue() { + if (referenceId != null) { + return toExternalId(referenceId); + } + String outputString = WebColors.toString(value, false); + String colorName = WebColors.toWebColorName(value); + if (colorName != null) { + outputString += " // " + colorName; + } + return outputString; + } + + @Override + public void installValue(ThemeManager themeManager) { + themeManager.setColor(this); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/DiscoverableGTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/DiscoverableGTheme.java new file mode 100644 index 0000000000..61ce005ca2 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/DiscoverableGTheme.java @@ -0,0 +1,34 @@ +/* ### + * 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 generic.theme; + +import ghidra.util.classfinder.ExtensionPoint; + +/** + * Abstract base class for built-in {@link GTheme}s. + */ +public abstract class DiscoverableGTheme extends GTheme implements ExtensionPoint { + static final String CLASS_PREFIX = "Class:"; + + protected DiscoverableGTheme(String name, LafType lookAndFeel, boolean useDarkDefaults) { + super(name, lookAndFeel, useDarkDefaults); + } + + @Override + public String getThemeLocater() { + return CLASS_PREFIX + getClass().getName(); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/FontChangedThemeEvent.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/FontChangedThemeEvent.java new file mode 100644 index 0000000000..0cebe15464 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/FontChangedThemeEvent.java @@ -0,0 +1,51 @@ +/* ### + * 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 generic.theme; + +/** + * {@link ThemeEvent} for when a font changes for exactly one font id. + */ +public class FontChangedThemeEvent extends ThemeEvent { + private final FontValue font; + private final GThemeValueMap values; + + /** + * Constructor + * @param values the set of theme values used to resolve indirect references + * @param font the new {@link FontValue} for the font id that changed + */ + public FontChangedThemeEvent(GThemeValueMap values, FontValue font) { + this.values = values; + this.font = font; + } + + @Override + public boolean isFontChanged(String id) { + if (id.equals(font.getId())) { + return true; + } + FontValue testValue = values.getFont(id); + if (testValue == null) { + return false; + } + return testValue.inheritsFrom(font.getId(), values); + } + + @Override + public boolean hasAnyFontChanged() { + return true; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/FontModifier.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/FontModifier.java new file mode 100644 index 0000000000..d2b6c84494 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/FontModifier.java @@ -0,0 +1,205 @@ +/* ### + * 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 generic.theme; + +import java.awt.Font; +import java.text.ParseException; +import java.util.List; + +/** + * Class that can transform one font into another. For example if want a font that is the same + * basic font as some other font, but is just a different size,style, or family, you use a + * FontModifier + */ +public class FontModifier { + private String family; + private Integer style; + private Integer size; + + private FontModifier() { + + } + + /** + * Creates a new FontModifier that can change a given font by one or more font properties. + * @param family if non-null, modifies a font to use this family + * @param style if non-null, modifies a font to use this style + * @param size if non-null, modifies a font to be this size + */ + public FontModifier(String family, Integer style, Integer size) { + this.family = family; + this.style = style; + this.size = size; + } + + /** + * Sets the family for modifying a font + * @param newFamily the font family to use when modifying fonts + */ + public void addFamilyModifier(String newFamily) { + if (family != null) { + throw new IllegalStateException("Multiple font family names specified"); + } + this.family = newFamily; + } + + /** + * Sets the font size modifier + * @param newSize the size to use when modifying fonts + */ + public void addSizeModfier(int newSize) { + if (size != null) { + throw new IllegalStateException("Multiple font sizes specified"); + } + this.size = newSize; + } + + /** + * Sets the font stle modifier. This can be called multiple times to bold and italicize. + * @param newStyle the style to use for the font. + */ + public void addStyleModifier(int newStyle) { + if (style == null) { + style = newStyle; + return; + } + if (style == Font.PLAIN || newStyle == Font.PLAIN) { + throw new IllegalStateException("Attempted to set incompable styles"); + } + style = style | newStyle; + } + + /** + * Returns a modified font for the given font. + * @param font the font to be modified + * @return a new modified font + */ + public Font modify(Font font) { + if (family == null) { + if (style != null && size != null) { + return font.deriveFont(style, size); + } + else if (style != null) { + return font.deriveFont(style); + } + return font.deriveFont((float) size); + } + int newStyle = style != null ? style : font.getStyle(); + int newSize = size != null ? size : font.getSize(); + return new Font(family, newStyle, newSize); + } + + /** + * Returns a string that can be parsed by the {@link #parse(String)} method of this class + * @return a string that can be parsed by the {@link #parse(String)} method of this class + */ + public String getSerializationString() { + StringBuilder builder = new StringBuilder(); + if (family != null) { + builder.append("[" + family + "]"); + } + if (size != null) { + builder.append("[" + size + "]"); + } + if (style != null) { + switch (style.intValue()) { + case Font.PLAIN: + builder.append("[plain]"); + break; + case Font.BOLD: + builder.append("[bold]"); + break; + case Font.ITALIC: + builder.append("[italic]"); + break; + case Font.BOLD | Font.ITALIC: + builder.append("[bold][italic]"); + break; + } + } + + return builder.toString(); + } + + /** + * Parses the given string as one or more font modifiers + * @param value the string to parse as modifiers + * @return a FontModifier as specified by the given string + * @throws ParseException if The value can't be parsed + */ + public static FontModifier parse(String value) throws ParseException { + List modifierValues = ThemeValueUtils.parseGroupings(value, '[', ']'); + if (modifierValues.isEmpty()) { + return null; + } + FontModifier modifier = new FontModifier(); + for (String modifierString : modifierValues) { + if (setSize(modifier, modifierString)) { + continue; + } + if (setStyle(modifier, modifierString)) { + continue; + } + setFamily(modifier, modifierString); + } + if (modifier.hadModifications()) { + return modifier; + } + return null; + } + + private static void setFamily(FontModifier modifier, String modifierString) + throws ParseException { + try { + modifier.addFamilyModifier(modifierString); + } + catch (IllegalStateException e) { + throw new ParseException("Multiple Font Families specfied", 0); + } + + } + + private boolean hadModifications() { + return family != null || size != null || style != null; + } + + private static boolean setStyle(FontModifier modifier, String modifierString) + throws ParseException { + int style = FontValue.getStyle(modifierString); + if (style >= 0) { + try { + modifier.addStyleModifier(style); + } + catch (IllegalStateException e) { + throw new ParseException("Illegal style combination", 0); + } + return true; + } + return false; + } + + private static boolean setSize(FontModifier modifier, String modifierString) { + try { + int size = Integer.parseInt(modifierString); + modifier.addSizeModfier(size); + return true; + } + catch (NumberFormatException e) { + return false; + } + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/FontValue.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/FontValue.java new file mode 100644 index 0000000000..50e95a91b5 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/FontValue.java @@ -0,0 +1,239 @@ +/* ### + * 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 generic.theme; + +import java.awt.Font; +import java.text.ParseException; + +import ghidra.util.Msg; + +/** + * A class for storing {@link Font} values that have a String id (e.g. font.foo.bar) and either + * a concrete font or a reference id which is the String id of another FontValue that it + * will inherit its font from. So if this class's font value is non-null, the refId will be null + * and if the class's refId is non-null, then the font value will be null. + */ +public class FontValue extends ThemeValue { + static final String FONT_ID_PREFIX = "font."; + public static final Font LAST_RESORT_DEFAULT = new Font("monospaced", Font.PLAIN, 12); + private static final String EXTERNAL_PREFIX = "[font]"; + private FontModifier modifier; + + /** + * Constructor used when the FontValue will have a direct {@link Font} value. The refId + * will be null. + * @param id the id for this FontValue + * @param value the {@link Font} to associate with the given id + */ + public FontValue(String id, Font value) { + super(id, null, value); + } + + /** + * Constructor used when the FontValue will inherit its {@link Font} from another FontValue. The + * font value field will be null. + * @param id the id for this FontValue + * @param refId the id of another FontValue that this FontValue will inherit from + */ + public FontValue(String id, String refId) { + super(id, refId, null); + } + + private FontValue(String id, String refId, FontModifier modifier) { + super(id, refId, null); + this.modifier = modifier; + } + + @Override + public Font get(GThemeValueMap values) { + Font font = super.get(values); + if (modifier != null) { + return modifier.modify(font); + } + return font; + } + + @Override + public String getSerializationString() { + String outputId = toExternalId(id); + return outputId + " = " + getValueOutput(); + } + + private String getValueOutput() { + if (referenceId != null) { + String refId = toExternalId(referenceId); + if (modifier != null) { + return refId + modifier.getSerializationString(); + } + return refId; + } + return fontToString(value); + } + + /** + * Converts a file to a string. + * @param font the font to convert to a String + * @return a String that represents the font + */ + public static String fontToString(Font font) { + return String.format("%s-%s-%s", font.getName(), getStyleString(font), font.getSize()); + } + + /** + * Returns true if the given key string is a valid external key for a font value + * @param key the key string to test + * @return true if the given key string is a valid external key for a font value + */ + public static boolean isFontKey(String key) { + return key.startsWith(FONT_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX); + } + + /** + * Parses the value string into a font or reference and creates a new FontValue using + * the given key and the parse results. + * @param key the key to associate the parsed value with + * @param value the font value to parse + * @return a FontValue with the given key and the parsed value + * @throws ParseException + */ + public static FontValue parse(String key, String value) throws ParseException { + String id = fromExternalId(key); + + value = clean(value); + + if (isFontKey(value)) { + return getRefFontValue(id, value); + } + Font font = parseFont(value); + return font == null ? null : new FontValue(id, font); + } + + /** + * Returns the Font style int for the given style string + * @param styleString the string to convert to a Font style int + * @return the Font style int for the given style string + */ + public static int getStyle(String styleString) { + if ("plain".equalsIgnoreCase(styleString)) { + return Font.PLAIN; + } + if ("bold".equalsIgnoreCase(styleString)) { + return Font.BOLD; + } + if ("italic".equalsIgnoreCase(styleString)) { + return Font.ITALIC; + } + if ("bolditalic".equalsIgnoreCase(styleString)) { + return Font.BOLD | Font.ITALIC; + } + return -1; + } + + @Override + protected FontValue getReferredValue(GThemeValueMap values, String refId) { + return values.getFont(refId); + } + + @Override + 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; + } + + private static String toExternalId(String internalId) { + if (internalId.startsWith(FONT_ID_PREFIX)) { + return internalId; + } + return EXTERNAL_PREFIX + internalId; + } + + private static String fromExternalId(String externalId) { + if (externalId.startsWith(EXTERNAL_PREFIX)) { + return externalId.substring(EXTERNAL_PREFIX.length()); + } + return externalId; + } + + private static Font parseFont(String value) { + int sizeIndex = value.lastIndexOf("-"); + int styleIndex = value.lastIndexOf("-", sizeIndex - 1); + if (sizeIndex <= 0 || styleIndex <= 0) { + return null; + } + String sizeString = value.substring(sizeIndex + 1); + String styleString = value.substring(styleIndex + 1, sizeIndex); + String familyName = value.substring(0, styleIndex); + + try { + int size = Integer.parseInt(sizeString); + int style = getStyle(styleString); + if (style >= 0) { + return new Font(familyName, style, size); + } + } + catch (NumberFormatException e) { + // parse failed, return null + } + return null; + } + + private static FontValue getRefFontValue(String id, String value) throws ParseException { + if (value.startsWith(EXTERNAL_PREFIX)) { + value = value.substring(EXTERNAL_PREFIX.length()); + } + int modIndex = value.indexOf("["); + if (modIndex < 0) { + return new FontValue(id, fromExternalId(value)); + } + String refId = value.substring(0, modIndex).trim(); + FontModifier modifier = FontModifier.parse(value.substring(modIndex)); + return new FontValue(id, refId, modifier); + } + + private static String clean(String value) { + value = value.trim(); + if (value.startsWith("(")) { + value = value.substring(1); + } + if (value.endsWith(")")) { + value = value.substring(0, value.length() - 1); + } + return value; + } + + private static String getStyleString(Font font) { + boolean bold = font.isBold(); + boolean italic = font.isItalic(); + if (bold && italic) { + return "BOLDITALIC"; + } + if (bold) { + return "BOLD"; + } + if (italic) { + return "ITALIC"; + } + return "PLAIN"; + } + + @Override + public void installValue(ThemeManager themeManager) { + themeManager.setFont(this); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GColor.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GColor.java new file mode 100644 index 0000000000..653a85c9c0 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GColor.java @@ -0,0 +1,248 @@ +/* ### + * 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 generic.theme; + +import java.awt.*; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.util.Objects; + +import ghidra.util.WebColors; +import ghidra.util.datastruct.WeakStore; + +/** + * A {@link Color} whose value is dynamically determined by looking up its id into a global + * color table that is determined by the active {@link GTheme}. + *

The idea is for developers to + * not use specific colors in their code, but to instead use a GColor with an id that hints at + * its use. For example, instead of hard coding a component's background color to white by coding + * "component.setBackground(Color.white)", you would do something like + * "component.setBackground(new GColor("color.mywidget.bg"). Then in a + * "[module name].theme.properties" file (located in the module's data directory), you would + * set the default value by adding this line "color.mywidget.bg = white". + */ +public class GColor extends Color { + // keeps a weak reference to all uses of GColor, so their cached color value can be refreshed + private static WeakStore inUseColors = new WeakStore<>(); + + private String id; + private Color delegate; + private Short alpha; + + /** + * Construct a GColor with an id that will be used to look up the current color associated with + * that id, which can be changed at runtime. + * @param id the id used to lookup the current value for this color + */ + public GColor(String id) { + super(0x808080); + this.id = id; + delegate = Gui.getColor(id); + inUseColors.add(this); + + } + + private GColor(String id, int alpha) { + this(id); + this.alpha = (short) alpha; + delegate = new Color(delegate.getRed(), delegate.getGreen(), delegate.getBlue(), alpha); + } + + /** + * Creates a transparent version of this GColor. If the underlying value of this GColor changes, + * the transparent version will also change. + * @param newAlpha the transparency level for the new color + * @return a transparent version of this GColor + */ + public GColor withAlpha(int newAlpha) { + return new GColor(id, newAlpha); + } + + /** + * Returns the id for this GColor. + * @return the id for this GColor. + */ + public String getId() { + return id; + } + + @Override + public int getRed() { + return delegate.getRed(); + } + + @Override + public int getGreen() { + return delegate.getGreen(); + } + + @Override + public int getBlue() { + return delegate.getBlue(); + } + + @Override + public int getAlpha() { + return delegate.getAlpha(); + } + + @Override + public int getRGB() { + return delegate.getRGB(); + } + + @Override + public Color brighter() { + return delegate.brighter(); + } + + @Override + public Color darker() { + return delegate.darker(); + } + + /** + * Returns true if this GColor could not find a value for its color id in the current theme + * and is using the default color as its delegate + * @return true if this GColor could not find a value for its color id in the current theme + */ + public boolean isUnresolved() { + return delegate == ColorValue.LAST_RESORT_DEFAULT; + } + + @Override + public String toString() { + return toHexString(); + } + + /** + * Returns this color as a hex string that starts with '#' + * @return the hex string + */ + public String toHexString() { + return WebColors.toString(this, false); + } + + /** + * Generates a more verbose toString() + * @return a more verbose toString() + */ + public String toDebugString() { + Color c = delegate; + String rgb = + "(" + c.getRed() + "," + c.getGreen() + "," + c.getBlue() + "," + c.getAlpha() + ")"; + String hexrgb = "(" + WebColors.toString(c, true) + ")"; + return getClass().getSimpleName() + " [id = " + id + ", color = " + + c.getClass().getSimpleName() + rgb + hexrgb + "]"; + } + + @Override + public int hashCode() { + return Objects.hash(id, alpha); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GColor other = (GColor) obj; + return Objects.equals(id, other.id) && Objects.equals(alpha, other.alpha); + } + + @Override + public float[] getRGBComponents(float[] compArray) { + return delegate.getRGBComponents(compArray); + } + + @Override + public float[] getRGBColorComponents(float[] compArray) { + return delegate.getRGBColorComponents(compArray); + } + + @Override + public float[] getComponents(float[] compArray) { + return delegate.getColorComponents(compArray); + } + + @Override + public float[] getColorComponents(float[] compArray) { + return delegate.getColorComponents(compArray); + } + + @Override + public float[] getComponents(ColorSpace cspace, float[] compArray) { + return delegate.getComponents(cspace, compArray); + } + + @Override + public float[] getColorComponents(ColorSpace cspace, float[] compArray) { + return delegate.getColorComponents(cspace, compArray); + } + + @Override + public ColorSpace getColorSpace() { + return delegate.getColorSpace(); + } + + @Override + public synchronized PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D r2d, + AffineTransform xform, RenderingHints hints) { + return delegate.createContext(cm, r, r2d, xform, hints); + } + + @Override + public int getTransparency() { + return delegate.getTransparency(); + } + + /** + * Reloads the delegate. + * @param currentValues the map of current theme values + */ + public void refresh(GThemeValueMap currentValues) { + ColorValue value = currentValues.getColor(id); + Color color = value == null ? null : value.get(currentValues); + if (color != null) { + if (alpha != null) { + delegate = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); + } + else { + delegate = color; + } + } + } + + /** + * Static method for notifying all the existing GColors that colors have changed and they + * should reload their cached indirect color. + * @param currentValues the map of current theme values + */ + public static void refreshAll(GThemeValueMap currentValues) { + for (GColor gcolor : inUseColors.getValues()) { + gcolor.refresh(currentValues); + } + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GColorUIResource.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GColorUIResource.java new file mode 100644 index 0000000000..7c93e21c38 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GColorUIResource.java @@ -0,0 +1,33 @@ +/* ### + * 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 generic.theme; + +import javax.swing.UIDefaults; +import javax.swing.plaf.UIResource; + +/** + * Version of GColor that implements UIResource. It is important that when setting java defaults + * in the {@link UIDefaults} that it implements UIResource. Otherwise, java will think the color + * was set explicitly by client code and therefore can't update it generically when it goes to + * update the default color in the UIs for each component. + */ +public class GColorUIResource extends GColor implements UIResource { + + public GColorUIResource(String id) { + super(id); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java new file mode 100644 index 0000000000..17aed43333 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GIcon.java @@ -0,0 +1,174 @@ +/* ### + * 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 generic.theme; + +import java.awt.Component; +import java.awt.Graphics; +import java.net.URL; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import ghidra.util.datastruct.WeakStore; +import resources.ResourceManager; +import resources.icons.*; + +/** + * An {@link Icon} whose value is dynamically determined by looking up its id into a global + * icon table that is determined by the active {@link GTheme}. + *

The idea is for developers to + * not use specific icons in their code, but to instead use a GIcon with an id that hints at + * its use. For example, instead of hard coding a label's icon by coding + * "label.setIcon(ResourceManager.loadImage("images/refresh.png", you would do something like + * label.setIcon(new GIcon("icon.refresh"). Then in a "[module name].theme.properties" file + * (located in the module's data directory), you would set the default value by adding this + * line "icon.refresh = images/refresh.png". + */ +public class GIcon implements Icon { + private static WeakStore inUseIcons = new WeakStore<>(); + + private String id; + private Icon delegate; + + /** + * Static method for notifying all the existing GIcon that icons have changed and they + * should reload their cached indirect icon. + * @param currentValues the map of all current theme values + */ + public static void refreshAll(GThemeValueMap currentValues) { + for (GIcon gIcon : inUseIcons.getValues()) { + gIcon.refresh(currentValues); + } + } + + /** + * Construct a GIcon with an id that will be used to look up the current icon associated with + * that id, which can be changed at runtime. + * @param id the id used to lookup the current value for this color + */ + public GIcon(String id) { + this.id = id; + delegate = Gui.getIcon(id); + inUseIcons.add(this); + } + + /** + * Returns the id for this GIcon. + * @return the id for this GIcon. + */ + public String getId() { + return id; + } + + /** + * Returns the url used to load the icon delegate of this class. If the delegate icon was not + * loaded from a url, then null will be returned. + * @return the icon or null + */ + public URL getUrl() { + return getUrl(delegate); + } + + private URL getUrl(Icon icon) { + if (icon instanceof UrlImageIcon urlIcon) { + return urlIcon.getUrl(); + } + else if (icon instanceof TranslateIcon translateIcon) { + return getUrl(translateIcon.getBaseIcon()); + } + else if (icon instanceof DerivedImageIcon derivedIcon) { + return getUrl(derivedIcon.getSourceIcon()); + } + else if (icon instanceof RotateIcon rotateIcon) { + return getUrl(rotateIcon.getSourceIcon()); + } + return null; + + } + + /** + * Returns the image for this icon. + * @return the image + */ + public ImageIcon getImageIcon() { + return ResourceManager.getImageIcon(delegate); + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + delegate.paintIcon(c, g, x, y); + } + + @Override + public int getIconWidth() { + return delegate.getIconWidth(); + } + + @Override + public int getIconHeight() { + return delegate.getIconHeight(); + } + + /** + * Reloads the delegate. + * @param currentValues the map of current theme values + */ + public void refresh(GThemeValueMap currentValues) { + IconValue value = currentValues.getIcon(id); + Icon icon = value == null ? null : value.get(currentValues); + if (icon != null) { + delegate = icon; + } + } + + /** + * Returns the current delegate for this GIcon. Note that this delegate can change when the + * theme changes or is edited. + * @return the current delegate icon for this GIcon. + */ + public Icon getDelegate() { + return delegate; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GIcon other = (GIcon) obj; + return id.equals(other.id); + } + + @Override + public String toString() { + URL url = getUrl(); + if (url == null) { + return id; + } + return getUrl().toString(); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GIconUIResource.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GIconUIResource.java new file mode 100644 index 0000000000..ad6e9aa4de --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GIconUIResource.java @@ -0,0 +1,33 @@ +/* ### + * 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 generic.theme; + +import javax.swing.UIDefaults; +import javax.swing.plaf.UIResource; + +/** + * Version of GIcon that implements UIResource. It is important that when setting java defaults + * in the {@link UIDefaults} that it implements UIResource. Otherwise, java will think the icon + * was set explicitly by client code and therefore can't update it generically when it goes to + * update the default icon in the UIs for each component. + */ +public class GIconUIResource extends GIcon implements UIResource { + + public GIconUIResource(String id) { + super(id); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java new file mode 100644 index 0000000000..277a67b463 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GTheme.java @@ -0,0 +1,232 @@ +/* ### + * 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 generic.theme; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.io.IOException; +import java.util.Objects; + +import javax.swing.Icon; +import javax.swing.LookAndFeel; + +/** + * Class to store all the configurable appearance properties (Colors, Fonts, Icons, Look and Feel) + * in an application. + */ +public class GTheme extends GThemeValueMap { + public static final String FILE_PREFIX = "File:"; + public static final String JAVA_ICON = ""; + + public static String FILE_EXTENSION = "theme"; + public static String ZIP_FILE_EXTENSION = "theme.zip"; + + private final String name; + private final LafType lookAndFeel; + private final boolean useDarkDefaults; + private final File file; + + /** + * Creates a new GTheme with the given name, the default {@link LookAndFeel} for the the + * platform and not using dark defaults. This theme will be using all the standard defaults + * from the theme.property files and the defaults from the default LookAndFeel. + * @param name the name for this GTheme + */ + public GTheme(String name) { + this(name, LafType.getDefaultLookAndFeel(), false); + + } + + /** + * Creates a new empty GTheme with the given name, {@link LookAndFeel}, and whether or not to + * use dark defaults. + * @param name the name for the new GTheme + * @param lookAndFeel the look and feel type used by this theme + * @param useDarkDefaults determines whether or + */ + public GTheme(String name, LafType lookAndFeel, boolean useDarkDefaults) { + this(null, name, lookAndFeel, useDarkDefaults); + } + + /** + * Constructor for creating a GTheme with an associated File. + * @param file the file that this theme will save to + * @param name the name of the new theme + * @param lookAndFeel the {@link LafType} for the new theme + * @param useDarkDefaults true if this new theme uses dark defaults + */ + public GTheme(File file, String name, LafType lookAndFeel, boolean useDarkDefaults) { + this.name = name; + this.lookAndFeel = lookAndFeel; + this.useDarkDefaults = useDarkDefaults; + this.file = file; + } + + /** + * Returns the name of this GTheme + * @return the name of this GTheme + */ + public String getName() { + return name; + } + + /** + * Returns the name of the LookAndFeel associated with this GTheme + * @return the name of the LookAndFeel associated with this GTheme + */ + public LafType getLookAndFeelType() { + return lookAndFeel; + } + + /** + * Returns true if this theme should use dark defaults + * @return true if this theme should use dark defaults + */ + public boolean useDarkDefaults() { + return useDarkDefaults; + } + + /** + * Returns a String that can be used to find and restore this theme. + * @return a String that can be used to find and restore this theme. + */ + public String getThemeLocater() { + if (file != null) { + return FILE_PREFIX + file.getAbsolutePath(); + } + return "Default"; + } + + /** + * Returns the file associated with this theme. + * @return the file associated with this theme. + */ + public File getFile() { + return file; + } + + /** + * Sets the Color for the given id + * @param id the id to associate with the given Color + * @param color the Color to associate with the given id + */ + public void setColor(String id, Color color) { + addColor(new ColorValue(id, color)); + } + + /** + * Sets a referred Color for the given id + * @param id the id to associate with the refId + * @param refId the id of an indirect Color lookup for the given id. + */ + public void setColorRef(String id, String refId) { + addColor(new ColorValue(id, refId)); + } + + /** + * Sets the Font for the given id + * @param id the id to associate with the given Font + * @param font the Font to associate with the given id + */ + public void setFont(String id, Font font) { + addFont(new FontValue(id, font)); + } + + /** + * Sets a referred font for the given id + * @param id the id to associate with the given Font reference id + * @param refId the id of an indirect Font lookup for the given id. + */ + public void setFontRef(String id, String refId) { + addFont(new FontValue(id, refId)); + } + + /** + * Sets the icon for the given id + * @param id the id to associate with the given IconPath + * @param icon the icon to assign to the given id + */ + public void setIcon(String id, Icon icon) { + addIcon(new IconValue(id, icon)); + } + + /** + * Sets a referred icon id for the given id + * @param id the id to associate with the given Font + * @param refId the id of an indirect Icon lookup for the given id. + */ + public void setIconRef(String id, String refId) { + addIcon(new IconValue(id, refId)); + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GTheme other = (GTheme) obj; + return Objects.equals(name, other.name) && Objects.equals(lookAndFeel, other.lookAndFeel); + } + + /** + * Returns true if this theme has a {@link LookAndFeel} that is supported by the current + * platform. + * @return true if this theme has a {@link LookAndFeel} that is supported by the current + * platform. + */ + public boolean hasSupportedLookAndFeel() { + return lookAndFeel.isSupported(); + } + + /** + * Saves this theme to its associated file. + * @throws IOException if an I/O error occurs when writing the file + */ + public void save() throws IOException { + ThemeWriter writer = new ThemeWriter(this); + writer.writeThemeToFile(file); + } + + /** + * Reads a theme from a file. The file can be either a theme file or a zip file containing + * a theme file and optionally a set of icon files. + * @param file the file to read. + * @return the theme that was read from the file + * @throws IOException if an error occcured trying to read a theme from the file. + */ + public static GTheme loadTheme(File file) throws IOException { + ThemeReader reader = new ThemeReader(file); + return reader.readTheme(); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GThemeDefaults.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GThemeDefaults.java new file mode 100644 index 0000000000..c95fc657c9 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GThemeDefaults.java @@ -0,0 +1,136 @@ +/* ### + * 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 generic.theme; + +import java.awt.Color; + +/** TODO doc how clients should use this in their code, with + * + * + * Colors.BACKGROUND + * Colors.Java.BORDER + */ +public class GThemeDefaults { + public static final String STANDARD_DEFAULTS = "Standard Defaults"; // core defaults map name + public static final String DARK = "Dark"; // defaults map name for dark based themes + + public static class Ids { + + public static class Java { + public static final String BORDER = "system.color.border"; // TODO + } + + public static class Fonts { + public static final String STANDARD = "font.standard"; + public static final String BOLD = "font.bold"; + public static final String ITALIC = "font.italic"; + public static final String BOLD_ITALIC = "font.bold.italic"; + public static final String MONOSPACED = "font.monospaced"; + } + } + + /** + * Colors mapped to system values + */ + public static class Colors { + + // generic color concepts + //@formatter:off + public static final GColor BACKGROUND = new GColor("color.bg"); + public static final GColor BACKGROUND_TOOLTIP = new GColor("color.bg.tooltip"); + public static final GColor CURSOR = new GColor("color.cursor.focused"); + public static final GColor DISABLED = new GColor("color.palette.disabled"); + public static final GColor ERROR = new GColor("color.fg.error"); // TODO replace most uses of this with Messages.ERROR + public static final GColor FOREGROUND = new GColor("color.fg"); + public static final GColor FOREGROUND_DISABLED = new GColor("color.fg.disabled"); + //@formatter:on + + public static class Java { + public static final GColor BORDER = new GColor(Ids.Java.BORDER); + } + + public static class Tables { + //@formatter:off + public static final GColor FG_ERROR_SELECTED = new GColor("color.fg.error.table.selected"); + public static final GColor FG_ERROR_UNSELECTED = new GColor("color.fg.error.table.unselected"); + public static final GColor FG_UNEDITABLE_SELECTED = new GColor("color.fg.table.uneditable.selected"); + public static final GColor FG_UNEDITABLE_UNSELECTED = new GColor("color.fg.table.uneditable.unselected"); + public static final GColor FG_UNSELECTED = new GColor("color.fg.table"); + public static final GColor FG_SELECTED = new GColor("color.fg.table.unselected"); + //@formatter:on + } + + /** + * 'Messages' is primarily used by system dialogs to display status. That the colors are + * used for foregrounds is implied. + */ + public static class Messages { + //@formatter:off + public static final GColor NORMAL = new GColor("color.fg.messages.normal"); + public static final GColor ERROR = new GColor("color.fg.messages.error"); + public static final GColor HINT = new GColor("color.fg.messages.hint"); + public static final GColor WARNING = new GColor("color.fg.messages.warning"); + //@formatter:on + + } + + /** + * Generic palette colors, using color names, that may be changed along with the theme + */ + public static class Palette { + + /** Transparent color */ + public static final Color NO_COLOR = getColor("nocolor"); + + public static final GColor BLACK = getColor("black"); + public static final GColor BLUE = getColor("blue"); + public static final GColor CYAN = getColor("cyan"); + public static final GColor DARK_GRAY = getColor("darkgray"); + public static final GColor GOLD = getColor("gold"); + public static final GColor GRAY = getColor("gray"); + public static final GColor GREEN = getColor("green"); + public static final GColor LAVENDER = getColor("lavender"); + public static final GColor LIGHT_GRAY = getColor("lightgray"); + public static final GColor LIME = getColor("lime"); + public static final GColor MAGENTA = getColor("magenta"); + public static final GColor MAROON = getColor("maroon"); + public static final GColor ORANGE = getColor("orange"); + public static final GColor PINK = getColor("pink"); + public static final GColor PURPLE = getColor("purple"); + public static final GColor RED = getColor("red"); + public static final GColor SILVER = getColor("silver"); + public static final GColor WHITE = getColor("white"); + public static final GColor YELLOW = getColor("yellow"); + + /** + * Returns a new {@link GColor} for the given palette name. + *

+ * For a list of supported palette IDs, see {@code docking.palette.theme.properties}. + *

+ * It is preferred to use the static colors defined in {@link Palette} when possible, as + * it prevents excess object creation. This method should be used when the desired + * palette color is not in that list. Further, this method should only be called once + * per use, such as when initializing a constant value. + * + * @param name the palette entry name + * @return the GColor + */ + public static GColor getColor(String name) { + return new GColor("color.palette." + name); + } + } + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/GThemeValueMap.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/GThemeValueMap.java new file mode 100644 index 0000000000..470d1297ca --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/GThemeValueMap.java @@ -0,0 +1,318 @@ +/* ### + * 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 generic.theme; + +import java.io.File; +import java.net.URL; +import java.util.*; + +import javax.swing.Icon; + +import resources.ResourceManager; +import resources.icons.UrlImageIcon; + +/** + * Class for storing colors, fonts, and icons by id + */ +public class GThemeValueMap { + protected Map colorMap = new HashMap<>(); + protected Map fontMap = new HashMap<>(); + protected Map iconMap = new HashMap<>(); + + /** + * Constructs a new empty map. + */ + public GThemeValueMap() { + } + + /** + * Constructs a new value map, populated by all the values in the given map. Essentailly clones + * the given map. + * @param initial the set of values to initialize to + */ + public GThemeValueMap(GThemeValueMap initial) { + load(initial); + } + + /** + * Adds the {@link ColorValue} to the map. If a ColorValue already exists in the map with + * the same id, it will be replaced + * @param value the {@link ColorValue} to store in the map. + * @return the previous value for the color key or null if no previous value existed + */ + public ColorValue addColor(ColorValue value) { + if (value != null) { + return colorMap.put(value.getId(), value); + } + return null; + } + + /** + * Adds the {@link FontValue} to the map. If a FontValue already exists in the map with + * the same id, it will be replaced + * @param value the {@link FontValue} to store in the map. + * @return the previous value for the font key or null if no previous value existed + */ + public FontValue addFont(FontValue value) { + if (value != null) { + return fontMap.put(value.getId(), value); + } + return null; + } + + /** + * Adds the {@link IconValue} to the map. If a IconValue already exists in the map with + * the same id, it will be replaced + * @param value the {@link IconValue} to store in the map. + * @return the previous value for the icon key or null if no previous value existed + */ + public IconValue addIcon(IconValue value) { + if (value != null) { + return iconMap.put(value.getId(), value); + } + return null; + } + + /** + * Returns the current {@link ColorValue} for the given id or null if none exists. + * @param id the id to look up a color for + * @return the current {@link ColorValue} for the given id or null if none exists. + */ + public ColorValue getColor(String id) { + return colorMap.get(id); + } + + /** + * Returns the current {@link FontValue} for the given id or null if none exists. + * @param id the id to look up a font for + * @return the current {@link FontValue} for the given id or null if none exists. + */ + public FontValue getFont(String id) { + return fontMap.get(id); + } + + /** + * Returns the current {@link IconValue} for the given id or null if none exists. + * @param id the id to look up a icon for + * @return the current {@link IconValue} for the given id or null if none exists. + */ + public IconValue getIcon(String id) { + return iconMap.get(id); + } + + /** + * Loads all the values from the given map into this map, replacing values with the + * same ids. + * @param valueMap the map whose values are to be loaded into this map + */ + public void load(GThemeValueMap valueMap) { + valueMap.colorMap.values().forEach(v -> addColor(v)); + valueMap.fontMap.values().forEach(v -> addFont(v)); + valueMap.iconMap.values().forEach(v -> addIcon(v)); + + } + + /** + * Returns a list of all the {@link ColorValue}s stored in this map. + * @return a list of all the {@link ColorValue}s stored in this map. + */ + public List getColors() { + return new ArrayList<>(colorMap.values()); + } + + /** + * Returns a list of all the {@link FontValue}s stored in this map. + * @return a list of all the {@link Fontvalue}s stored in this map. + */ + public List getFonts() { + return new ArrayList<>(fontMap.values()); + } + + /** + * Returns a list of all the {@link IconValue}s stored in this map. + * @return a list of all the {@link IconValue}s stored in this map. + */ + public List getIcons() { + return new ArrayList<>(iconMap.values()); + } + + /** + * Returns true if a {@link ColorValue} exists in this map for the given id. + * @param id the id to check + * @return true if a {@link ColorValue} exists in this map for the given id + */ + public boolean containsColor(String id) { + return colorMap.containsKey(id); + } + + /** + * Returns true if a {@link FontValue} exists in this map for the given id. + * @param id the id to check + * @return true if a {@link FontValue} exists in this map for the given id + */ + public boolean containsFont(String id) { + return fontMap.containsKey(id); + } + + /** + * Returns true if an {@link IconValue} exists in this map for the given id. + * @param id the id to check + * @return true if an {@link IconValue} exists in this map for the given id + */ + public boolean containsIcon(String id) { + return iconMap.containsKey(id); + } + + /** + * Returns the total number of color, font, and icon values stored in this map + * @return the total number of color, font, and icon values stored in this map + */ + public Object size() { + return colorMap.size() + fontMap.size() + iconMap.size(); + } + + /** + * Clears all color, font, and icon values from this map + */ + public void clear() { + colorMap.clear(); + fontMap.clear(); + iconMap.clear(); + } + + /** + * Returns true if there are not color, font, or icon values in this map + * @return true if there are not color, font, or icon values in this map + */ + public boolean isEmpty() { + return colorMap.isEmpty() && fontMap.isEmpty() && iconMap.isEmpty(); + } + + /** + * removes any {@link ColorValue} with the given id from this map. + * @param id the id to remove + */ + public void removeColor(String id) { + colorMap.remove(id); + } + + /** + * removes any {@link FontValue} with the given id from this map. + * @param id the id to remove + */ + public void removeFont(String id) { + fontMap.remove(id); + } + + /** + * removes any {@link IconValue} with the given id from this map. + * @param id the id to remove + */ + public void removeIcon(String id) { + iconMap.remove(id); + } + + /** + * Returns a new {@link GThemeValueMap} that is only populated by values that don't exist + * in the give map. + * @param base the set of values (usually the default set) to compare against to determine + * what values are changed. + * @return a new {@link GThemeValueMap} that is only populated by values that don't exist + * in the give map + */ + public GThemeValueMap getChangedValues(GThemeValueMap base) { + GThemeValueMap map = new GThemeValueMap(); + for (ColorValue color : colorMap.values()) { + if (!color.equals(base.getColor(color.getId()))) { + map.addColor(color); + } + } + for (FontValue font : fontMap.values()) { + if (!font.equals(base.getFont(font.getId()))) { + map.addFont(font); + } + } + for (IconValue icon : iconMap.values()) { + if (!icon.equals(base.getIcon(icon.getId()))) { + map.addIcon(icon); + } + } + return map; + } + + /** + * Gets the set of icon (.png, .gif) files that are used by IconValues that came from files + * versus resources in the classpath. These are the icon files that need to be included + * when exporting this set of values to a zip file. + * @return the set of icon (.png, .gif) files that are used by IconValues that came from files + * versus resources in the classpath + */ + public Set getExternalIconFiles() { + Set files = new HashSet<>(); + for (IconValue iconValue : iconMap.values()) { + Icon icon = iconValue.getRawValue(); + if (icon instanceof UrlImageIcon urlIcon) { + String originalPath = urlIcon.getOriginalPath(); + if (originalPath.startsWith(ResourceManager.EXTERNAL_ICON_PREFIX)) { + URL url = urlIcon.getUrl(); + String filePath = url.getFile(); + if (filePath != null) { + File iconFile = new File(filePath); + if (iconFile.exists()) { + files.add(iconFile); + } + } + } + } + } + return files; + } + + @Override + public int hashCode() { + return Objects.hash(colorMap, fontMap, iconMap); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + GThemeValueMap other = (GThemeValueMap) obj; + return Objects.equals(colorMap, other.colorMap) && Objects.equals(fontMap, other.fontMap) && + Objects.equals(iconMap, other.iconMap); + } + + public void checkForUnresolvedReferences() { + // attempting to get the values for all properties, will print warnings if they are unresolved + for (ColorValue colorValue : colorMap.values()) { + colorValue.get(this); + } + for (FontValue fontValue : fontMap.values()) { + fontValue.get(this); + } + for (IconValue iconValue : iconMap.values()) { + iconValue.get(this); + } + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java new file mode 100644 index 0000000000..a9c3d86428 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/Gui.java @@ -0,0 +1,168 @@ +/* ### + * 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 generic.theme; + +import java.awt.*; + +import javax.swing.Icon; +import javax.swing.LookAndFeel; + +/** + * Provides a static set of methods for globally managing application themes and their values. + *

+ * The basic idea is that all the colors, fonts, and icons used in an application should be + * accessed indirectly via an "id" string. Then the actual color, font, or icon can be changed + * without changing the source code. The default mapping of the id strings to a value is defined + * in .theme.properties files which are dynamically discovered by searching the module's + * data directory. Also, these files can optionally define a dark default value for an id which + * would replace the standard default value in the event that the current theme specifies that it + * is a dark theme. Themes are used to specify the application's {@link LookAndFeel}, whether or + * not it is dark, and any customized values for colors, fonts, or icons. There are several + * "built-in" themes, one for each supported {@link LookAndFeel}, but additional themes can + * be defined and stored in the users application home directory as a .theme file. + * + */ +public class Gui { + // Start with an StubThemeManager so that simple tests can operate without having + // to initialize the theme system. Applications and integration tests will + // called ThemeManager.initialize() which will replace this with a fully initialized version. + private static ThemeManager themeManager = new StubThemeManager(); + + private Gui() { + // static utils class, can't construct + } + + /** + * Returns the current {@link Font} associated with the given id. A default font will be + * returned if the font can't be resolved and an error message will be printed to the console. + * @param id the id for the desired font + * @return the current {@link Font} associated with the given id. + */ + public static Font getFont(String id) { + return themeManager.getFont(id); + } + + /** + * Returns the {@link Color} registered for the given id. Will output an error message if + * the id can't be resolved. + * @param id the id to get the direct color for + * @return the {@link Color} registered for the given id. + */ + public static Color getColor(String id) { + return themeManager.getColor(id); + } + + /** + * Adds a {@link ThemeListener} to be notified of theme changes. + * @param listener the listener to be notified + */ + public static void addThemeListener(ThemeListener listener) { + themeManager.addThemeListener(listener); + } + + /** + * Removes the given {@link ThemeListener} from the list of listeners to be notified of + * theme changes. + * @param listener the listener to be removed + */ + public static void removeThemeListener(ThemeListener listener) { + themeManager.removeThemeListener(listener); + } + + /** + * Returns the Icon registered for the given id. If no icon is registered for the id, + * the default icon will be returned and an error message will be dumped to the console + * @param id the id to get the registered icon for + * @return the actual icon registered for the given id + */ + public static Icon getIcon(String id) { + return themeManager.getIcon(id); + } + + /** + * Returns true if an color for the given Id has been defined + * @param id the id to check for an existing color. + * @return true if an color for the given Id has been defined + */ + public static boolean hasColor(String id) { + return themeManager.hasColor(id); + } + + /** + * Returns true if an font for the given Id has been defined + * @param id the id to check for an existing font. + * @return true if an font for the given Id has been defined + */ + public static boolean hasFont(String id) { + return themeManager.hasFont(id); + } + + /** + * Returns true if an icon for the given Id has been defined + * @param id the id to check for an existing icon. + * @return true if an icon for the given Id has been defined + */ + public static boolean hasIcon(String id) { + return themeManager.hasIcon(id); + } + + /** + * Returns a darker version of the given color or brighter if the current theme is dark. + * @param color the color to get a darker version of + * @return a darker version of the given color or brighter if the current theme is dark + */ + public static Color darker(Color color) { + if (isDarkTheme()) { + return color.brighter(); + } + return color.darker(); + } + + /** + * Returns a brighter version of the given color or darker if the current theme is dark. + * @param color the color to get a brighter version of + * @return a brighter version of the given color or darker if the current theme is dark + */ + public static Color brighter(Color color) { + if (isDarkTheme()) { + return color.darker(); + } + return color.brighter(); + } + + /** + * Binds the component to the font identified by the given font id. Whenever the font for + * the font id changes, the component will updated with the new font. + * @param component the component to set/update the font + * @param fontId the id of the font to register with the given component + */ + public static void registerFont(Component component, String fontId) { + themeManager.registerFont(component, fontId); + } + + /** + * Returns true if the active theme is using dark defaults + * @return true if the active theme is using dark defaults + */ + public static boolean isDarkTheme() { + return themeManager.isDarkTheme(); + } + + static void setThemeManager(ThemeManager manager) { + themeManager = manager; + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/IconChangedThemeEvent.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/IconChangedThemeEvent.java new file mode 100644 index 0000000000..78524c0da7 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/IconChangedThemeEvent.java @@ -0,0 +1,50 @@ +/* ### + * 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 generic.theme; + +/** + * {@link ThemeEvent} for when an icon changes for exactly one icon id. + */ +public class IconChangedThemeEvent extends ThemeEvent { + private final GThemeValueMap values; + private final IconValue icon; + + /** + * Constructor + * @param icon the new {@link IconValue} for the icon id that changed + */ + public IconChangedThemeEvent(GThemeValueMap values, IconValue icon) { + this.values = values; + this.icon = icon; + } + + @Override + public boolean isIconChanged(String id) { + if (id.equals(icon.getId())) { + return true; + } + IconValue testValue = values.getIcon(id); + if (testValue == null) { + return false; + } + return testValue.inheritsFrom(icon.getId(), values); + } + + @Override + public boolean hasAnyIconChanged() { + return true; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/IconModifier.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/IconModifier.java new file mode 100644 index 0000000000..0cb67ed483 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/IconModifier.java @@ -0,0 +1,295 @@ +/* ### + * 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 generic.theme; + +import java.awt.Dimension; +import java.awt.Point; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Icon; +//font.foo = images/flag.png[size(12,16)][move(3,4)][disable] + +import resources.MultiIcon; +import resources.ResourceManager; +import resources.icons.RotateIcon; +import resources.icons.TranslateIcon; + +/** + * Class that can transform one icon into another. Useful for scaling, translating, disabling, + * or overlaying an icon. + */ + +public class IconModifier { + Dimension size; + Point translation; + boolean disabled; + Integer rotation; + List overlayIconValues = null; + + /** + * Creates an IconModifier that can scale, translate, or disable an icon. + * @param size if non-null, scales an icon to this size. + * @param translation if non-null, translates an icon by this amount + * @param rotation if non-null, the amount in degrees to rotate the icon + * @param disabled if true, creates a disabled version of the icon + */ + public IconModifier(Dimension size, Point translation, Integer rotation, boolean disabled) { + this.size = size; + this.translation = translation; + this.rotation = rotation; + this.disabled = disabled; + } + + private IconModifier() { + + } + + /** + * Sets size modifier. Icons that are modified by this IconModifier will be scaled to this size. + * @param size the size to scale modified icons. + */ + public void setSizeModifier(Dimension size) { + this.size = size; + } + + /** + * Sets the translation for this modifier. Icons that are modified by this IconModifier will + * be translated by the amount of the given point. + * @param point the x,y amount to translate an image + */ + public void setMoveModifier(Point point) { + this.translation = point; + } + + /** + * Sets the rotation for this modifier. Icons that are modified by this IconModifier will + * be rotated by the given amount (in degrees) + * @param degrees the rotation amount; + */ + public void setRotationModifer(int degrees) { + this.rotation = degrees; + } + + /** + * Sets this modifier to disable an icon + */ + public void setDisabled() { + disabled = true; + } + + /** + * Modifies the given icon by the any of the modifiers set. + * @param icon the icon to be modified + * @param values the ThemeValueMap needed if the modify action is to overlay other icons. The + * values are used to resolve indirect overlay icon references + * @return A new Icon that is a modified version of the given icon + */ + public Icon modify(Icon icon, GThemeValueMap values) { + Icon modified = icon; + if (size != null) { + modified = ResourceManager.getScaledIcon(modified, size.width, size.height); + } + if (disabled) { + modified = ResourceManager.getDisabledIcon(modified); + } + if (rotation != null) { + modified = new RotateIcon(icon, rotation); + } + if (translation != null) { + modified = new TranslateIcon(modified, translation.x, translation.y); + } + if (overlayIconValues != null) { + MultiIcon multiIcon = new MultiIcon(modified); + for (IconValue iconValue : overlayIconValues) { + multiIcon.addIcon(iconValue.get(values)); + } + modified = multiIcon; + } + return modified; + } + + /** + * Returns a string that can be parsed by the {@link #parse(String)} method of this class + * @return a string that can be parsed by the {@link #parse(String)} method of this class + */ + public String getSerializationString() { + StringBuilder builder = new StringBuilder(); + if (size != null) { + builder.append("[" + "size(" + size.width + "," + size.height + ")]"); + } + if (rotation != null) { + builder.append("[rotate(" + rotation + ")]"); + } + if (translation != null) { + builder.append("[" + "move(" + translation.x + "," + translation.y + ")]"); + } + if (disabled) { + builder.append("[disabled]"); + } + return builder.toString(); + } + + /** + * Parses the given string as one or more icon modifiers + * @param iconModifierString the string to parse as modifiers + * @return an IconModifier as specified by the given string + * @throws ParseException if the iconModifierString in not properly formatted icon modifier + */ + public static IconModifier parse(String iconModifierString) throws ParseException { + if (iconModifierString.isBlank()) { + return null; + } + IconModifier modifier = new IconModifier(); + String baseModifierString = getBaseModifierString(iconModifierString); + parseBaseModifiers(modifier, baseModifierString); + + String overlayValuesString = getIconOverlaysString(iconModifierString); + parseOverlayModifiers(modifier, overlayValuesString); + if (modifier.hadModifications()) { + return modifier; + } + return null; + } + + private static void parseOverlayModifiers(IconModifier modifier, String overlayValuesString) + throws ParseException { + List overlayModifierStrings = + ThemeValueUtils.parseGroupings(overlayValuesString, '{', '}'); + for (String overlayIconString : overlayModifierStrings) { + IconValue overlayIconValue = IconValue.parse("", overlayIconString); + modifier.addOverlayIcon(overlayIconValue); + } + } + + private void addOverlayIcon(IconValue overlayIconValue) { + if (overlayIconValues == null) { + overlayIconValues = new ArrayList<>(); + } + overlayIconValues.add(overlayIconValue); + } + + private static void parseBaseModifiers(IconModifier modifier, String baseModifierString) + throws ParseException { + List modifierValues = ThemeValueUtils.parseGroupings(baseModifierString, '[', ']'); + for (String modifierString : modifierValues) { + modifierString = modifierString.replaceAll("\\s", "").toLowerCase(); + + if (modifierString.startsWith("size")) { + parseSizeModifier(modifier, modifierString); + } + else if (modifierString.startsWith("move")) { + parseMoveModifier(modifier, modifierString); + } + else if (modifierString.startsWith("rotate")) { + parseRotateModifier(modifier, modifierString); + } + else if (modifierString.startsWith("disabled")) { + parseDisabledModifier(modifier, modifierString); + } + else { + throw new ParseException("Invalid icon modifier: " + modifierString, 0); + } + } + } + + private static String getBaseModifierString(String value) { + int overlayStart = value.indexOf("{"); + if (overlayStart < 0) { + return value; + } + if (overlayStart == 0) { + return ""; + } + return value.substring(0, overlayStart); + } + + private static String getIconOverlaysString(String value) { + int overlayStart = value.indexOf("{"); + if (overlayStart >= 0) { + return value.substring(overlayStart); + } + return ""; + } + + private boolean hadModifications() { + return size != null || translation != null || overlayIconValues != null || + rotation != null || disabled; + } + + private static void parseDisabledModifier(IconModifier modifier, String modifierString) + throws ParseException { + if (!modifierString.equals("disabled")) { + throw new ParseException("Illegal Icon modifier: " + modifier, 0); + } + modifier.setDisabled(); + } + + private static void parseRotateModifier(IconModifier modifier, String modifierString) + throws ParseException { + String argsString = modifierString.substring("rotate".length()); + int rotation = parseIntArg(argsString); + modifier.setRotationModifer(rotation); + } + + private static void parseMoveModifier(IconModifier modifier, String modifierString) + throws ParseException { + String argsString = modifierString.substring("move".length()); + Point argValue = parsePointArgs(argsString); + modifier.setMoveModifier(argValue); + } + + private static void parseSizeModifier(IconModifier modifier, String modifierString) + throws ParseException { + String argsString = modifierString.substring("size".length()); + Point argValue = parsePointArgs(argsString); + modifier.setSizeModifier(new Dimension(argValue.x, argValue.y)); + } + + private static Point parsePointArgs(String argsString) throws ParseException { + if (!(argsString.startsWith("(") && argsString.endsWith(")"))) { + throw new ParseException("Invalid arguments: " + argsString, 0); + } + argsString = argsString.substring(1, argsString.length() - 1); + String[] split = argsString.split(","); + if (split.length != 2) { + throw new ParseException("Invalid arguments: " + argsString, 0); + } + try { + int arg1 = Integer.parseInt(split[0]); + int arg2 = Integer.parseInt(split[1]); + return new Point(arg1, arg2); + } + catch (NumberFormatException e) { + throw new ParseException("Invalid arguments: " + argsString, 0); + } + } + + private static int parseIntArg(String argString) throws ParseException { + if (!(argString.startsWith("(") && argString.endsWith(")"))) { + throw new ParseException("Invalid arguments: " + argString, 0); + } + argString = argString.substring(1, argString.length() - 1); + try { + return Integer.parseInt(argString); + } + catch (NumberFormatException e) { + throw new ParseException("Invalid arguments: " + argString, 0); + } + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/IconValue.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/IconValue.java new file mode 100644 index 0000000000..ae5479e5e8 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/IconValue.java @@ -0,0 +1,254 @@ +/* ### + * 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 generic.theme; + +import java.text.ParseException; + +import javax.swing.Icon; + +import ghidra.util.Msg; +import resources.ResourceManager; +import resources.icons.EmptyIcon; +import resources.icons.UrlImageIcon; + +/** + * A class for storing {@link Icon} values that have a String id (e.g. icon.bg.foo) and either + * a concrete icon or a reference id which is the String id of another IconValue that it + * will inherit its icon from. So if this class's icon value is non-null, the refId will be null + * and if the class's refId is non-null, then the icon value will be null. + */ +public class IconValue extends ThemeValue { + private static final String EMPTY_ICON_STRING = "EMPTY_ICON"; + + static final String ICON_ID_PREFIX = "icon."; + + public static final Icon LAST_RESORT_DEFAULT = ResourceManager.getDefaultIcon(); + + private static final String EXTERNAL_PREFIX = "[icon]"; + + private static final int STANDARD_EMPTY_ICON_SIZE = 16; + + private IconModifier modifier; + + /** + * Constructor used when the ColorValue will have a direct {@link Icon} value. The refId will + * be null. Note: if a {@link GIcon} is passed in as the value, then this will be an indirect + * IconValue that inherits its icon from the id stored in the GIcon. + * @param id the id for this IconValue + * @param icon the {@link Icon} to associate with the given id + */ + public IconValue(String id, Icon icon) { + super(id, getRefId(icon), getRawIcon(icon)); + } + + /** + * Constructor used when the IconValue will inherit its {@link Icon} from another IconValue. The + * icon value field will be null. + * @param id the id for this IconValue + * @param refId the id of another IconValue that this IconValue will inherit from + */ + public IconValue(String id, String refId) { + super(id, refId, null); + } + + private IconValue(String id, String refId, IconModifier modifier) { + super(id, refId, null); + this.modifier = modifier; + } + + private IconValue(String id, Icon icon, IconModifier modifier) { + super(id, null, icon); + this.modifier = modifier; + } + + @Override + public Icon get(GThemeValueMap values) { + Icon icon = super.get(values); + if (modifier != null) { + return modifier.modify(icon, values); + } + return icon; + } + + @Override + public String getSerializationString() { + String outputId = toExternalId(id); + return outputId + " = " + getValueOutput(); + } + + /** + * Returns true if the given key string is a valid external key for an icon value + * @param key the key string to test + * @return true if the given key string is a valid external key for an icon value + */ + public static boolean isIconKey(String key) { + return key.startsWith(ICON_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX); + } + + /** + * Converts an icon to a string. + * @param icon the icon to convert to a String + * @return a String that represents the icon + */ + public static String iconToString(Icon icon) { + if (icon instanceof EmptyIcon) { + int iconWidth = icon.getIconWidth(); + int iconHeight = icon.getIconHeight(); + if (iconWidth == STANDARD_EMPTY_ICON_SIZE && iconHeight == STANDARD_EMPTY_ICON_SIZE) { + return EMPTY_ICON_STRING; + } + return EMPTY_ICON_STRING + "[size(" + iconWidth + "," + iconHeight + ")]"; + } + + if (icon instanceof UrlImageIcon urlIcon) { + return urlIcon.getOriginalPath(); + } + return GTheme.JAVA_ICON; + } + + /** + * Parses the value string into an icon or reference and creates a new IconValue using + * the given key and the parse results. + * @param key the key to associate the parsed value with + * @param value the color value to parse + * @return an IconValue with the given key and the parsed value + * @throws ParseException if the value can't be parsed + */ + public static IconValue parse(String key, String value) throws ParseException { + String id = fromExternalId(key); + if (isIconKey(value)) { + return parseRefIcon(id, value); + } + return parseIcon(id, value); + } + + private static IconValue parseIcon(String id, String value) throws ParseException { + int modifierIndex = getModifierIndex(value); + + if (modifierIndex < 0) { + if (value.isBlank()) { + return null; + } + return new IconValue(id, getIcon(value)); + } + + String baseIconString = value.substring(0, modifierIndex).trim(); + if (baseIconString.isBlank()) { + return null; + } + Icon icon = getIcon(baseIconString); + String iconModifierString = value.substring(modifierIndex); + IconModifier modifier = IconModifier.parse(iconModifierString); + return new IconValue(id, icon, modifier); + } + + private static Icon getIcon(String baseIconString) throws ParseException { + if (EMPTY_ICON_STRING.equals(baseIconString)) { + return new EmptyIcon(STANDARD_EMPTY_ICON_SIZE, STANDARD_EMPTY_ICON_SIZE); + } + Icon icon = ResourceManager.loadIcon(baseIconString); + if (icon == null) { + throw new ParseException("Can't find icon for \"" + baseIconString + "\"", 0); + } + return icon; + } + + private static IconValue parseRefIcon(String id, String value) throws ParseException { + if (value.startsWith(EXTERNAL_PREFIX)) { + value = value.substring(EXTERNAL_PREFIX.length()); + } + int modifierIndex = getModifierIndex(value); + if (modifierIndex < 0) { + return new IconValue(id, value); + } + String refId = value.substring(0, modifierIndex).trim(); + IconModifier modifier = IconModifier.parse(value.substring(modifierIndex)); + return new IconValue(id, refId, modifier); + } + + private static int getModifierIndex(String value) { + 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; + } + if (overlayModifierIndex < 0) { + return baseModifierIndex; + } + return Math.min(overlayModifierIndex, baseModifierIndex); + } + + @Override + protected IconValue getReferredValue(GThemeValueMap values, String refId) { + return values.getIcon(refId); + } + + @Override + protected Icon getUnresolvedReferenceValue(String id, String unresolvedId) { + Msg.warn(this, + "Could not resolve indirect icon path for \"" + unresolvedId + + "\" for primary id \"" + id + "\", using last resort default"); + return LAST_RESORT_DEFAULT; + } + + private static String toExternalId(String internalId) { + if (internalId.startsWith(ICON_ID_PREFIX)) { + return internalId; + } + return EXTERNAL_PREFIX + internalId; + } + + private static String fromExternalId(String externalId) { + if (externalId.startsWith(EXTERNAL_PREFIX)) { + return externalId.substring(EXTERNAL_PREFIX.length()); + } + return externalId; + } + + private static Icon getRawIcon(Icon value) { + if (value instanceof GIcon) { + return null; + } + return value; + } + + private static String getRefId(Icon value) { + if (value instanceof GIcon) { + return ((GIcon) value).getId(); + } + return null; + } + + private String getValueOutput() { + String outputString = null; + if (referenceId != null) { + outputString = toExternalId(referenceId); + } + else { + outputString = iconToString(value); + } + if (modifier != null) { + outputString += modifier.getSerializationString(); + } + return outputString; + } + + @Override + public void installValue(ThemeManager themeManager) { + themeManager.setIcon(this); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/LafType.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/LafType.java new file mode 100644 index 0000000000..c8fc06d5c2 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/LafType.java @@ -0,0 +1,138 @@ +/* ### + * 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 generic.theme; + +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; + +import generic.theme.laf.*; +import ghidra.framework.OperatingSystem; +import ghidra.framework.Platform; +import ghidra.util.exception.AssertException; + +/** + * An enumeration that represents the set of supported {@link LookAndFeel}s + */ +public enum LafType { + METAL("Metal"), + NIMBUS("Nimbus"), + GTK("GTK+"), + MOTIF("CDE/Motif"), + FLAT_LIGHT("Flat Light"), + FLAT_DARK("Flat Dark"), + WINDOWS("Windows"), + WINDOWS_CLASSIC("Windows Classic"), + MAC("Mac OS X"); + + private String name; + + private LafType(String name) { + this.name = name; + } + + /** + * Returns the name of this LafType. + * @return the name of this LafType. + */ + public String getName() { + return name; + } + + /** + * Returns the LafType for the given name or null if the given name does not match any types + * @param name the name to search a LafType for. + * @return the LafType for the given name or null if the given name does not match any types + */ + public static LafType fromName(String name) { + for (LafType type : values()) { + if (type.getName().equals(name)) { + return type; + } + } + return null; + } + + /** + * Returns true if the {@link LookAndFeel} represented by this LafType is supported on the + * current platform. + * @return true if the {@link LookAndFeel} represented by this LafType is supported on the + * current platform + */ + public boolean isSupported() { + LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels(); + for (LookAndFeelInfo info : installedLookAndFeels) { + if (name.equals(info.getName())) { + return true; + } + } + return false; + } + + /** + * Returns a LookAndFeelManager that can install and update the {@link LookAndFeel} associated + * with this LafType. + * @param themeManager The application ThemeManager + * @return a LookAndFeelManager that can install and update the {@link LookAndFeel} associated + * with this LafType. + */ + public LookAndFeelManager getLookAndFeelManager(ApplicationThemeManager themeManager) { + return createManager(this, themeManager); + } + + private static LookAndFeelManager createManager(LafType type, + ApplicationThemeManager themeManager) { + switch (type) { + case MAC: + return new MacLookAndFeelManager(themeManager); + case METAL: + return new MetalLookAndFeelManager(themeManager); + case WINDOWS: + return new WindowsLookAndFeelManager(themeManager); + case WINDOWS_CLASSIC: + return new WindowsClassicLookAndFeelManager(themeManager); + case GTK: + return new GtkLookAndFeelManager(themeManager); + case MOTIF: + return new MotifLookAndFeelManager(themeManager); + case NIMBUS: + return new NimbusLookAndFeelManager(themeManager); + case FLAT_DARK: + case FLAT_LIGHT: + return new FlatLookAndFeelManager(type, themeManager); + default: + throw new AssertException("No lookAndFeelManager defined for " + type); + } + } + + /** + * Returns the default LafType for the current platform. + * @return the default LafType for the current platform. + */ + public static LafType getDefaultLookAndFeel() { + OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem(); + switch (OS) { + case MAC_OS_X: + return MAC; + case WINDOWS: + return WINDOWS; + case LINUX: + case UNSUPPORTED: + default: + return NIMBUS; + } + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/StubThemeManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/StubThemeManager.java new file mode 100644 index 0000000000..82c56dfa90 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/StubThemeManager.java @@ -0,0 +1,227 @@ +/* ### + * 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 generic.theme; + +import static ghidra.util.WebColors.*; + +import java.awt.Color; +import java.awt.Component; +import java.util.Set; + +import javax.swing.plaf.ComponentUI; + +/** + * Version of ThemeManager that is used before an application or test installs a full + * ApplicationThemeManager. Provides enough basic functionality used by the Gui class to + * allow simple unit tests to run. + */ +public class StubThemeManager extends ThemeManager { + + public StubThemeManager() { + installPaletteColors(); + } + + // palette colors are used statically throughout the application, so having them have values + // in the stub will allow unit tests to run withouth initializing theming + protected void installPaletteColors() { + addPalette("nocolor", BLACK); + addPalette("black", BLACK); + addPalette("blue", BLUE); + addPalette("cyan", CYAN); + addPalette("darkgray", DARK_GRAY); + addPalette("gold", GOLD); + addPalette("gray", GRAY); + addPalette("green", GREEN); + addPalette("lavender", LAVENDER); + addPalette("lightgray", LIGHT_GRAY); + addPalette("lime", LIME); + addPalette("magenta", MAGENTA); + addPalette("maroon", MAROON); + addPalette("orange", ORANGE); + addPalette("pink", PINK); + addPalette("purple", PURPLE); + addPalette("red", RED); + addPalette("silver", SILVER); + addPalette("white", WHITE); + addPalette("yellow", YELLOW); + + } + + @Override + public void reloadApplicationDefaults() { + throw new UnsupportedOperationException(); + } + + @Override + public void restoreThemeValues() { + throw new UnsupportedOperationException(); + } + + @Override + public void restoreColor(String id) { + throw new UnsupportedOperationException(); + } + + @Override + public void restoreFont(String id) { + throw new UnsupportedOperationException(); + } + + @Override + public void restoreIcon(String id) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isChangedColor(String id) { + return false; + } + + @Override + public boolean isChangedFont(String id) { + return false; + } + + @Override + public boolean isChangedIcon(String id) { + return false; + } + + @Override + public void setTheme(GTheme theme) { + throw new UnsupportedOperationException(); + } + + @Override + public void addTheme(GTheme newTheme) { + throw new UnsupportedOperationException(); + } + + @Override + public void deleteTheme(GTheme theme) { + throw new UnsupportedOperationException(); + } + + @Override + public Set getAllThemes() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getSupportedThemes() { + throw new UnsupportedOperationException(); + } + + @Override + public GTheme getActiveTheme() { + throw new UnsupportedOperationException(); + } + + @Override + public LafType getLookAndFeelType() { + throw new UnsupportedOperationException(); + } + + @Override + public GTheme getTheme(String themeName) { + throw new UnsupportedOperationException(); + } + + @Override + public GThemeValueMap getThemeValues() { + throw new UnsupportedOperationException(); + } + + @Override + public void setFont(FontValue newValue) { + currentValues.addFont(newValue); + } + + @Override + public void setColor(ColorValue newValue) { + currentValues.addColor(newValue); + } + + @Override + public void setIcon(IconValue newValue) { + currentValues.addIcon(newValue); + } + + @Override + public GColorUIResource getGColorUiResource(String id) { + throw new UnsupportedOperationException(); + } + + @Override + public GIconUIResource getGIconUiResource(String id) { + throw new UnsupportedOperationException(); + } + + @Override + public GThemeValueMap getJavaDefaults() { + throw new UnsupportedOperationException(); + } + + @Override + public GThemeValueMap getApplicationDarkDefaults() { + throw new UnsupportedOperationException(); + } + + @Override + public GThemeValueMap getApplicationLightDefaults() { + throw new UnsupportedOperationException(); + } + + @Override + public GThemeValueMap getDefaults() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isUsingAquaUI(ComponentUI UI) { + return false; + } + + @Override + public boolean isUsingNimbusUI() { + return false; + } + + @Override + public boolean hasThemeChanges() { + return false; + } + + @Override + public void registerFont(Component component, String fontId) { + // do nothing + } + + @Override + public boolean isDarkTheme() { + return false; + } + + @Override + protected void error(String message) { + // don't report errors in stub for test purposes + } + + private void addPalette(String paletteId, Color color) { + setColor(new ColorValue("color.palette." + paletteId, color)); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeEvent.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeEvent.java new file mode 100644 index 0000000000..5fee8d029b --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeEvent.java @@ -0,0 +1,93 @@ +/* ### + * 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 generic.theme; + +import javax.swing.LookAndFeel; + +/** + * Event for when a theme value changes; + */ +public class ThemeEvent { + + /** + * Returns true if the color associated with the given id has changed. + * @param id the color id to test if changed + * @return true if the color associated with the given id has changed + */ + public boolean isColorChanged(String id) { + return false; + } + + /** + * Returns true if the font associated with the given id has changed. + * @param id the font id to test if changed + * @return true if the font associated with the given id has changed + */ + public boolean isFontChanged(String id) { + return false; + } + + /** + * Returns true if the icon associated with the given id has changed. + * @param id the icon id to test if changed + * @return true if the icon associated with the given id has changed + */ + public boolean isIconChanged(String id) { + return false; + } + + /** + * Returns true if the {@link LookAndFeel} has changed (theme changed). + * @return true if the {@link LookAndFeel} has changed (theme changed). + */ + public boolean isLookAndFeelChanged() { + return false; + } + + /** + * Returns true if any color value changed. + * @return true if any color value changed. + */ + public boolean hasAnyColorChanged() { + return false; + } + + /** + * Returns true if any font value changed. + * @return true if any font value changed. + */ + public boolean hasAnyFontChanged() { + return false; + } + + /** + * Returns true if any icon value changed. + * @return true if any icon value changed. + */ + public boolean hasAnyIconChanged() { + return false; + } + + /** + * Returns true if all colors, fonts, and icons may have changed. This doesn't guarantee that + * all the values have actually changed, just that they might have. In other words, a mass + * change occurred (theme change, theme reset, etc.) and any or all values may have changed. + * @return true if all colors, fonts, and icons may have changed. + */ + public boolean haveAllValuesChanged() { + return false; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeFileLoader.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeFileLoader.java new file mode 100644 index 0000000000..0489086416 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeFileLoader.java @@ -0,0 +1,107 @@ +/* ### + * 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 generic.theme; + +import java.io.*; +import java.util.*; + +import generic.jar.ResourceFile; +import ghidra.framework.Application; +import ghidra.util.Msg; + +/** + * Loads all the system theme.property files that contain all the default color, font, and + * icon values. + */ +public class ThemeFileLoader { + public static final String THEME_DIR = "themes"; + + private GThemeValueMap defaults = new GThemeValueMap(); + private GThemeValueMap darkDefaults = new GThemeValueMap(); + + /** + * Searches for all the theme.property files and loads them into either the standard + * defaults (light) map or the dark defaults map. + */ + public void loadThemeDefaultFiles() { + defaults.clear(); + darkDefaults.clear(); + + List themeDefaultFiles = + Application.findFilesByExtensionInApplication(".theme.properties"); + + for (ResourceFile resourceFile : themeDefaultFiles) { + Msg.debug(this, "found theme file: " + resourceFile.getAbsolutePath()); + try { + ThemePropertyFileReader reader = new ThemePropertyFileReader(resourceFile); + defaults.load(reader.getDefaultValues()); + darkDefaults.load(reader.getDarkDefaultValues()); + } + catch (IOException e) { + Msg.error(this, + "Error reading theme properties file: " + resourceFile.getAbsolutePath(), e); + } + } + } + + public Collection loadThemeFiles() { + List fileList = new ArrayList<>(); + FileFilter themeFileFilter = file -> file.getName().endsWith("." + GTheme.FILE_EXTENSION); + + File dir = Application.getUserSettingsDirectory(); + File themeDir = new File(dir, THEME_DIR); + File[] files = themeDir.listFiles(themeFileFilter); + if (files != null) { + fileList.addAll(Arrays.asList(files)); + } + + List list = new ArrayList<>(); + for (File file : fileList) { + GTheme theme = loadTheme(file); + if (theme != null) { + list.add(theme); + } + } + return list; + + } + + /** + * Returns the standard defaults {@link GThemeValueMap} + * @return the standard defaults {@link GThemeValueMap} + */ + public GThemeValueMap getDefaults() { + return defaults; + } + + /** + * Returns the dark defaults {@link GThemeValueMap} + * @return the dark defaults {@link GThemeValueMap} + */ + public GThemeValueMap getDarkDefaults() { + return darkDefaults; + } + + private static GTheme loadTheme(File file) { + try { + return new ThemeReader(file).readTheme(); + } + catch (IOException e) { + Msg.error(Gui.class, "Could not load theme from file: " + file.getAbsolutePath(), e); + } + return null; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/Images.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeListener.java similarity index 67% rename from Ghidra/Framework/Generic/src/main/java/generic/Images.java rename to Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeListener.java index 13e762713b..eba81040a7 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/Images.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeListener.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package generic; +package generic.theme; + +/** + * Listener interface for theme changes + */ +public interface ThemeListener { + + /** + * Called when the theme or any of its values change + * @param event the {@link ThemeEvent} that describes what changed + */ + public void themeChanged(ThemeEvent event); -public class Images { - public static String BOMB = "images/core.png"; - public static String BIG_BOMB = "images/core24.png"; } diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeManager.java new file mode 100644 index 0000000000..ad5720773f --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeManager.java @@ -0,0 +1,483 @@ +/* ### + * 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 generic.theme; + +import java.awt.*; +import java.util.Set; + +import javax.swing.Icon; +import javax.swing.LookAndFeel; +import javax.swing.plaf.ComponentUI; + +import generic.theme.builtin.*; +import ghidra.framework.OperatingSystem; +import ghidra.framework.Platform; +import ghidra.util.Msg; +import ghidra.util.datastruct.WeakDataStructureFactory; +import ghidra.util.datastruct.WeakSet; +import resources.ResourceManager; +import utilities.util.reflection.ReflectionUtilities; + +/** + * This class manages application themes and their values. The ThemeManager is an abstract + * base class that has two concrete subclasses (and others for testing purposes) - + * StubThemeManager and ApplicationThememManager. The StubThemeManager exists as a placeholder + * until the ApplicationThemeManager is installed via {@link ApplicationThemeManager#initialize()}. + *

+ * The basic idea is that all the colors, fonts, and icons used in an application should be + * accessed indirectly via an "id" string. Then the actual color, font, or icon can be changed + * without changing the source code. The default mapping of the id strings to a value is defined + * in .theme.properties files which are dynamically discovered by searching the module's + * data directory. Also, these files can optionally define a dark default value for an id which + * would replace the standard default value in the event that the current theme specifies that it + * is a dark theme. Themes are used to specify the application's {@link LookAndFeel}, whether or + * not it is dark, and any customized values for colors, fonts, or icons. There are several + * "built-in" themes, one for each supported {@link LookAndFeel}, but additional themes can + * be defined and stored in the users application home directory as a .theme file. + *

+ * Clients that just need to access the colors, fonts, and icons from the theme can use the + * convenience methods in the {@link Gui} class. Clients that need to directly manipulate the + * themes and values will need to directly use the ThemeManager which and be retrieved using the + * static {@link #getInstance()} method. + */ + +public abstract class ThemeManager { + static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12); + static final Color DEFAULT_COLOR = Color.CYAN; + + protected static ThemeManager INSTANCE; + + protected GThemeValueMap currentValues = new GThemeValueMap(); + + // these notifications are only when the user is manipulating theme values, so rare and at + // user speed, so using copy on read + private WeakSet themeListeners = + WeakDataStructureFactory.createCopyOnReadWeakSet(); + + public static ThemeManager getInstance() { + return INSTANCE; + } + + public ThemeManager() { + if (INSTANCE == null) { + // default behavior is only install to INSTANCE if first time + INSTANCE = this; + } + } + + protected void installInGui() { + Gui.setThemeManager(this); + } + + /** + * Reloads the defaults from all the discoverable theme.property files. + */ + public abstract void reloadApplicationDefaults(); + + /** + * Restores all the current application back to the values as specified by the active theme. + * In other words, reverts any changes to the active theme that haven't been saved. + */ + public abstract void restoreThemeValues(); + + /** + * Restores the current color value for the given color id to the value established by the + * current theme. + * @param id the color id to restore back to the original theme value + */ + public abstract void restoreColor(String id); + + /** + * Restores the current font value for the given font id to the value established by the + * current theme. + * @param id the font id to restore back to the original theme value + */ + public abstract void restoreFont(String id); + + /** + * Restores the current icon value for the given icon id to the value established by the + * current theme. + * @param id the icon id to restore back to the original theme value + */ + public abstract void restoreIcon(String id); + + /** + * Returns true if the color associated with the given id has been changed from the current + * theme value for that id. + * @param id the color id to check if it has been changed + * @return true if the color associated with the given id has been changed from the current + * theme value for that id. + */ + public abstract boolean isChangedColor(String id); + + /** + * Returns true if the font associated with the given id has been changed from the current + * theme value for that id. + * @param id the font id to check if it has been changed + * @return true if the font associated with the given id has been changed from the current + * theme value for that id. + */ + public abstract boolean isChangedFont(String id); + + /** + * Returns true if the Icon associated with the given id has been changed from the current + * theme value for that id. + * @param id the Icon id to check if it has been changed + * @return true if the Icon associated with the given id has been changed from the current + * theme value for that id. + */ + public abstract boolean isChangedIcon(String id); + + /** + * Sets the application's active theme to the given theme. + * @param theme the theme to make active + */ + public abstract void setTheme(GTheme theme); + + /** + * Adds the given theme to set of all themes. + * @param newTheme the theme to add + */ + public abstract void addTheme(GTheme newTheme); + + /** + * Removes the theme from the set of all themes. Also, if the theme has an associated + * file, the file will be deleted. + * @param theme the theme to delete + */ + public abstract void deleteTheme(GTheme theme); + + /** + * Returns a set of all known themes. + * @return a set of all known themes. + */ + public abstract Set getAllThemes(); + + /** + * Returns a set of all known themes that are supported on the current platform. + * @return a set of all known themes that are supported on the current platform. + */ + public abstract Set getSupportedThemes(); + + /** + * Returns the active theme. + * @return the active theme. + */ + public abstract GTheme getActiveTheme(); + + /** + * Returns the {@link LafType} for the currently active {@link LookAndFeel} + * @return the {@link LafType} for the currently active {@link LookAndFeel} + */ + public abstract LafType getLookAndFeelType(); + + /** + * Returns the known theme that has the given name. + * @param themeName the name of the theme to retrieve + * @return the known theme that has the given name + */ + public abstract GTheme getTheme(String themeName); + + /** + * Returns a {@link GThemeValueMap} of all current theme values including unsaved changes to the + * theme. + * @return a {@link GThemeValueMap} of all current theme values + */ + public GThemeValueMap getCurrentValues() { + return new GThemeValueMap(currentValues); + } + + /** + * Returns the theme values as defined by the current theme, ignoring any unsaved changes that + * are currently applied to the application. + * @return the theme values as defined by the current theme, ignoring any unsaved changes that + * are currently applied to the application + */ + public abstract GThemeValueMap getThemeValues(); + + /** + * Returns a {@link GThemeValueMap} contains all values that differ from the default + * values (values defined by the {@link LookAndFeel} or in the theme.properties files. + * @return a {@link GThemeValueMap} contains all values that differ from the defaults. + */ + public GThemeValueMap getNonDefaultValues() { + return currentValues.getChangedValues(getDefaults()); + } + + /** + * Returns the {@link Color} registered for the given id. Will output an error message if + * the id can't be resolved. + * @param id the id to get the direct color for + * @return the {@link Color} registered for the given id. + */ + public Color getColor(String id) { + ColorValue color = currentValues.getColor(id); + + if (color == null) { + error("No color value registered for: '" + id + "'"); + return DEFAULT_COLOR; + } + return color.get(currentValues); + } + + /** + * Returns the current {@link Font} associated with the given id. A default font will be + * returned if the font can't be resolved and an error message will be printed to the console. + * @param id the id for the desired font + * @return the current {@link Font} associated with the given id. + */ + public Font getFont(String id) { + FontValue font = currentValues.getFont(id); + + if (font == null) { + error("No color value registered for: '" + id + "'"); + return DEFAULT_FONT; + } + return font.get(currentValues); + } + + /** + * Returns the Icon registered for the given id. If no icon is registered for the id, + * the default icon will be returned and an error message will be dumped to the console + * @param id the id to get the registered icon for + * @return the actual icon registered for the given id + */ + public Icon getIcon(String id) { + IconValue icon = currentValues.getIcon(id); + if (icon == null) { + error("No icon value registered for: '" + id + "'"); + return ResourceManager.getDefaultIcon(); + } + return icon.get(currentValues); + } + + /** + * Updates the current font for the given id. + * @param id the font id to update to the new color + * @param font the new font for the id + */ + public void setFont(String id, Font font) { + setFont(new FontValue(id, font)); + } + + /** + * Updates the current value for the font id in the newValue + * @param newValue the new {@link FontValue} to install in the current values. + */ + public abstract void setFont(FontValue newValue); + + /** + * Updates the current color for the given id. + * @param id the color id to update to the new color + * @param color the new color for the id + */ + public void setColor(String id, Color color) { + if (color == null) { + throw new IllegalArgumentException("Can't set theme value to null!"); + } + if (color instanceof GColor gColor) { + if (id.equals(gColor.getId())) { + Throwable t = new Throwable(); + Msg.error(this, "Attempted to set a color for id \"" + id + "\" using a GColor" + + " defined using that same id! This would create a self reference!", t); + return; // this would create a circular reference to itself, don't do it + } + } + setColor(new ColorValue(id, color)); + } + + /** + * Updates the current value for the color id in the newValue + * @param newValue the new {@link ColorValue} to install in the current values. + */ + public abstract void setColor(ColorValue newValue); + + /** + * Updates the current {@link Icon} for the given id. + * @param id the icon id to update to the new icon + * @param icon the new {@link Icon} for the id + */ + public void setIcon(String id, Icon icon) { + setIcon(new IconValue(id, icon)); + } + + /** + * Updates the current value for the {@link Icon} id in the newValue + * @param newValue the new {@link IconValue} to install in the current values. + */ + public abstract void setIcon(IconValue newValue); + + /** + * gets a UIResource version of the GColor for the given id. Using this method ensures that + * the same instance is used for a given id. This combats some poor code in some of the + * {@link LookAndFeel}s where the use == in some places to test for equals. + * @param id the id to get a GColorUIResource for + * @return a GColorUIResource for the given id + */ + public abstract GColorUIResource getGColorUiResource(String id); + + /** + * gets a UIResource version of the GIcon for the given id. Using this method ensures that + * the same instance is used for a given id. This combats some poor code in some of the + * {@link LookAndFeel}s where the use == in some places to test for equals. + * @param id the id to get a {@link GIconUIResource} for + * @return a GIconUIResource for the given id + */ + public abstract GIconUIResource getGIconUiResource(String id); + + /** + * Returns the {@link GThemeValueMap} containing all the default theme values defined by the + * current {@link LookAndFeel}. + * @return the {@link GThemeValueMap} containing all the default theme values defined by the + * current {@link LookAndFeel} + */ + public abstract GThemeValueMap getJavaDefaults(); + + /** + * Returns the {@link GThemeValueMap} containing all the dark default values defined + * in theme.properties files. Note that dark defaults includes light defaults that haven't + * been overridden by a dark default with the same id. + * @return the {@link GThemeValueMap} containing all the dark values defined in + * theme.properties files + */ + public abstract GThemeValueMap getApplicationDarkDefaults(); + + /** + * Returns the {@link GThemeValueMap} containing all the standard default values defined + * in theme.properties files. + * @return the {@link GThemeValueMap} containing all the standard values defined in + * theme.properties files + */ + public abstract GThemeValueMap getApplicationLightDefaults(); + + /** + * Returns a {@link GThemeValueMap} containing all default values for the current theme. It + * is a combination of application defined defaults and java {@link LookAndFeel} defaults. + * @return the current set of defaults. + */ + public abstract GThemeValueMap getDefaults(); + + /** + * Returns true if the given UI object is using the Aqua Look and Feel. + * @param UI the UI to examine. + * @return true if the UI is using Aqua + */ + public abstract boolean isUsingAquaUI(ComponentUI UI); + + /** + * Returns true if 'Nimbus' is the current Look and Feel + * @return true if 'Nimbus' is the current Look and Feel + */ + public abstract boolean isUsingNimbusUI(); + + /** + * Adds a {@link ThemeListener} to be notified of theme changes. + * @param listener the listener to be notified + */ + public void addThemeListener(ThemeListener listener) { + themeListeners.add(listener); + } + + /** + * Removes the given {@link ThemeListener} from the list of listeners to be notified of + * theme changes. + * @param listener the listener to be removed + */ + public void removeThemeListener(ThemeListener listener) { + themeListeners.remove(listener); + } + + /** + * Returns the default theme for the current platform. + * @return the default theme for the current platform. + */ + public static GTheme getDefaultTheme() { + OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem(); + switch (OS) { + case MAC_OS_X: + return new MacTheme(); + case WINDOWS: + return new WindowsTheme(); + case LINUX: + case UNSUPPORTED: + default: + return new NimbusTheme(); + } + } + + /** + * Returns true if there are any unsaved changes to the current theme. + * @return true if there are any unsaved changes to the current theme. + */ + public abstract boolean hasThemeChanges(); + + /** + * Returns true if an color for the given Id has been defined + * @param id the id to check for an existing color. + * @return true if an color for the given Id has been defined + */ + public boolean hasColor(String id) { + return currentValues.containsColor(id); + } + + /** + * Returns true if an font for the given Id has been defined + * @param id the id to check for an existing font. + * @return true if an font for the given Id has been defined + */ + public boolean hasFont(String id) { + return currentValues.containsFont(id); + } + + /** + * Returns true if an icon for the given Id has been defined + * @param id the id to check for an existing icon. + * @return true if an icon for the given Id has been defined + */ + public boolean hasIcon(String id) { + return currentValues.containsIcon(id); + } + + /** + * Binds the component to the font identified by the given font id. Whenever the font for + * the font id changes, the component will updated with the new font. + * @param component the component to set/update the font + * @param fontId the id of the font to register with the given component + */ + public abstract void registerFont(Component component, String fontId); + + /** + * Returns true if the current theme use dark default values. + * @return true if the current theme use dark default values. + */ + public abstract boolean isDarkTheme(); + + protected void notifyThemeChanged(ThemeEvent event) { + for (ThemeListener listener : themeListeners) { + listener.themeChanged(event); + } + } + + protected void error(String message) { + Throwable t = ReflectionUtilities.createThrowableWithStackOlderThan(); + StackTraceElement[] trace = t.getStackTrace(); + StackTraceElement[] filtered = + ReflectionUtilities.filterStackTrace(trace, "java.", "theme.Gui", "theme.ThemeManager", + "theme.GColor"); + t.setStackTrace(filtered); + Msg.error(this, message, t); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemePreferences.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemePreferences.java new file mode 100644 index 0000000000..6c8f84d556 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemePreferences.java @@ -0,0 +1,69 @@ +/* ### + * 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 generic.theme; + +import java.io.File; +import java.io.IOException; + +import ghidra.framework.preferences.Preferences; +import ghidra.util.Msg; + +/** + * Reads and writes current theme info to preferences + */ +public class ThemePreferences { + private static final String THEME_PREFFERENCE_KEY = "Theme"; + + /** + * Returns the theme that was stored in preferences or the default theme if none stored. + * @return the last theme used (stored in preferences) or the default theme if not stored + * in preferences + */ + public GTheme load() { + String themeId = Preferences.getProperty(THEME_PREFFERENCE_KEY, "Default", true); + if (themeId.startsWith(GTheme.FILE_PREFIX)) { + String filename = themeId.substring(GTheme.FILE_PREFIX.length()); + try { + return new ThemeReader(new File(filename)).readTheme(); + } + catch (IOException e) { + Msg.showError(GTheme.class, null, "Can't Load Previous Theme", + "Error loading theme file: " + filename, e); + } + } + else if (themeId.startsWith(DiscoverableGTheme.CLASS_PREFIX)) { + String className = themeId.substring(DiscoverableGTheme.CLASS_PREFIX.length()); + try { + Class forName = Class.forName(className); + return (GTheme) forName.getDeclaredConstructor().newInstance(); + } + catch (Exception e) { + Msg.showError(GTheme.class, null, "Can't Load Previous Theme", + "Can't find or instantiate class: " + className, e); + } + } + return ThemeManager.getDefaultTheme(); + } + + /** + * Saves the current theme choice to {@link Preferences}. + * @param theme the theme to remember in {@link Preferences} + */ + public void save(GTheme theme) { + Preferences.setProperty(THEME_PREFFERENCE_KEY, theme.getThemeLocater()); + Preferences.store(); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemePropertyFileReader.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemePropertyFileReader.java new file mode 100644 index 0000000000..9d66a17c4d --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemePropertyFileReader.java @@ -0,0 +1,89 @@ +/* ### + * 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 generic.theme; + +import java.io.*; + +import generic.jar.ResourceFile; + +/** + * Reads the values for a single theme.properities file + */ +public class ThemePropertyFileReader extends AbstractThemeReader { + + private GThemeValueMap defaults; + private GThemeValueMap darkDefaults; + + /** + * Constructor for when the the theme.properties file is a {@link ResourceFile} + * @param file the {@link ResourceFile} esourceFileto read + * @throws IOException if an I/O error occurs reading the file + */ + public ThemePropertyFileReader(ResourceFile file) throws IOException { + super(file.getAbsolutePath()); + + try (Reader reader = new InputStreamReader(file.getInputStream())) { + read(reader); + } + + } + + /** + * Constructor using a Reader (needed for reading from zip files). + * @param source the name or description of the Reader source + * @param reader the {@link Reader} to parse as theme data + * @throws IOException if an I/O error occurs while reading from the Reader + */ + protected ThemePropertyFileReader(String source, Reader reader) throws IOException { + super(source); + read(reader); + } + + /** + * Returns the map of standard defaults values. + * @return the map of standard defaults values. + */ + public GThemeValueMap getDefaultValues() { + return defaults == null ? new GThemeValueMap() : defaults; + } + + /** + * Returns the map of dark defaults values. + * @return the map of dark defaults values. + */ + public GThemeValueMap getDarkDefaultValues() { + return darkDefaults == null ? new GThemeValueMap() : darkDefaults; + } + + protected void processNoSection(Section section) throws IOException { + if (!section.isEmpty()) { + error(0, "Theme properties file has values defined outside of a defined section"); + } + } + + @Override + protected void processDefaultSection(Section section) throws IOException { + defaults = new GThemeValueMap(); + processValues(defaults, section); + } + + @Override + protected void processDarkDefaultSection(Section section) throws IOException { + darkDefaults = new GThemeValueMap(); + processValues(darkDefaults, section); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeReader.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeReader.java new file mode 100644 index 0000000000..88a64ee26a --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeReader.java @@ -0,0 +1,145 @@ +/* ### + * 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 generic.theme; + +import java.io.*; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.apache.commons.io.FileUtils; + +import ghidra.framework.Application; +import ghidra.util.Msg; + +/** + * Reads Themes from a file or {@link Reader} + */ +class ThemeReader extends AbstractThemeReader { + + private File file; + private GTheme theme; + + /** + * Constructor for reading a theme from a file. + * @param file the file to read as a theme + * @throws IOException if an I/O error occurs reading the theme file + */ + ThemeReader(File file) throws IOException { + super(file.getAbsolutePath()); + this.file = file; + } + + public GTheme readTheme() throws IOException { + if (file.getName().endsWith(GTheme.FILE_EXTENSION)) { + return readFileTheme(); + } + if (file.getName().endsWith(GTheme.ZIP_FILE_EXTENSION)) { + return readZipTheme(); + } + + throw new IOException("Imported File must end in either " + GTheme.FILE_EXTENSION + " or " + + GTheme.ZIP_FILE_EXTENSION); + } + + /** + * Assumes the file is a theme file and reads it. + * @return + * @throws IOException + */ + private GTheme readFileTheme() throws IOException { + try (Reader reader = new FileReader(file)) { + read(reader); + } + if (theme == null) { + throw new IOException("Invalid Theme file: " + file); + } + return theme; + } + + private GTheme readZipTheme() throws IOException { + try (ZipFile zipFile = new ZipFile(file)) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + String name = entry.getName(); + try (InputStream is = zipFile.getInputStream(entry)) { + if (name.endsWith(".theme")) { + processThemeData(name, is); + } + else { + processIconFile(name, is); + } + } + } + } + return theme; + } + + // for testing + GTheme readTheme(Reader reader) throws IOException { + read(reader); + return theme; + } + + @Override + protected void processNoSection(Section section) throws IOException { + String themeName = section.getValue(ThemeWriter.THEME_NAME_KEY); + if (themeName == null) { + throw new IOException("Missing theme name!"); + } + String lookAndFeelName = section.getValue(ThemeWriter.THEME_LOOK_AND_FEEL_KEY); + LafType lookAndFeel = LafType.fromName(lookAndFeelName); + if (lookAndFeel == null) { + throw new IOException( + "Invalid or missing lookAndFeel name: \"" + lookAndFeelName + "\""); + } + boolean isDark = Boolean.valueOf(section.getValue(ThemeWriter.THEME_USE_DARK_DEFAULTS)); + + theme = new GTheme(file, themeName, lookAndFeel, isDark); + section.remove(ThemeWriter.THEME_NAME_KEY); + section.remove(ThemeWriter.THEME_LOOK_AND_FEEL_KEY); + section.remove(ThemeWriter.THEME_USE_DARK_DEFAULTS); + processValues(theme, section); + } + + @Override + protected void processDefaultSection(Section section) throws IOException { + error(section.getLineNumber(), "[Defaults] section not allowed in theme files!"); + } + + @Override + protected void processDarkDefaultSection(Section section) throws IOException { + error(section.getLineNumber(), "[Dark Defaults] section not allowed in theme files!"); + } + + private void processIconFile(String path, InputStream is) throws IOException { + int indexOf = path.indexOf("images/"); + if (indexOf < 0) { + Msg.error(this, "Unknown file: " + path); + } + String relativePath = path.substring(indexOf, path.length()); + File dir = Application.getUserSettingsDirectory(); + File iconFile = new File(dir, relativePath); + FileUtils.copyInputStreamToFile(is, iconFile); + } + + private void processThemeData(String name, InputStream is) throws IOException { + InputStreamReader reader = new InputStreamReader(is); + read(reader); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeValue.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeValue.java new file mode 100644 index 0000000000..5d45bcd1dc --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeValue.java @@ -0,0 +1,250 @@ +/* ### + * 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 generic.theme; + +import java.util.*; + +import ghidra.util.Msg; + +/** + * A generic class for storing theme values that have a String id (e.g. color.bg.foo) and either + * a concrete value of type T or a reference id which is the String id of another ThemeValue. So + * if this class's value is non-null, the refId will be null and if the class's refId is non-null, + * then the value will be null. + * + * @param the base type this ThemeValue works on (i.e., Colors, Fonts, Icons) + */ +public abstract class ThemeValue implements Comparable> { + protected final String id; + protected final T value; + 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; + } + + /** + * Returns the identifier for this ThemeValue. + * @return the identifier for this ThemeValue. + */ + public String getId() { + return id; + } + + /** + * Returns the referencId of another ThemeValue that we inherit its value pr null if we have + * a value + * + * @return the referencId of another ThemeValue that we inherit its value or null if we have + * a value + */ + public String getReferenceId() { + return referenceId; + } + + /** + * Returns the stored value. Does not follow referenceIds. Will be null if this instance + * has a referenceId. + * + * @return the stored value. Does not follow referenceIds. Will be null if this instance + * has a referenceId. + */ + public T getRawValue() { + return value; + } + + /** + * Returns the T value for this instance, following references as needed. Uses the given + * preferredValues map to resolve references. If the value can't be resolved by following + * reference chains, an error stack trace will be generated and the default T value will + * be returned. In rare situations where it is acceptable for the value to not be resolvable, + * use the {@link #hasResolvableValue(GThemeValueMap)} method first. + * @param values the {@link GThemeValueMap} used to resolve references if this + * instance doesn't have an actual value. + * @return the T value for this instance, following references as needed. + */ + public T get(GThemeValueMap values) { + if (value != null) { + return value; + } + + Set visitedKeys = new HashSet<>(); + visitedKeys.add(id); + ThemeValue referred = getReferredValue(values, referenceId); + + // loop resolving indirect references + while (referred != null) { + if (referred.value != null) { + return referred.value; + } + visitedKeys.add(referred.id); + if (visitedKeys.contains(referred.referenceId)) { + Msg.warn(this, "Theme value reference loop detected for key: " + id); + return getUnresolvedReferenceValue(id, referred.referenceId); + } + referred = getReferredValue(values, referred.referenceId); + } + return getUnresolvedReferenceValue(id, referenceId); + } + + /** + * Returns true if the ThemeValue can resolve to the concrete T value (color, font, or icon) + * from the given set of theme values. + * @param values the set of values to use to try and follow reference chains to ultimately + * resolve the ThemeValue to a an actual T value + * @return true if the ThemeValue can resolve to the concrete T value (color, font, or icon) + * from the given set of theme values. + */ + public boolean hasResolvableValue(GThemeValueMap values) { + if (value != null) { + return true; + } + + Set visitedKeys = new HashSet<>(); + visitedKeys.add(id); + ThemeValue referred = getReferredValue(values, referenceId); + + // loop resolving indirect references + while (referred != null) { + if (referred.value != null) { + return true; + } + visitedKeys.add(referred.id); + if (visitedKeys.contains(referred.referenceId)) { + Msg.warn(this, "Theme value reference loop detected for key: " + id); + return false; + } + referred = getReferredValue(values, referred.referenceId); + } + return false; + } + + /** + * Returns true if this ThemeValue derives its value from the given ancestorId. + * @param ancestorId the id to test if this Theme value inherits from + * @param values the set of values used to resolve indirect references to attempt to trace + * back to the given ancestor id + * @return true if this ThemeValue derives its value from the given ancestorId. + */ + public boolean inheritsFrom(String ancestorId, GThemeValueMap values) { + if (referenceId == null) { + return false; + } + if (referenceId.equals(ancestorId)) { + return true; + } + + Set visitedKeys = new HashSet<>(); + visitedKeys.add(id); + ThemeValue parent = getReferredValue(values, referenceId); + + // loop resolving indirect references + while (parent != null) { + if (parent.referenceId == null) { + return false; + } + if (parent.referenceId.equals(ancestorId)) { + return true; + } + visitedKeys.add(parent.id); + if (visitedKeys.contains(parent.referenceId)) { + return false; + } + parent = getReferredValue(values, parent.referenceId); + } + return false; + } + + /** + * Returns true if this ColorValue gets its value from some other ColorValue + * @return true if this ColorValue gets its value from some other ColorValue + */ + public boolean isIndirect() { + return referenceId != null; + } + + /** + * Returns the "key = value" String for writing this ThemeValue to a file + * @return the "key = value" String for writing this ThemeValue to a file + */ + public abstract String getSerializationString(); + + /** + * Returns the T to be used if the indirect reference 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 id, String unresolvedId); + + /** + * Returns the ThemeValue referred to by this ThemeValue. Needs to be overridden by + * concrete classes as they know the correct method to call on the preferredValues map. + * @param preferredValues the {@link GThemeValueMap} to be used to resolve the reference id + * @param refId the id of the reference ThemeValue + * @return the ThemeValue referred to by this ThemeValue. + */ + protected abstract ThemeValue getReferredValue(GThemeValueMap preferredValues, + String refId); + + @Override + public int compareTo(ThemeValue o) { + return id.compareTo(o.id); + } + + @Override + public int hashCode() { + return Objects.hash(id, referenceId, value); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ThemeValue other = (ThemeValue) obj; + + return Objects.equals(id, other.id) && Objects.equals(referenceId, other.referenceId) && + Objects.equals(value, other.value); + } + + @Override + public String toString() { + String name = getClass().getSimpleName(); + if (referenceId == null) { + return name + " (" + id + ", " + value + ")"; + } + return name + " (" + id + ", " + referenceId + ")"; + } + + /** + * Install this value as the current value for the application + * @param themeManager the application ThemeManager + */ + public abstract void installValue(ThemeManager themeManager); + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeValueUtils.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeValueUtils.java new file mode 100644 index 0000000000..376d046a54 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeValueUtils.java @@ -0,0 +1,84 @@ +/* ### + * 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 generic.theme; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +public class ThemeValueUtils { + /** + * Parses the given source string into a list of strings, one for each group. The startChar + * and endChar defined the group characters. So, for example, "(ab (cd))(ef)((gh))" would + * result in a list with the following values: "ab (cd)", "ef", and "(gh)" + * @param source the source string to parse into groups + * @param startChar the character that defines the start of a group + * @param endChar the character that defines then end of a group + * @return a List of strings, one for each consecutive group contained in the string + * @throws ParseException if the groupings are not balanced or missing altogether + */ + public static List parseGroupings(String source, char startChar, char endChar) + throws ParseException { + List results = new ArrayList<>(); + int index = 0; + + while (index < source.length()) { + int groupStart = findNextNonWhiteSpaceChar(source, index); + if (groupStart < 0) { + break; + } + if (source.charAt(groupStart) != startChar) { + throw new ParseException("Error parsing groupings for " + source, index); + } + int groupEnd = findMatchingEnd(source, groupStart + 1, startChar, endChar); + if (groupEnd < 0) { + throw new ParseException("Error parsing groupings for " + source, index); + } + results.add(source.substring(groupStart + 1, groupEnd)); + index = groupEnd + 1; + } + return results; + } + + private static int findMatchingEnd(String source, int index, char startChar, char endChar) { + int level = 0; + while (index < source.length()) { + char c = source.charAt(index); + if (c == startChar) { + level++; + } + else if (c == endChar) { + if (level == 0) { + return index; + } + level--; + } + index++; + } + return -1; + } + + private static int findNextNonWhiteSpaceChar(String source, int index) { + while (index < source.length()) { + if (!Character.isWhitespace(source.charAt(index))) { + return index; + } + index++; + } + return -1; + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeWriter.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeWriter.java new file mode 100644 index 0000000000..1d778e867c --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/ThemeWriter.java @@ -0,0 +1,138 @@ +/* ### + * 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 generic.theme; + +import java.io.*; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import com.google.common.io.Files; + +/** + * Writes a theme to a file either as a single theme file or as a zip file that contains the theme + * file and any external (from the file system, not the classpath) icons used by the theme. + */ +public class ThemeWriter { + static final String THEME_NAME_KEY = "name"; + static final String THEME_LOOK_AND_FEEL_KEY = "lookAndFeel"; + static final String THEME_USE_DARK_DEFAULTS = "useDarkDefaults"; + protected GTheme theme; + + /** + * Constructor + * @param theme the theme to be written to a file + */ + public ThemeWriter(GTheme theme) { + this.theme = theme; + } + + /** + * Writes the theme to the given file with the option to output as a zip file. + * @param file the file to write to + * @param asZip if true, outputs in zip format + * @throws FileNotFoundException i + * @throws IOException if an I/O error occurs trying to write the file + */ + public void writeTheme(File file, boolean asZip) throws IOException { + if (asZip) { + writeThemeToZipFile(file); + } + else { + writeThemeToFile(file); + } + } + + /** + * Writes the theme to the given file. + * @param file the file to write to + * @throws FileNotFoundException i + * @throws IOException if an I/O error occurs trying to write the file + */ + public void writeThemeToFile(File file) throws IOException { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writeThemeValues(writer); + } + } + + /** + * Writes the theme to the given file in a zip format. + * @param file the file to write to + * @throws IOException if an I/O error occurs trying to write the file + */ + public void writeThemeToZipFile(File file) throws IOException { + String dir = theme.getName() + ".theme/"; + try (FileOutputStream fos = new FileOutputStream(file)) { + ZipOutputStream zos = new ZipOutputStream(fos); + saveThemeFileToZip(dir, zos); + Set iconFiles = theme.getExternalIconFiles(); + for (File iconFile : iconFiles) { + copyToZipFile(dir, iconFile, zos); + } + zos.finish(); + } + } + + protected void writeThemeValues(BufferedWriter writer) throws IOException { + List colors = theme.getColors(); + Collections.sort(colors); + + List fonts = theme.getFonts(); + Collections.sort(fonts); + + List icons = theme.getIcons(); + Collections.sort(icons); + + writer.write(THEME_NAME_KEY + " = " + theme.getName()); + writer.newLine(); + + writer.write(THEME_LOOK_AND_FEEL_KEY + " = " + theme.getLookAndFeelType().getName()); + writer.newLine(); + + writer.write(THEME_USE_DARK_DEFAULTS + " = " + theme.useDarkDefaults()); + writer.newLine(); + + for (ColorValue colorValue : colors) { + writer.write(colorValue.getSerializationString()); + writer.newLine(); + } + + for (FontValue fontValue : fonts) { + writer.write(fontValue.getSerializationString()); + writer.newLine(); + } + + for (IconValue iconValue : icons) { + writer.write(iconValue.getSerializationString()); + writer.newLine(); + + } + } + + private void copyToZipFile(String dir, File iconFile, ZipOutputStream zos) throws IOException { + ZipEntry entry = new ZipEntry(dir + "images/" + iconFile.getName()); + zos.putNextEntry(entry); + Files.copy(iconFile, zos); + } + + private void saveThemeFileToZip(String dir, ZipOutputStream zos) throws IOException { + ZipEntry entry = new ZipEntry(dir + theme.getName() + ".theme"); + zos.putNextEntry(entry); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(zos)); + writeThemeValues(writer); + writer.flush(); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/CDEMotifTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/CDEMotifTheme.java new file mode 100644 index 0000000000..88366a4f7c --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/CDEMotifTheme.java @@ -0,0 +1,33 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the Motif {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class CDEMotifTheme extends DiscoverableGTheme { + + public CDEMotifTheme() { + super("Motif Theme", LafType.MOTIF, false); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/FlatDarkTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/FlatDarkTheme.java new file mode 100644 index 0000000000..1cdd08d0c0 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/FlatDarkTheme.java @@ -0,0 +1,30 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the FlatDark {@link LookAndFeel} and the dark application defaults. + */ +public class FlatDarkTheme extends DiscoverableGTheme { + public FlatDarkTheme() { + super("Flat Dark Theme", LafType.FLAT_DARK, true); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/FlatLightTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/FlatLightTheme.java new file mode 100644 index 0000000000..7aef97db7f --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/FlatLightTheme.java @@ -0,0 +1,32 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the FlatLight {@link LookAndFeel} and the dark application defaults. + */ +public class FlatLightTheme extends DiscoverableGTheme { + + public FlatLightTheme() { + super("Flat Light Theme", LafType.FLAT_LIGHT, false); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/GTKTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/GTKTheme.java new file mode 100644 index 0000000000..ddaae40ebc --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/GTKTheme.java @@ -0,0 +1,33 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the GTK+ {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class GTKTheme extends DiscoverableGTheme { + + public GTKTheme() { + super("GTK+ Theme", LafType.GTK, false); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/MacTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/MacTheme.java new file mode 100644 index 0000000000..3dda6c25c6 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/MacTheme.java @@ -0,0 +1,32 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the Aqua {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class MacTheme extends DiscoverableGTheme { + + public MacTheme() { + super("Mac OS X Theme", LafType.MAC, false); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/MetalTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/MetalTheme.java new file mode 100644 index 0000000000..ed948e6dd3 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/MetalTheme.java @@ -0,0 +1,33 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the Metal {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class MetalTheme extends DiscoverableGTheme { + + public MetalTheme() { + super("Metal Theme", LafType.METAL, false); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/NimbusTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/NimbusTheme.java new file mode 100644 index 0000000000..a7020b2f8a --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/NimbusTheme.java @@ -0,0 +1,33 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the Nimbus {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class NimbusTheme extends DiscoverableGTheme { + + public NimbusTheme() { + super("Nimbus Theme", LafType.NIMBUS, false); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/WindowsClassicTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/WindowsClassicTheme.java new file mode 100644 index 0000000000..08793e42ea --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/WindowsClassicTheme.java @@ -0,0 +1,32 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the Windows Classic {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class WindowsClassicTheme extends DiscoverableGTheme { + + public WindowsClassicTheme() { + super("Windows Classic Theme", LafType.WINDOWS_CLASSIC, false); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/WindowsTheme.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/WindowsTheme.java new file mode 100644 index 0000000000..2ce77ec1ce --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/builtin/WindowsTheme.java @@ -0,0 +1,32 @@ +/* ### + * 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 generic.theme.builtin; + +import javax.swing.LookAndFeel; + +import generic.theme.DiscoverableGTheme; +import generic.theme.LafType; + +/** + * Built-in GTheme that uses the Windows {@link LookAndFeel} and the standard (light) + * application defaults. + */ +public class WindowsTheme extends DiscoverableGTheme { + + public WindowsTheme() { + super("Windows Theme", LafType.WINDOWS, false); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/ComponentFontRegistry.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/ComponentFontRegistry.java new file mode 100644 index 0000000000..9ddc2dca6d --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/ComponentFontRegistry.java @@ -0,0 +1,64 @@ +/* ### + * 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 generic.theme.laf; + +import java.awt.Component; +import java.awt.Font; +import java.util.Objects; + +import generic.theme.Gui; +import ghidra.util.datastruct.WeakDataStructureFactory; +import ghidra.util.datastruct.WeakSet; + +/** + * Maintains a week set of components associated with a given font id. Whenever the font changes + * for the font id, this class will update the component's font to the new value. + */ +public class ComponentFontRegistry { + private WeakSet components = WeakDataStructureFactory.createCopyOnReadWeakSet(); + private String fontId; + + /** + * Constructs a registry for components bound to the given font id + * @param fontId the id of the font to update the containing components + */ + public ComponentFontRegistry(String fontId) { + this.fontId = fontId; + } + + /** + * Adds a {@link Component} to the weak set of components whose font should be updated when + * the underlying font changes for this registry's font id. + * @param component the component to add + */ + public void addComponent(Component component) { + component.setFont(Gui.getFont(fontId)); + components.add(component); + } + + /** + * Updates the font for all components bound to this registry's font id. + */ + public void updateComponentFonts() { + Font font = Gui.getFont(fontId); + for (Component component : components) { + Font existingFont = component.getFont(); + if (!Objects.equals(existingFont, font)) { + component.setFont(font); + } + } + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FlatLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FlatLookAndFeelManager.java new file mode 100644 index 0000000000..39c61836d4 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FlatLookAndFeelManager.java @@ -0,0 +1,45 @@ +/* ### + * 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 generic.theme.laf; + +import javax.swing.UIManager; + +import generic.theme.*; + +public class FlatLookAndFeelManager extends LookAndFeelManager { + + public FlatLookAndFeelManager(LafType laf, ApplicationThemeManager themeManager) { + super(laf, themeManager); + + // establish system color to LookAndFeel colors + systemToLafMap.addColor(new ColorValue(SYSTEM_WIDGET_BACKGROUND_COLOR_ID, "text")); + systemToLafMap.addColor(new ColorValue(SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID, "info")); + } + + @Override + protected void fixupLookAndFeelIssues() { + super.fixupLookAndFeelIssues(); + + // We have historically managed button focus-ability ourselves. Allow this by default so + // features continue to work as expected, such as right-clicking on ToolButtons. + UIManager.put("ToolBar.focusableButtons", Boolean.TRUE); + } + + @Override + protected ThemeGrouper getThemeGrouper() { + return new FlatThemeGrouper(); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FlatThemeGrouper.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FlatThemeGrouper.java new file mode 100644 index 0000000000..bed475a323 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FlatThemeGrouper.java @@ -0,0 +1,62 @@ +/* ### + * 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 generic.theme.laf; + +import generic.theme.GThemeValueMap; + +/** + * Adds specialized groupings unique to the Flat LookAndFeels + */ +public class FlatThemeGrouper extends ThemeGrouper { + + @Override + public void group(GThemeValueMap values) { + // @formatter:off + defineCustomColorGroup("color.flat.menu.hover.bg", "MenuBar.hoverBackground", values); + defineCustomColorGroup("color.flat.button.hover.bg", "Button.hoverBackground", values); + defineCustomColorGroup("color.flat.button.selected.bg", "Button.selectedBackground",values); + defineCustomColorGroup("color.flat.button.toolbar.hover.bg", "Button.toolbar.hoverBackground",values); + defineCustomColorGroup("color.flat.button.toolbar.pressed.bg", "Button.toolbar.pressedBackground",values); + defineCustomColorGroup("color.flat.checkbox.icon.focus.border", "CheckBox.icon.focusedBorderColor",values); + defineCustomColorGroup("color.flat.menu.accelerator.fg", "Menu.acceleratorForeground",values); + + + defineCustomColorGroup("color.flat.focus.border", "Button.focusedBorderColor", values); + defineCustomColorGroup("color.flat.focus", "Component.focusColor", values); + defineCustomColorGroup("color.flat.focus.bg", "Button.focusedBackground", values); + defineCustomColorGroup("color.flat.checkmark", "CheckBox.icon.checkmarkColor", values); + defineCustomColorGroup("color.flat.disabled", "Button.disabledBorderColor", values); + defineCustomColorGroup("color.flat.disabled.selected", "Button.disabledSelectedBackground",values); + defineCustomColorGroup("color.flat.arrow", "Spinner.buttonArrowColor",values); + defineCustomColorGroup("color.flat.arrow.disabled", "Spinner.buttonDisabledArrowColor",values); + defineCustomColorGroup("color.flat.arrow.hover", "Spinner.buttonHoverArrowColor",values); + defineCustomColorGroup("color.flat.arrow.pressed", "Spinner.buttonPressedArrowColor",values); + + defineCustomColorGroup("color.flat.dropcell.bg", "List.dropCellBackground",values); + defineCustomColorGroup("color.flat.dropline", "List.dropLineColor",values); + defineCustomColorGroup("color.flat.underline", "MenuItem.underlineSelectionColor",values); + defineCustomColorGroup("color.flat.docking.bg", "ToolBar.dockingBackground",values); + defineCustomColorGroup("color.flat.progressbar.bg", "ProgressBar.background",values); + defineCustomColorGroup("color.flat.progressbar.fg", "ProgressBar.foreground",values); + defineCustomColorGroup("color.flat.icon.bg", "Tree.icon.openColor",values); + defineCustomColorGroup("color.flat.selection.inactive", "Tree.selectionInactiveBackground",values); + + + // @formatter:on + super.group(values); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FontNonUiResource.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FontNonUiResource.java new file mode 100644 index 0000000000..67aa2996dc --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/FontNonUiResource.java @@ -0,0 +1,28 @@ +/* ### + * 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 generic.theme.laf; + +import java.awt.Font; + +/** + * Font subclass for creating an non UIResource Font from a FontUIResource. (The Font constructor + * that takes a font was protected) + */ +public class FontNonUiResource extends Font { + public FontNonUiResource(Font font) { + super(font); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/GNimbusLookAndFeel.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/GNimbusLookAndFeel.java new file mode 100644 index 0000000000..e3f4528c02 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/GNimbusLookAndFeel.java @@ -0,0 +1,109 @@ +/* ### + * 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 generic.theme.laf; + +import java.awt.Color; +import java.awt.Font; +import java.util.List; + +import javax.swing.*; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.nimbus.NimbusLookAndFeel; + +import generic.theme.*; + +/** + * Extends the {@link NimbusLookAndFeel} to intercept the {@link #getDefaults()}. Nimbus does + * not honor changes to the UIDefaults after it is installed as the active + * {@link LookAndFeel}, so we have to make the changes at the time the UIDefaults are installed. + * + * To get around this issue, we extend the NimbusLookAndFeel + * so that we can install our GColors and overridden properties as Nimbus is being installed, + * specifically during the call to the getDefaults() method. For all other Look And Feels, the + * GColors and overridden properties are changed in the UIDefaults after the Look And Feel is + * installed, so they don't need to extends the Look and Feel class. + * + * Also, note that Nimbus needs to be reinstalled every time we need to make a change to any of the + * UIDefaults values, since it does not respond to changes other than when first installed. + */ +public class GNimbusLookAndFeel extends NimbusLookAndFeel { + private ApplicationThemeManager themeManager; + + GNimbusLookAndFeel(ApplicationThemeManager themeManager) { + this.themeManager = themeManager; + } + + @Override + public UIDefaults getDefaults() { + UIDefaults defaults = super.getDefaults(); + GThemeValueMap javaDefaults = extractJavaDefaults(defaults); + + // replace all colors with GColors + for (ColorValue colorValue : javaDefaults.getColors()) { + String id = colorValue.getId(); + defaults.put(id, themeManager.getGColorUiResource(id)); + } + + // put fonts back into defaults in case they have been changed by the current theme + for (FontValue fontValue : javaDefaults.getFonts()) { + String id = fontValue.getId(); + Font font = themeManager.getFont(id); + defaults.put(id, new FontUIResource(font)); + } + + // put icons back into defaults in case they have been changed by the current theme + for (IconValue iconValue : javaDefaults.getIcons()) { + String id = iconValue.getId(); + // because some icons are weird, put raw icons into defaults, only use GIcons for + // setting Icons explicitly on components + Icon icon = themeManager.getIcon(id); + defaults.put(id, icon); + } + + defaults.put("Label.textForeground", themeManager.getGColorUiResource("Label.foreground")); + themeManager.refreshGThemeValues(); + return defaults; + } + + protected GThemeValueMap extractJavaDefaults(UIDefaults defaults) { + GThemeValueMap javaDefaults = new GThemeValueMap(); + + List colorIds = + LookAndFeelManager.getLookAndFeelIdsForType(defaults, Color.class); + for (String id : colorIds) { + Color color = defaults.getColor(id); + ColorValue value = new ColorValue(id, color); + javaDefaults.addColor(value); + } + List fontIds = + LookAndFeelManager.getLookAndFeelIdsForType(defaults, Font.class); + for (String id : fontIds) { + Font font = defaults.getFont(id); + FontValue value = new FontValue(id, LookAndFeelManager.fromUiResource(font)); + javaDefaults.addFont(value); + } + List iconIds = + LookAndFeelManager.getLookAndFeelIdsForType(defaults, Icon.class); + for (String id : iconIds) { + Icon icon = defaults.getIcon(id); + javaDefaults.addIcon(new IconValue(id, icon)); + } + // need to set javaDefalts now to trigger building currentValues so the when + // we create GColors below, they can be resolved. + themeManager.setJavaDefaults(javaDefaults); + return javaDefaults; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/GtkLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/GtkLookAndFeelManager.java new file mode 100644 index 0000000000..edf22b089a --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/GtkLookAndFeelManager.java @@ -0,0 +1,29 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package generic.theme.laf; + +import generic.theme.ApplicationThemeManager; +import generic.theme.LafType; + +/** + * {@link LookAndFeelManager} for GTK + */ +public class GtkLookAndFeelManager extends LookAndFeelManager { + + public GtkLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.GTK, themeManager); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/LookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/LookAndFeelManager.java new file mode 100644 index 0000000000..3ba62a1971 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/LookAndFeelManager.java @@ -0,0 +1,506 @@ +/* ### + * 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 generic.theme.laf; + +import java.awt.*; +import java.util.*; +import java.util.List; +import java.util.Map.Entry; + +import javax.swing.*; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.plaf.*; + +import org.apache.commons.collections4.IteratorUtils; + +import generic.theme.*; +import generic.util.action.*; +import ghidra.util.Msg; +import ghidra.util.SystemUtilities; + +/** + * Manages installing and updating a {@link LookAndFeel} + */ +public abstract class LookAndFeelManager { + + /** + * These are color ids (see {@link GColor} used to represent general concepts that + * application developers can use to get the color for that concept as defined by + * a specific {@link LookAndFeel}. This class will define some standard default + * mappings in the constructor, but it is expected that each specific LookAndFeelManager + * will override these mappings with values appropriate for that LookAndFeel. + */ + protected static final String SYSTEM_APP_BACKGROUND_COLOR_ID = "system.color.bg.application"; + protected static final String SYSTEM_WIDGET_BACKGROUND_COLOR_ID = "system.color.bg.widget"; + protected static final String SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID = "system.color.bg.tooltip"; + protected static final String SYSTEM_BORDER_COLOR_ID = "system.color.border"; + + private LafType laf; + private Map fontRegistryMap = new HashMap<>(); + protected GThemeValueMap systemToLafMap = new GThemeValueMap(); + protected ApplicationThemeManager themeManager; + + protected LookAndFeelManager(LafType laf, ApplicationThemeManager themeManager) { + this.laf = laf; + this.themeManager = themeManager; + + // establish system color to LookAndFeel colors + systemToLafMap.addColor(new ColorValue(SYSTEM_APP_BACKGROUND_COLOR_ID, "control")); + systemToLafMap.addColor(new ColorValue(SYSTEM_WIDGET_BACKGROUND_COLOR_ID, "control")); + systemToLafMap.addColor(new ColorValue(SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID, "control")); + systemToLafMap.addColor(new ColorValue(SYSTEM_BORDER_COLOR_ID, "controlShadow")); + } + + /** + * Returns the {@link LafType} managed by this manager. + * @return the {@link LafType} + */ + public LafType getLookAndFeelType() { + return laf; + } + + /** + * Installs the {@link LookAndFeel} + * @throws ClassNotFoundException if the LookAndFeel + * class could not be found + * @throws InstantiationException if a new instance of the class + * couldn't be created + * @throws IllegalAccessException if the class or initializer isn't accessible + * @throws UnsupportedLookAndFeelException if + * lnf.isSupportedLookAndFeel() is false + */ + public void installLookAndFeel() throws ClassNotFoundException, InstantiationException, + IllegalAccessException, UnsupportedLookAndFeelException { + + cleanUiDefaults(); + themeManager.setSystemDefaults(systemToLafMap); + doInstallLookAndFeel(); + installJavaDefaults(); + fixupLookAndFeelIssues(); + installGlobalProperties(); + updateComponentUis(); + } + + /** + * Called when all colors, fonts, and icons may have changed + * @param javaDefaults the current set of java defaults so that those ids can be updated + * special as needed by the current {@link LookAndFeel} + */ + public void resetAll(GThemeValueMap javaDefaults) { + themeManager.refreshGThemeValues(); + resetIcons(javaDefaults); + resetFonts(javaDefaults); + updateAllRegisteredComponentFonts(); + updateComponentUis(); + } + + protected void updateAllRegisteredComponentFonts() { + for (ComponentFontRegistry register : fontRegistryMap.values()) { + register.updateComponentFonts(); + } + } + + private void resetFonts(GThemeValueMap javaDefaults) { + List fonts = javaDefaults.getFonts(); + UIDefaults defaults = UIManager.getDefaults(); + for (FontValue fontValue : fonts) { + String id = fontValue.getId(); + Font correctFont = Gui.getFont(id); + Font storedFont = defaults.getFont(id); + if (correctFont != null && !correctFont.equals(storedFont)) { + defaults.put(id, correctFont); + } + } + } + + private void resetIcons(GThemeValueMap javaDefaults) { + List icons = javaDefaults.getIcons(); + UIDefaults defaults = UIManager.getDefaults(); + for (IconValue iconValue : icons) { + String id = iconValue.getId(); + Icon correctIcon = Gui.getIcon(id); + Icon storedIcon = defaults.getIcon(id); + if (correctIcon != null && !correctIcon.equals(storedIcon)) { + defaults.put(id, correctIcon); + } + } + } + + /** + * Called when one or more colors have changed. + */ + public void colorsChanged() { + themeManager.refreshGThemeValues(); + repaintAll(); + } + + /** + * Called when one or more icons have changed. + * @param changedIconIds set of icon ids affected by this icon change + * @param newIcon the new icon to use for the given set of icon ids + */ + public void iconsChanged(Set changedIconIds, Icon newIcon) { + if (!(newIcon instanceof UIResource)) { + newIcon = new IconUIResource(newIcon); + } + if (!changedIconIds.isEmpty()) { + UIDefaults defaults = UIManager.getDefaults(); + for (String javaIconId : changedIconIds) { + defaults.put(javaIconId, newIcon); + } + updateComponentUis(); + } + themeManager.refreshGThemeValues(); + repaintAll(); + } + + /** + * Called when one or more fonts have changed. + * @param changedJavaFontIds the set of Java Font ids that are affected by this change + */ + public void fontsChanged(Set changedJavaFontIds) { + if (!changedJavaFontIds.isEmpty()) { + UIDefaults defaults = UIManager.getDefaults(); + for (String javaFontId : changedJavaFontIds) { + // even though all these derive from the new font, they might be different + // because of FontModifiers. + Font font = Gui.getFont(javaFontId); + defaults.put(javaFontId, new FontUIResource(font)); + } + updateComponentUis(); + } + updateAllRegisteredComponentFonts(); + repaintAll(); + } + + protected void updateComponentUis() { + for (Window window : Window.getWindows()) { + SwingUtilities.updateComponentTreeUI(window); + } + } + + protected void repaintAll() { + for (Window window : Window.getWindows()) { + window.repaint(); + } + } + + /** + * Binds the component to the font identified by the given font id. Whenever the font for + * the font id changes, the component will updated with the new font. + * @param component the component to set/update the font + * @param fontId the id of the font to register with the given component + */ + public void registerFont(Component component, String fontId) { + ComponentFontRegistry register = + fontRegistryMap.computeIfAbsent(fontId, id -> new ComponentFontRegistry(id)); + + register.addComponent(component); + } + + /** + * Returns a color that is not a {@link UIResource}. + * @param color the color to return an non UIResource color for + * @return a color that is not a {@link UIResource}. + */ + public static Color fromUiResource(Color color) { + if (color.getClass() == Color.class) { + return color; + } + return new Color(color.getRGB(), true); + } + + /** + * Returns a font that is not a {@link UIResource}. + * @param font the font to return an non UIResource font for + * @return a font that is not a {@link UIResource}. + */ + public static Font fromUiResource(Font font) { + if (font instanceof UIResource) { + return new FontNonUiResource(font); + } + return font; + } + + /** + * Subclass provide this method to install the specific loo + * @throws ClassNotFoundException if the LookAndFeel + * class could not be found + * @throws InstantiationException if a new instance of the class + * couldn't be created + * @throws IllegalAccessException if the class or initializer isn't accessible + * @throws UnsupportedLookAndFeelException if + * lnf.isSupportedLookAndFeel() is false + */ + protected void doInstallLookAndFeel() throws ClassNotFoundException, InstantiationException, + IllegalAccessException, UnsupportedLookAndFeelException { + String name = laf.getName(); + UIManager.setLookAndFeel(findLookAndFeelClassName(name)); + + } + + /** + * Subclass can override this method to do specific LookAndFeel fix ups + */ + protected void fixupLookAndFeelIssues() { + // no generic fix-ups at this time. + } + + /** + * Extracts java default colors, fonts, and icons and stores them in {@link Gui}. + */ + private void installJavaDefaults() { + GThemeValueMap javaDefaults = extractJavaDefaults(); + ThemeGrouper grouper = getThemeGrouper(); + grouper.group(javaDefaults); + themeManager.setJavaDefaults(javaDefaults); + installPropertiesBackIntoUiDefaults(javaDefaults); + } + + protected ThemeGrouper getThemeGrouper() { + return new ThemeGrouper(); + } + + private void installPropertiesBackIntoUiDefaults(GThemeValueMap javaDefaults) { + UIDefaults defaults = UIManager.getDefaults(); + + GTheme theme = themeManager.getActiveTheme(); + + // we replace java default colors with GColor equivalents so that we + // can change colors without having to reinstall ui on each component + // This trick only works for colors. Fonts and icons don't universally + // allow being wrapped like colors do. + for (ColorValue colorValue : javaDefaults.getColors()) { + String id = colorValue.getId(); + defaults.put(id, themeManager.getGColorUiResource(id)); + } + + // put fonts back into defaults in case they have been changed by the current theme + for (FontValue fontValue : javaDefaults.getFonts()) { + String id = fontValue.getId(); + FontValue themeValue = theme.getFont(id); + if (themeValue != null) { + Font font = Gui.getFont(id); + defaults.put(id, new FontUIResource(font)); + } + } + + // put icons back into defaults in case they have been changed by the current theme + for (IconValue iconValue : javaDefaults.getIcons()) { + String id = iconValue.getId(); + IconValue themeValue = theme.getIcon(id); + if (themeValue != null) { + // because some icons are weird, put raw icons into defaults, only use GIcons for + // setting Icons explicitly on components + Icon icon = Gui.getIcon(id); + defaults.put(id, icon); + } + } + } + + protected GThemeValueMap extractJavaDefaults() { + UIDefaults defaults = UIManager.getDefaults(); + GThemeValueMap values = new GThemeValueMap(); + // for now, just doing color properties. + List ids = getLookAndFeelIdsForType(defaults, Color.class); + for (String id : ids) { + // convert UIResource color to regular colors so if used, they don't get wiped + // out when we update the UIs + values.addColor(new ColorValue(id, fromUiResource(UIManager.getColor(id)))); + } + ids = getLookAndFeelIdsForType(defaults, Font.class); + for (String id : ids) { + // convert UIResource fonts to regular fonts so if used, they don't get wiped + // out when we update UIs + values.addFont(new FontValue(id, fromUiResource(UIManager.getFont(id)))); + } + ids = getLookAndFeelIdsForType(defaults, Icon.class); + for (String id : ids) { + Icon icon = UIManager.getIcon(id); + values.addIcon(new IconValue(id, icon)); + } + return values; + } + + protected String findLookAndFeelClassName(String lookAndFeelName) { + LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels(); + for (LookAndFeelInfo info : installedLookAndFeels) { + String className = info.getClassName(); + if (lookAndFeelName.equals(className) || lookAndFeelName.equals(info.getName())) { + return className; + } + } + + Msg.debug(this, "Unable to find requested Look and Feel: " + lookAndFeelName); + return UIManager.getSystemLookAndFeelClassName(); + } + + protected boolean isSupported(String lookAndFeelName) { + LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels(); + for (LookAndFeelInfo info : installedLookAndFeels) { + if (lookAndFeelName.equals(info.getName())) { + return true; + } + } + return false; + } + + protected void setKeyBinding(String existingKsText, String newKsText, String[] prefixValues) { + + KeyStroke existingKs = KeyStroke.getKeyStroke(existingKsText); + KeyStroke newKs = KeyStroke.getKeyStroke(newKsText); + + for (String properyPrefix : prefixValues) { + + UIDefaults defaults = UIManager.getDefaults(); + Object object = defaults.get(properyPrefix + ".focusInputMap"); + InputMap inputMap = (InputMap) object; + Object action = inputMap.get(existingKs); + inputMap.put(newKs, action); + } + } + + private void installGlobalLookAndFeelAttributes() { + // Fix up the default fonts that Java 1.5.0 changed to Courier, which looked terrible. + Font f = new Font("Monospaced", Font.PLAIN, 12); + UIManager.put("PasswordField.font", f); + UIManager.put("TextArea.font", f); + + // We like buttons that change on hover, so force that to happen (see Tracker SCR 3966) + UIManager.put("Button.rollover", Boolean.TRUE); + UIManager.put("ToolBar.isRollover", Boolean.TRUE); + } + + private void installPopupMenuSettingsOverride() { + // Java 1.6 UI consumes MousePressed event when dismissing popup menu + // which prevents application components from getting this event. + UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE); + } + + private void installGlobalFontSizeOverride() { + + // only set a global size if the property is set + Integer overrideFontInteger = SystemUtilities.getFontSizeOverrideValue(); + if (overrideFontInteger == null) { + return; + } + + setGlobalFontSizeOverride(overrideFontInteger); + } + + private void installCustomLookAndFeelActions() { + // these prefixes are for text components + String[] UIPrefixValues = + { "TextField", "FormattedTextField", "TextArea", "TextPane", "EditorPane" }; + + DeleteToStartOfWordAction deleteToStartOfWordAction = new DeleteToStartOfWordAction(); + registerAction(deleteToStartOfWordAction, DeleteToStartOfWordAction.KEY_STROKE, + UIPrefixValues); + + DeleteToEndOfWordAction deleteToEndOfWordAction = new DeleteToEndOfWordAction(); + registerAction(deleteToEndOfWordAction, DeleteToEndOfWordAction.KEY_STROKE, UIPrefixValues); + + BeginningOfLineAction beginningOfLineAction = new BeginningOfLineAction(); + registerAction(beginningOfLineAction, BeginningOfLineAction.KEY_STROKE, UIPrefixValues); + + EndOfLineAction endOfLineAction = new EndOfLineAction(); + registerAction(endOfLineAction, EndOfLineAction.KEY_STROKE, UIPrefixValues); + + SelectBeginningOfLineAction selectBeginningOfLineAction = new SelectBeginningOfLineAction(); + registerAction(selectBeginningOfLineAction, SelectBeginningOfLineAction.KEY_STROKE, + UIPrefixValues); + + SelectEndOfLineAction selectEndOfLineAction = new SelectEndOfLineAction(); + registerAction(selectEndOfLineAction, SelectEndOfLineAction.KEY_STROKE, UIPrefixValues); + } + + /** Allows you to globally set the font size (don't use this method!) */ + private void setGlobalFontSizeOverride(int fontSize) { + UIDefaults defaults = UIManager.getDefaults(); + + Set> set = defaults.entrySet(); + Iterator> iterator = set.iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + Object key = entry.getKey(); + + if (key.toString().toLowerCase().indexOf("font") != -1) { + Font currentFont = defaults.getFont(key); + if (currentFont != null) { + Font newFont = currentFont.deriveFont((float) fontSize); + UIManager.put(key, newFont); + } + } + } + } + + private void registerAction(Action action, KeyStroke keyStroke, String[] prefixValues) { + for (String properyPrefix : prefixValues) { + UIDefaults defaults = UIManager.getDefaults(); + Object object = defaults.get(properyPrefix + ".focusInputMap"); + InputMap inputMap = (InputMap) object; + inputMap.put(keyStroke, action); + } + } + + private void installGlobalProperties() { + installGlobalLookAndFeelAttributes(); + installGlobalFontSizeOverride(); + installCustomLookAndFeelActions(); + installPopupMenuSettingsOverride(); + } + + private void cleanUiDefaults() { + GThemeValueMap javaDefaults = themeManager.getJavaDefaults(); + if (javaDefaults == null) { + return; + } + UIDefaults defaults = UIManager.getDefaults(); + for (ColorValue colorValue : javaDefaults.getColors()) { + String id = colorValue.getId(); + defaults.put(id, null); + } + for (FontValue fontValue : javaDefaults.getFonts()) { + String id = fontValue.getId(); + defaults.put(id, null); + } + for (IconValue iconValue : javaDefaults.getIcons()) { + String id = iconValue.getId(); + defaults.put(id, null); + } + } + + /** + * Searches the given UIDefaults for ids whose value matches the given class + * @param defaults the UIDefaults to search + * @param clazz the value class to look for (i.e., Color, Font, or Icon) + * @return the list of ids whose value is of the given class type. + */ + public static List getLookAndFeelIdsForType(UIDefaults defaults, Class clazz) { + List colorKeys = new ArrayList<>(); + List keyList = IteratorUtils.toList(defaults.keys().asIterator()); + for (Object key : keyList) { + if (key instanceof String) { + Object value = defaults.get(key); + if (clazz.isInstance(value)) { + colorKeys.add((String) key); + } + } + } + return colorKeys; + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MacLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MacLookAndFeelManager.java new file mode 100644 index 0000000000..7c6caf885f --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MacLookAndFeelManager.java @@ -0,0 +1,31 @@ +/* ### + * 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 generic.theme.laf; + +import generic.theme.ApplicationThemeManager; +import generic.theme.LafType; + +public class MacLookAndFeelManager extends LookAndFeelManager { + + public MacLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.MAC, themeManager); + } + + @Override + protected ThemeGrouper getThemeGrouper() { + return new MacThemeGrouper(); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MacThemeGrouper.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MacThemeGrouper.java new file mode 100644 index 0000000000..7411e7abe7 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MacThemeGrouper.java @@ -0,0 +1,38 @@ +/* ### + * 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 generic.theme.laf; + +import generic.theme.GThemeValueMap; + +/** + * Adds specialized groupings unique to the Mac LookAndFeel + */ +public class MacThemeGrouper extends ThemeGrouper { + + @Override + public void group(GThemeValueMap values) { + // @formatter:off + defineCustomColorGroup("color.mac.disabled.fg", "Menu.disabledForeground", values); + defineCustomColorGroup("color.mac.button.select", "Button.select", values); + defineCustomColorGroup("color.mac.menu.select", "Menu.selectionBackground",values); + defineCustomColorGroup("color.mac.seletion.inactive.bg", "List.selectionInactiveBackground",values);//d4d4d4 + + defineCustomFontGroup("font.mac.small.font", "IconButton.font", values); + // @formatter:on + super.group(values); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MetalLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MetalLookAndFeelManager.java new file mode 100644 index 0000000000..0eb565025e --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MetalLookAndFeelManager.java @@ -0,0 +1,26 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package generic.theme.laf; + +import generic.theme.ApplicationThemeManager; +import generic.theme.LafType; + +public class MetalLookAndFeelManager extends LookAndFeelManager { + + public MetalLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.METAL, themeManager); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MotifLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MotifLookAndFeelManager.java new file mode 100644 index 0000000000..ba8421359e --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MotifLookAndFeelManager.java @@ -0,0 +1,55 @@ +/* ### + * 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 generic.theme.laf; + +import generic.theme.*; + +/** + * Motif {@link LookAndFeelManager}. Specialized so that it can return the Motif installer + */ +public class MotifLookAndFeelManager extends LookAndFeelManager { + + public MotifLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.MOTIF, themeManager); + // establish system color to LookAndFeel colors + systemToLafMap.addColor(new ColorValue(SYSTEM_APP_BACKGROUND_COLOR_ID, "control")); + systemToLafMap.addColor(new ColorValue(SYSTEM_WIDGET_BACKGROUND_COLOR_ID, "window")); + systemToLafMap.addColor(new ColorValue(SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID, "info")); + systemToLafMap.addColor(new ColorValue(SYSTEM_BORDER_COLOR_ID, "activeCaptionBorder")); + } + + @Override + protected void fixupLookAndFeelIssues() { + // + // The Motif LaF does not bind copy/paste/cut to Control-C/V/X by default. Rather, they + // only use the COPY/PASTE/CUT keys. The other LaFs bind both shortcuts. + // + + // these prefixes are for text components + String[] UIPrefixValues = + { "TextField", "FormattedTextField", "TextArea", "TextPane", "EditorPane" }; + + setKeyBinding("COPY", "ctrl C", UIPrefixValues); + setKeyBinding("PASTE", "ctrl V", UIPrefixValues); + setKeyBinding("CUT", "ctrl X", UIPrefixValues); + } + + @Override + protected ThemeGrouper getThemeGrouper() { + return new MotifThemeGrouper(); + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/PixelType.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MotifThemeGrouper.java similarity index 51% rename from Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/PixelType.java rename to Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MotifThemeGrouper.java index a37178780c..0b584e932d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/spaceview/PixelType.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/MotifThemeGrouper.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,50 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.app.plugin.core.spaceview; +package generic.theme.laf; -public enum PixelType { - UNUSED_TYPE, - ERROR, +import generic.theme.GThemeValueMap; - UNINIT_UNUSED, - UNINIT_DATA, +/** + * Adds specialized groupings unique to the Motif LookAndFeel + */ +public class MotifThemeGrouper extends ThemeGrouper { + public MotifThemeGrouper() { - EXTERNAL, - - UNDEF_DATA0, - UNDEF_DATA1, - UNDEF_DATA2, - UNDEF_DATA3, - UNDEF_DATA4, - UNDEF_DATA5, - UNDEF_DATA6, - UNDEF_DATA7, - - DEF_DATA0, - DEF_DATA1, - DEF_DATA2, - DEF_DATA3, - DEF_DATA4, - DEF_DATA5, - DEF_DATA6, - DEF_DATA7, - - CODE_MEMORY, - CODE_FLOW, - CODE_SPECIAL, - CODE_NORMAL, - - FUN_CODE_MEMORY, - FUN_CODE_FLOW, - FUN_CODE_SPECIAL, - FUN_CODE_NORMAL, - - SELECTED, - HIGHLIGHTED, - SEL_AND_HIGH; - - public byte type() { - return (byte) ordinal(); } + + @Override + public void group(GThemeValueMap values) { + defineCustomFontGroup("font.monospaced", "Spinner.font", values); + + super.group(values); + } + } diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/NimbusLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/NimbusLookAndFeelManager.java new file mode 100644 index 0000000000..e2d9414c31 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/NimbusLookAndFeelManager.java @@ -0,0 +1,107 @@ +/* ### + * 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 generic.theme.laf; + +import java.awt.Dimension; +import java.util.Set; + +import javax.swing.*; + +import generic.theme.*; +import ghidra.util.exception.AssertException; + +/** + * Nimbus {@link LookAndFeelManager}. Specialized so that it can return the Nimbus installer and + * do specialized updating when icons or fonts change. Basically, needs to re-install a new + * instance of the Nimbus LookAndFeel each time a font or icon changes + */ +public class NimbusLookAndFeelManager extends LookAndFeelManager { + + public NimbusLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.NIMBUS, themeManager); + + // establish system color specific to Nimbus + systemToLafMap.addColor(new ColorValue(SYSTEM_BORDER_COLOR_ID, "nimbusBorder")); + } + + @Override + public void resetAll(GThemeValueMap javaDefaults) { + themeManager.refreshGThemeValues(); + reinstallNimubus(); + } + + @Override + public void fontsChanged(Set affectedJavaIds) { + if (!affectedJavaIds.isEmpty()) { + reinstallNimubus(); + } + updateAllRegisteredComponentFonts(); + repaintAll(); + } + + @Override + public void iconsChanged(Set affectedJavaIds, Icon newIcon) { + if (!affectedJavaIds.isEmpty()) { + reinstallNimubus(); + } + themeManager.refreshGThemeValues(); + repaintAll(); + } + + private void reinstallNimubus() { + try { + UIManager.setLookAndFeel(new GNimbusLookAndFeel(themeManager) { + @Override + protected GThemeValueMap extractJavaDefaults(UIDefaults defaults) { + return themeManager.getJavaDefaults(); + } + }); + } + catch (UnsupportedLookAndFeelException e) { + throw new AssertException("This can't happen, we are just re-installing the same L&F"); + } + updateComponentUis(); + } + + @Override + protected void doInstallLookAndFeel() throws UnsupportedLookAndFeelException { + UIManager.setLookAndFeel(new GNimbusLookAndFeel(themeManager)); + } + + @Override + protected GThemeValueMap extractJavaDefaults() { + // The GNimbusLookAndFeel already extracted the java defaults and installed them in the Gui + return themeManager.getJavaDefaults(); + } + + @Override + protected ThemeGrouper getThemeGrouper() { + return new NimbusThemeGrouper(); + } + + @Override + protected void fixupLookAndFeelIssues() { + super.fixupLookAndFeelIssues(); + + // fix scroll bar grabber disappearing. See https://bugs.openjdk.java.net/browse/JDK-8134828 + // This fix looks like it should not cause harm even if the bug is fixed on the jdk side. + UIDefaults defaults = UIManager.getDefaults(); + defaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30)); + + // (see NimbusDefaults for key values that can be changed here) + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/NimbusThemeGrouper.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/NimbusThemeGrouper.java new file mode 100644 index 0000000000..8c977d3ee1 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/NimbusThemeGrouper.java @@ -0,0 +1,43 @@ +/* ### + * 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 generic.theme.laf; + +import generic.theme.GThemeValueMap; + +/** + * Adds specialized groupings unique to the Nimbus LookAndFeel + */ +public class NimbusThemeGrouper extends ThemeGrouper { + public NimbusThemeGrouper() { + // Nimbus defines a new type of button + buttonGroup.addComponents("ArrowButton"); + + // Nimbus defines some other color sources + colorSourceProperties.add("nimbusFocus"); + colorSourceProperties.add("nimbusOrange"); + colorSourceProperties.add("nimbusBorder"); + + } + + @Override + public void group(GThemeValueMap values) { + defineCustomColorGroup("color.nimbus.text.alt", "Menu.foreground", values); + defineCustomFontGroup("font.titledborder", "TitledBorder.font", values); + + super.group(values); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/ThemeGrouper.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/ThemeGrouper.java new file mode 100644 index 0000000000..420e5ee782 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/ThemeGrouper.java @@ -0,0 +1,452 @@ +/* ### + * 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 generic.theme.laf; + +import java.awt.Color; +import java.awt.Font; +import java.util.*; + +import javax.swing.LookAndFeel; +import javax.swing.plaf.basic.BasicLookAndFeel; + +import generic.theme.*; + +/** + * Organizes UIDefaults color and font properties into groups so that every property doesn't + * have its own direct value. The idea is that users can affect many properties that have the + * same value by just changing the value for the group. For colors, the {@link LookAndFeel}s + * organize the properties internally and this class attempts to restore that organization + * as much as possible by using the values defined in the {@link BasicLookAndFeel} such as + * "control", "window", "controlShadlow", etc. The fonts don't appear to have any such internal + * organization, so we created our own groups and used a lookAndFeel property to initialize each + * group source value. Then whenever the font matched a group source value, the font is replace + * with an indirect reference to the group source font value. + *

+ * This class is sometimes sub-classed for a particular {@link LookAndFeel}. The subclass can + * create new groups and mappings that are unique to that LookAndFeel. + * + * Often, many of the various group source ids have the same color value. To try to group + * properties as defined in BasicLookAndFeel, the preferred source ids are + * defined for each group. These will be tried first, but if a match isn't found among the + * preferred sources, then all the sources will be searched for a match + */ +public class ThemeGrouper { + private static String DEFAULT_FONT_GROUP_ID = "font.default"; + private static String BUTTON_FONT_GROUP_ID = "font.button"; + private static String TEXT_FONT_GROUP_ID = "font.text"; + private static String WIDGET_FONT_GROUP_ID = "font.widget"; + private static String COMPONENT_FONT_GROUP_ID = "font.component"; + private static String MENU_FONT_GROUP_ID = "font.menu"; + private static String MENU_ACCELERATOR_FONT_GROUP_ID = "font.menu.accelerator"; + + static List DEFAULT_FONT_SOURCE_PROPERTIES = List.of( + DEFAULT_FONT_GROUP_ID, + COMPONENT_FONT_GROUP_ID, + WIDGET_FONT_GROUP_ID, + TEXT_FONT_GROUP_ID, + BUTTON_FONT_GROUP_ID, + MENU_FONT_GROUP_ID, + MENU_ACCELERATOR_FONT_GROUP_ID); + + // The list of color properties (defined in BasicLookAndFeel) that are used to populate + // other component specific colors. + // The order is important. If any have the same color value, the one higher in the list is used. + // Individual groups (buttons, menus, etc.) may define a different order that is more specific + // to that group + public static List DEFAULT_COLOR_SOURCE_PROPERTIES = List.of( + "control", + "window", + "activeCaption", + "activeCaptionBorder", + "activeCaptionText", + "controlDkShadow", + "controlHighlight", + "controlLtHighlight", + "controlShadow", + "controlText", + "desktp", + "inactiveCaption", + "inactiveCaptionBorder", + "inactiveCaptionText", + "info", + "infoText", + "menu", + "menuText", + "scrollbar", + "scrollBarTrack", + "text", + "textHighlight", + "textHighlightText", + "textInactiveText", + "textText", + "windowBorder", + "windowText"); + + private static final String[] BUTTON_GROUP = { + "Button", + "ToggleButton", + "RadioButton", + "CheckBox" + }; + private static final String[] MENU_GROUP = { + "Menu", + "MenuBar", + "MenuItem", + "PopupMenu", + "RadioButtonMenuItem", + "CheckBoxMenuItem" + }; + private static final String[] TEXT_GROUP = { + "TextField", + "FormattedTextField", + "PasswordField", + "TextArea", + "TextPane", + "EditorPane" + }; + private static final String[] WIDGET_GROUP = { + "FileChooser", + "ColorChooser", + "ComboBox", + "List", + "Table", + "Tree" + }; + private static final String[] COMPONENT_GROUP = { + "Desktop", + "Panel", + "InternalFrame", + "Label", + "OptionPane", + "ProgressBar", + "Separator", + "ScrollBar", + "ScrollPane", + "Viewport", + "Slider", + "Spinner", + "SplitPane", + "TabbedPane", + "TableHeader", + "TitledBorder", + "ToolBar", + "ToolTip" + }; + + private static final String[] BUTTON_PREFERRED_SOURCES = { + "control", + "controlText", + "controlShadow", + "controlDkShadow", + "controlHighlight", + "controlLtHighlight" + }; + private static final String[] MENU_PREFERRED_SOURCES = { + "menu", + "menuText", + "textHighlightText", + "textHighlight", + "controlShadow", + "controlDkShadow", + "controlHighlight", + "controlLtHighlight" + }; + private static final String[] TEXT_PREFERRED_SOURCES = { + "window", + "text", + "textText", + "textInactiveText", + "textHighlight", + "textHighlightText", + "controlShadow", + "controlDkShadow", + "controlHighlight", + "controlLtHighlight" + }; + private static final String[] WIDGET_PREFERRED_SOURCES = { + "window", + "textText", + "textHighlight", + "textHighlightText", + "control", + "controlShadow", + "controlDkShadow", + "controlHighlight", + "controlLtHighlight" + }; + private static final String[] COMPONENT_PREFERRED_SOURCES = { + "control", + "controlText", + "controlShadow", + "controlDkShadow", + "controlHighlight", + "controlLtHighlight", + "textText", + "textHighlight" + }; + + protected List colorSourceProperties; + protected List fontSourceProperties; + protected Set groups; + protected PropertyGroup buttonGroup = new PropertyGroup(BUTTON_GROUP, BUTTON_PREFERRED_SOURCES); + protected PropertyGroup menuGroup = new PropertyGroup(MENU_GROUP, MENU_PREFERRED_SOURCES); + protected PropertyGroup widgetGroup = new PropertyGroup(WIDGET_GROUP, WIDGET_PREFERRED_SOURCES); + protected PropertyGroup textGroup = new PropertyGroup(TEXT_GROUP, TEXT_PREFERRED_SOURCES); + protected PropertyGroup componentGroup = + new PropertyGroup(COMPONENT_GROUP, COMPONENT_PREFERRED_SOURCES); + + public ThemeGrouper() { + colorSourceProperties = new ArrayList<>(DEFAULT_COLOR_SOURCE_PROPERTIES); + fontSourceProperties = new ArrayList<>(DEFAULT_FONT_SOURCE_PROPERTIES); + groups = getPropertyGroups(); + } + + /** + * Replaces direct property values in the given GThemeValueMap with indirect references + * using the values from match source ids. + * @param values the values to search and replace source matches + */ + public void group(GThemeValueMap values) { + initialize(values); + Map groupMap = buildGroupMap(values); + groupColors(values, groupMap); + groupFonts(values, groupMap); + } + + /** + * Defines a new color id that will be used as the reference value for any specific color ids that + * have the same color value. This will allow all those specific colors to be changed at once. + * @param customGroupColorName name of a higher level group color id that will be used as the + * value for more specific color ids defined by the lookAndFeel. + * @param lookAndFeelSourceId the lookAndFeel color id whose value will be used as the value + * for the new custom group color id + * @param values the map where we store the default theme value mappings + */ + protected void defineCustomColorGroup(String customGroupColorName, String lookAndFeelSourceId, + GThemeValueMap values) { + + colorSourceProperties.add(customGroupColorName); + ColorValue colorValue = values.getColor(lookAndFeelSourceId); + if (colorValue != null) { + Color color = colorValue.get(values); + values.addColor(new ColorValue(customGroupColorName, color)); + } + } + + /** + * Defines a new font id that will be used as the reference value for any specific font ids that + * have the same font value. This will allow all those specific fonts to be changed at once. + * @param customGroupFontName name of a higher level group font id that will be used as the + * value of more specific font ids defined by the lookAndFeel. + * @param lookAndFeelSourceId the lookAndFeel font id whose value will be used as the value + * for the new custom group font id + * @param values the map where we store the default theme value mappings + */ + protected void defineCustomFontGroup(String customGroupFontName, String lookAndFeelSourceId, + GThemeValueMap values) { + fontSourceProperties.add(customGroupFontName); + FontValue fontValue = values.getFont(lookAndFeelSourceId); + if (fontValue != null) { + Font font = fontValue.get(values); + values.addFont(new FontValue(customGroupFontName, font)); + } + } + + private void groupColors(GThemeValueMap values, Map groupMap) { + Set skip = new HashSet<>(colorSourceProperties); // we don't want to map sources + Map defaultColorMapping = buildColorToSourceMap(values); + // try to map each color property to a source property (e.g., Button.background -> control) + for (ColorValue colorValue : values.getColors()) { + String id = colorValue.getId(); + if (colorValue.isIndirect() || skip.contains(id)) { + continue; + } + PropertyGroup group = groupMap.get(getComponentName(id)); + int rgb = colorValue.getRawValue().getRGB(); + String sourceProperty = group == null ? null : group.getSourceProperty(rgb); + if (sourceProperty == null) { + sourceProperty = defaultColorMapping.get(rgb); + } + + if (sourceProperty != null) { + values.addColor(new ColorValue(id, sourceProperty)); + } + } + } + + private void groupFonts(GThemeValueMap values, Map groupMap) { + Set skip = new HashSet<>(fontSourceProperties); // we don't want to map sources + Map defaultFontMapping = buildFontToSourceMap(values); + + // try to map each color property to a source property (e.g., Button.background -> control) + for (FontValue fontValue : values.getFonts()) { + String id = fontValue.getId(); + if (fontValue.isIndirect() || skip.contains(id)) { + continue; + } + Font font = fontValue.getRawValue(); + PropertyGroup group = groupMap.get(getComponentName(id)); + String sourceProperty = group == null ? null : group.getSourceProperty(font); + if (sourceProperty == null) { + sourceProperty = defaultFontMapping.get(font); + } + if (sourceProperty != null) { + values.addFont(new FontValue(id, sourceProperty)); + } + } + } + + private void initialize(GThemeValueMap values) { + // initialized default font to the Panel's font + FontValue defaultFontValue = values.getFont("Panel.font"); + if (defaultFontValue != null) { + values.addFont(new FontValue(DEFAULT_FONT_GROUP_ID, defaultFontValue.get(values))); + } + + // initialize the default group fonts to a font from an exemplar property in that group + initializeFontGroup(buttonGroup, BUTTON_FONT_GROUP_ID, "Button.font", values); + initializeFontGroup(textGroup, TEXT_FONT_GROUP_ID, "TextField.font", values); + initializeFontGroup(widgetGroup, WIDGET_FONT_GROUP_ID, "Table.font", values); + initializeFontGroup(componentGroup, COMPONENT_FONT_GROUP_ID, "Panel.font", values); + initializeFontGroup(menuGroup, MENU_FONT_GROUP_ID, "Menu.font", values); + initializeFontGroup(menuGroup, MENU_ACCELERATOR_FONT_GROUP_ID, "Menu.acceleratorFont", + values); + } + + private void initializeFontGroup(PropertyGroup group, String fontGroupId, String exemplarId, + GThemeValueMap values) { + FontValue fontValue = values.getFont(exemplarId); + if (fontValue != null) { + Font font = fontValue.getRawValue(); + values.addFont(new FontValue(fontGroupId, font)); + group.addFontMapping(font, fontGroupId); + } + } + + private Set getPropertyGroups() { + Set set = new HashSet<>(); + set.add(buttonGroup); + set.add(menuGroup); + set.add(textGroup); + set.add(widgetGroup); + set.add(componentGroup); + return set; + } + + private Map buildGroupMap(GThemeValueMap values) { + Map map = new HashMap<>(); + for (PropertyGroup group : groups) { + group.initialize(values); + group.populateGroupMap(map); + } + return map; + } + + private String getComponentName(String id) { + int dotIndex = id.indexOf("."); + if (dotIndex < 0) { + return id; + } + return id.substring(0, dotIndex); + } + + private Map buildColorToSourceMap(GThemeValueMap values) { + Map colorMapping = new HashMap<>(); + ArrayList reversed = new ArrayList<>(colorSourceProperties); + Collections.reverse(reversed); + // go through in reverse order so that values at the top of the list have precedence + // if multiple propertyBases have the save value. + for (String propertyBase : reversed) { + ColorValue colorValue = values.getColor(propertyBase); + if (colorValue != null) { + Color color = colorValue.get(values); + colorMapping.put(color.getRGB(), propertyBase); + } + } + return colorMapping; + } + + private Map buildFontToSourceMap(GThemeValueMap values) { + Map fontMapping = new HashMap<>(); + ArrayList reversed = new ArrayList<>(fontSourceProperties); + Collections.reverse(reversed); + // go through in reverse order so that values at the top of the list have precedence + // if multiple propertyBases have the save value. + for (String propertyBase : reversed) { + FontValue fontValue = values.getFont(propertyBase); + if (fontValue != null) { + Font font = fontValue.get(values); + fontMapping.put(font, propertyBase); + } + } + return fontMapping; + } + + static class PropertyGroup { + private Set groupComponents = new HashSet<>(); + private List preferredPropertyColorSources = new ArrayList<>(); + private Map colorMapping; + private Map fontMapping = new HashMap<>(); + + PropertyGroup(String[] components, String[] perferredSources) { + addComponents(components); + addPreferredColorSources(perferredSources); + } + + String getSourceProperty(int rgb) { + return colorMapping.get(rgb); + } + + String getSourceProperty(Font font) { + return fontMapping.get(font); + } + + void populateGroupMap(Map groupMap) { + for (String component : groupComponents) { + groupMap.put(component, this); + } + } + + void addPreferredColorSources(String... preferedColorSources) { + this.preferredPropertyColorSources.addAll(Arrays.asList(preferedColorSources)); + } + + void addComponents(String... properties) { + groupComponents.addAll(Arrays.asList(properties)); + } + + void addFontMapping(Font font, String sourceId) { + fontMapping.put(font, sourceId); + } + + private Map initialize(GThemeValueMap values) { + colorMapping = new HashMap<>(); + ArrayList reversed = new ArrayList<>(preferredPropertyColorSources); + Collections.reverse(reversed); + // go through in reverse order so that values at the top of the list have precedence + // if multiple propertyBases have the save value. + for (String propertyBase : reversed) { + ColorValue colorValue = values.getColor(propertyBase); + if (colorValue != null) { + Color color = colorValue.get(values); + colorMapping.put(color.getRGB(), propertyBase); + } + } + return colorMapping; + } + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/WindowsClassicLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/WindowsClassicLookAndFeelManager.java new file mode 100644 index 0000000000..c6ba737d0e --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/WindowsClassicLookAndFeelManager.java @@ -0,0 +1,26 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package generic.theme.laf; + +import generic.theme.ApplicationThemeManager; +import generic.theme.LafType; + +public class WindowsClassicLookAndFeelManager extends LookAndFeelManager { + + public WindowsClassicLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.WINDOWS_CLASSIC, themeManager); + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/WindowsLookAndFeelManager.java b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/WindowsLookAndFeelManager.java new file mode 100644 index 0000000000..ab86b2c231 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/generic/theme/laf/WindowsLookAndFeelManager.java @@ -0,0 +1,27 @@ +/* ### + * 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 generic.theme.laf; + +import generic.theme.ApplicationThemeManager; +import generic.theme.LafType; + +public class WindowsLookAndFeelManager extends LookAndFeelManager { + + public WindowsLookAndFeelManager(ApplicationThemeManager themeManager) { + super(LafType.WINDOWS, themeManager); + } + +} diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/BeginningOfLineAction.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/BeginningOfLineAction.java similarity index 97% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/BeginningOfLineAction.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/BeginningOfLineAction.java index 62e488c352..a0645de482 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/BeginningOfLineAction.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/BeginningOfLineAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; import java.awt.Component; import java.awt.event.ActionEvent; diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/DeleteToEndOfWordAction.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/DeleteToEndOfWordAction.java similarity index 96% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/DeleteToEndOfWordAction.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/DeleteToEndOfWordAction.java index 116649b2b8..79537d5ca2 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/DeleteToEndOfWordAction.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/DeleteToEndOfWordAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; import java.awt.Component; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import javax.swing.*; import javax.swing.text.*; -import docking.DockingUtils; - /** * An action to delete from the cursor position to the end of the current word. */ public class DeleteToEndOfWordAction extends TextAction { public static final KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, - DockingUtils.CONTROL_KEY_MODIFIER_MASK); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); private static final String ACTION_NAME = "delete-to-end-of-word-word"; public DeleteToEndOfWordAction() { diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/DeleteToStartOfWordAction.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/DeleteToStartOfWordAction.java similarity index 96% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/DeleteToStartOfWordAction.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/DeleteToStartOfWordAction.java index 3bf976ba2f..9886bfe7ae 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/DeleteToStartOfWordAction.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/DeleteToStartOfWordAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,24 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; import java.awt.Component; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import javax.swing.*; import javax.swing.text.*; -import docking.DockingUtils; - /** * An action to delete from the cursor position to the beginning of the current word, backwards. */ public class DeleteToStartOfWordAction extends TextAction { public static final KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, - DockingUtils.CONTROL_KEY_MODIFIER_MASK); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); private static final String ACTION_NAME = "delete-to-start-of-word"; public DeleteToStartOfWordAction() { diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/EndOfLineAction.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/EndOfLineAction.java similarity index 97% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/EndOfLineAction.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/EndOfLineAction.java index 4836f0333a..2a204ca9e2 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/EndOfLineAction.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/EndOfLineAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; import java.awt.Component; import java.awt.event.ActionEvent; diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/ReservedKeyBindings.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/ReservedKeyBindings.java similarity index 67% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/ReservedKeyBindings.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/ReservedKeyBindings.java index 025c116c48..0cfbe6c692 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/ReservedKeyBindings.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/ReservedKeyBindings.java @@ -13,17 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; +import java.awt.Toolkit; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import javax.swing.KeyStroke; -import docking.DockingUtils; - public class ReservedKeyBindings { + private static final int CONTROL_KEY_MODIFIER_MASK = + Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx(); + private ReservedKeyBindings() { // utils class } @@ -31,23 +33,24 @@ public class ReservedKeyBindings { public static final KeyStroke HELP_KEY1 = KeyStroke.getKeyStroke(KeyEvent.VK_HELP, 0); public static final KeyStroke HELP_KEY2 = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0); public static final KeyStroke HELP_INFO_KEY = - KeyStroke.getKeyStroke(KeyEvent.VK_F1, DockingUtils.CONTROL_KEY_MODIFIER_MASK); + KeyStroke.getKeyStroke(KeyEvent.VK_F1, CONTROL_KEY_MODIFIER_MASK); public static final KeyStroke CONTEXT_MENU_KEY1 = KeyStroke.getKeyStroke(KeyEvent.VK_F10, InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke CONTEXT_MENU_KEY2 = KeyStroke.getKeyStroke(KeyEvent.VK_CONTEXT_MENU, 0); - public static final KeyStroke FOCUS_INFO_KEY = - KeyStroke.getKeyStroke(KeyEvent.VK_F2, DockingUtils.CONTROL_KEY_MODIFIER_MASK | - InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); - public static final KeyStroke FOCUS_CYCLE_INFO_KEY = - KeyStroke.getKeyStroke(KeyEvent.VK_F3, DockingUtils.CONTROL_KEY_MODIFIER_MASK | - InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + public static final KeyStroke FOCUS_INFO_KEY = KeyStroke.getKeyStroke(KeyEvent.VK_F2, + CONTROL_KEY_MODIFIER_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + public static final KeyStroke FOCUS_CYCLE_INFO_KEY = KeyStroke.getKeyStroke(KeyEvent.VK_F3, + CONTROL_KEY_MODIFIER_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke UPDATE_KEY_BINDINGS_KEY = KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0); + public static final KeyStroke COMPONENT_THEME_INFO_KEY = KeyStroke.getKeyStroke(KeyEvent.VK_F9, + CONTROL_KEY_MODIFIER_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + public static boolean isReservedKeystroke(KeyStroke keyStroke) { int code = keyStroke.getKeyCode(); if (code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_ALT || code == KeyEvent.VK_CONTROL || @@ -55,7 +58,8 @@ public class ReservedKeyBindings { HELP_KEY1.equals(keyStroke) || HELP_KEY2.equals(keyStroke) || HELP_INFO_KEY.equals(keyStroke) || UPDATE_KEY_BINDINGS_KEY.equals(keyStroke) || FOCUS_INFO_KEY.equals(keyStroke) || FOCUS_CYCLE_INFO_KEY.equals(keyStroke) || - CONTEXT_MENU_KEY1.equals(keyStroke) || CONTEXT_MENU_KEY2.equals(keyStroke)) { + COMPONENT_THEME_INFO_KEY.equals(keyStroke) || CONTEXT_MENU_KEY1.equals(keyStroke) || + CONTEXT_MENU_KEY2.equals(keyStroke)) { return true; } diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/SelectBeginningOfLineAction.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/SelectBeginningOfLineAction.java similarity index 97% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/SelectBeginningOfLineAction.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/SelectBeginningOfLineAction.java index 66aa713eaa..e96e2a2920 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/SelectBeginningOfLineAction.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/SelectBeginningOfLineAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; import java.awt.Component; import java.awt.event.*; diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/SelectEndOfLineAction.java b/Ghidra/Framework/Generic/src/main/java/generic/util/action/SelectEndOfLineAction.java similarity index 97% rename from Ghidra/Framework/Docking/src/main/java/ghidra/util/SelectEndOfLineAction.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/action/SelectEndOfLineAction.java index cdef00517f..1644370325 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/SelectEndOfLineAction.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/action/SelectEndOfLineAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.util; +package generic.util.action; import java.awt.Component; import java.awt.event.*; diff --git a/Ghidra/Framework/Generic/src/main/java/generic/util/image/ImageUtils.java b/Ghidra/Framework/Generic/src/main/java/generic/util/image/ImageUtils.java index 5d0be478ae..d9067aa6b9 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/util/image/ImageUtils.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/image/ImageUtils.java @@ -24,6 +24,7 @@ import java.util.Objects; import javax.imageio.ImageIO; import javax.swing.*; +import generic.theme.GThemeDefaults.Colors; import ghidra.util.MathUtilities; import ghidra.util.Msg; @@ -112,7 +113,7 @@ public class ImageUtils { public static BufferedImage createEmptyImage(int width, int height) { BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics g = newImage.getGraphics(); - g.setColor(Color.WHITE); + g.setColor(Colors.BACKGROUND); g.fillRect(0, 0, width, height); return newImage; } @@ -242,7 +243,7 @@ public class ImageUtils { * Write the specified image to file in PNG format * @param i the image to save * @param imageFile the file to save the image to - * @throws IOException + * @throws IOException if there is an exception */ public static void writeFile(Image i, File imageFile) throws IOException { ImageIO.write(toRenderedImage(i), "png", imageFile); @@ -252,7 +253,7 @@ public class ImageUtils { * Write the specified image to file in PNG format * @param i the image to save * @param imageFile the file to save the image to - * @throws IOException + * @throws IOException if there is an exception */ public static void writeFile(RenderedImage i, File imageFile) throws IOException { ImageIO.write(i, "png", imageFile); @@ -262,7 +263,7 @@ public class ImageUtils { * Load an image from a file * @param imageFile image source-data file * @return the image, decoded from bytes in specified file - * @throws IOException + * @throws IOException if there is an exception */ public static BufferedImage readFile(File imageFile) throws IOException { return ImageIO.read(imageFile); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java index 45d9ef8d7e..ac9e9e523e 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java @@ -25,6 +25,7 @@ import java.util.*; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; +import generic.theme.*; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.datastruct.WeakDataStructureFactory; @@ -59,6 +60,8 @@ public abstract class AbstractOptions implements Options { protected Map optionsEditorMap; protected Map categoryHelpMap; protected Map aliasMap; + protected ThemeListener themeListener; + protected Map themeToOptionMap = new HashMap<>(); protected AbstractOptions(String name) { this.name = name; @@ -67,7 +70,8 @@ public abstract class AbstractOptions implements Options { optionsEditorMap = new HashMap<>(); categoryHelpMap = new HashMap<>(); aliasMap = new HashMap<>(); - + themeListener = this::themeChanged; + Gui.addThemeListener(themeListener); } protected abstract Option createRegisteredOption(String optionName, OptionType type, @@ -135,6 +139,20 @@ public abstract class AbstractOptions implements Options { throw new IllegalArgumentException( "Can't register an option of type: " + OptionType.NO_TYPE); } + + if (type == OptionType.COLOR_TYPE) { + warnShouldUseTheme("Color"); + } + if (type == OptionType.FONT_TYPE) { + warnShouldUseTheme("font"); + } + + if (!type.isCompatible(defaultValue)) { + throw new IllegalStateException( + "Given default value does not match the given OptionType! OptionType = " + type + + ", defaultValue = " + defaultValue); + } + if (type == OptionType.CUSTOM_TYPE && editor == null) { throw new IllegalStateException( "Can't register a custom option without a property editor"); @@ -144,7 +162,7 @@ public abstract class AbstractOptions implements Options { ReflectionUtilities.createJavaFilteredThrowable()); } - Option currentOption = getExistingComptibleOption(optionName, type, defaultValue); + Option currentOption = getExistingComptibleOption(optionName, type); if (currentOption != null) { currentOption.updateRegistration(description, help, defaultValue, editor); return; @@ -156,8 +174,46 @@ public abstract class AbstractOptions implements Options { valueMap.put(optionName, option); } - private Option getExistingComptibleOption(String optionName, OptionType type, - Object defaultValue) { + private void warnShouldUseTheme(String optionType) { + Throwable throwable = + ReflectionUtilities.createThrowableWithStackOlderThan(AbstractOptions.class, + SubOptions.class); + String call = throwable.getStackTrace()[0].toString(); + Msg.warn(this, "Registering a direct " + optionType + " in the options is deprecated." + + " Use registerTheme" + optionType + "Binding() instead!\n Called from " + call + "\n"); + } + + @Override + public void registerThemeColorBinding(String optionName, String colorId, HelpLocation help, + String description) { + Option currentOption = getExistingComptibleOption(optionName, OptionType.COLOR_TYPE); + if (currentOption != null && currentOption instanceof ThemeColorOption) { + currentOption.updateRegistration(description, help, null, null); + return; + } + description += " (Theme Color: " + colorId + ")"; + Option option = new ThemeColorOption(optionName, colorId, description, help); + valueMap.put(optionName, option); + } + + @Override + public void registerThemeFontBinding(String optionName, String fontId, HelpLocation help, + String description) { + if (Gui.getFont(fontId) == null) { + throw new IllegalArgumentException("Invalid theme font id: \"" + fontId + "\""); + } + Option currentOption = getExistingComptibleOption(optionName, OptionType.FONT_TYPE); + if (currentOption != null && currentOption instanceof ThemeFontOption) { + currentOption.updateRegistration(description, help, null, null); + return; + } + description += " (Theme Font: " + fontId + ")"; + Option option = new ThemeFontOption(optionName, fontId, description, help); + themeToOptionMap.put(fontId, optionName); + valueMap.put(optionName, option); + } + + private Option getExistingComptibleOption(String optionName, OptionType type) { // There are several cases where an existing option may exist when registering an option // 1) the option was accessed before it was registered @@ -173,8 +229,7 @@ public abstract class AbstractOptions implements Options { if (option == null) { return null; } - - if (!isCompatibleOption(option, type, defaultValue)) { + if (option.getOptionType() != type) { Msg.error(this, "Registered option incompatible with existing option: " + optionName, new AssertException()); return null; @@ -182,15 +237,6 @@ public abstract class AbstractOptions implements Options { return option; } - private boolean isCompatibleOption(Option option, OptionType type, Object defaultValue) { - if (option.getOptionType() != type) { - return false; - } - Object optionValue = option.getValue(null); - return optionValue == null || defaultValue == null || - optionValue.getClass().equals(defaultValue.getClass()); - } - @Override public synchronized void removeOption(String optionName) { aliasMap.remove(optionName); @@ -700,7 +746,16 @@ public abstract class AbstractOptions implements Options { return true; } - return SUPPORTED_CLASSES.contains(obj.getClass()); + if (SUPPORTED_CLASSES.contains(obj.getClass())) { + return true; + } + // check for extended classes + for (Class class1 : SUPPORTED_CLASSES) { + if (class1.isAssignableFrom(obj.getClass())) { + return true; + } + } + return false; } /** @@ -798,6 +853,22 @@ public abstract class AbstractOptions implements Options { return new ArrayList<>(leafNames); } + private void themeChanged(ThemeEvent e) { + // We are only sending out OptionsChangedEvents in response to Font theme changes. We + // don't notify options changed for colors because we expect clients are using GColor + // which updates automatically, so should need to be notified via options. + + if (!e.hasAnyFontChanged()) { + return; + } + for (String fontId : themeToOptionMap.keySet()) { + if (e.isFontChanged(fontId)) { + String optionName = themeToOptionMap.get(fontId); + notifyOptionChanged(optionName, null, Gui.getFont(fontId)); + } + } + } + //================================================================================================== // Inner Classes //================================================================================================== diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/EditorState.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/EditorState.java index 644da95148..1c79064c95 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/EditorState.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/EditorState.java @@ -186,4 +186,9 @@ public class EditorState implements PropertyChangeListener { return options.getDescription(name); } + @Override + public String toString() { + return "EditorState: " + name + "= " + currentValue; + } + } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ErrorPropertyEditor.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ErrorPropertyEditor.java index 867c922dd3..00d72272a5 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ErrorPropertyEditor.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ErrorPropertyEditor.java @@ -15,12 +15,13 @@ */ package ghidra.framework.options; -import java.awt.Color; import java.beans.PropertyEditorSupport; import javax.swing.JComponent; import javax.swing.JLabel; +import generic.theme.GThemeDefaults.Colors.Messages; + public class ErrorPropertyEditor extends PropertyEditorSupport { private JLabel errorLabel; private Object editorValue; @@ -34,7 +35,7 @@ public class ErrorPropertyEditor extends PropertyEditorSupport { // Use native java JLabel because we can't use docking widgets here errorLabel = new JLabel(message); - errorLabel.setForeground(Color.RED); + errorLabel.setForeground(Messages.ERROR); errorLabel.putClientProperty("html.disable", true); } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/OptionType.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/OptionType.java index 060c11f852..b7da0fddd9 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/OptionType.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/OptionType.java @@ -64,6 +64,17 @@ public enum OptionType { return stringAdapter.objectToString(object); } + /** + * Return true if the give value is of the correct type for this option type. Note that a + * value of null is compatible with any class type + * since it is an acceptable value for any class type. + * @param object the object to see if it is compatible with this option type + * @return true if the give value is of the correct type for this option type. + */ + public boolean isCompatible(Object object) { + return object == null || clazz.isAssignableFrom(object.getClass()); + } + public Class getValueClass() { return clazz; } @@ -230,8 +241,8 @@ public enum OptionType { } catch (Exception e) { Msg.error(this, - "Can't create customOption instance for: " + customOptionClassName + - e); + "Can't create customOption instance for: " + customOptionClassName + + e); } return null; } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Options.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Options.java index 256d38df63..821431476d 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Options.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Options.java @@ -108,7 +108,14 @@ public interface Options { /** * Registers an option with a description, help location, and a default value without specifying * the option type. This form requires that the default value not be null so that the option - * type can be inferred from the default value. + * type can be inferred from the default value. + *

+ * Note, this method should not be used for + * colors and font as doing so will result in those colors and fonts becoming disconnected + * to the current theme. Instead use + * + * {@link #registerThemeColorBinding(String, String, HelpLocation, String)} or + * {@link #registerThemeFontBinding(String, String, HelpLocation, String)}. * @param optionName the name of the option being registered. * @param defaultValue the defaultValue for the option. The default value must not be * null so that the OptionType can be determined. If the default value should be null, use @@ -123,6 +130,13 @@ public interface Options { /** * Registers an option with a description, help location, and a optional default value. With an optional * default value, an OptionType must be passed as it is otherwise derived from the default value. + *

+ * Note, this method should not be used for + * colors and font as doing so will result in those colors and fonts becoming disconnected + * to the current theme. Instead use + * {@link #registerThemeColorBinding(String, String, HelpLocation, String)} or + * {@link #registerThemeFontBinding(String, String, HelpLocation, String)}. + * * @param optionName the name of the option being registered. * @param type the OptionType for this options. * @param defaultValue the defaultValue for the option. In this version of the method, the default @@ -136,6 +150,13 @@ public interface Options { /** * Registers an option with a description, help location, and a optional default value. With an optional * default value, an OptionType must be passed as it is otherwise derived from the default value. + *

+ * Note, this method should not be used for + * colors and font as doing so will result in those colors and fonts becoming disconnected + * to the current theme. Instead use + * {@link #registerThemeColorBinding(String, String, HelpLocation, String)} or + * {@link #registerThemeFontBinding(String, String, HelpLocation, String)}. + * * @param optionName the name of the option being registered. * @param type the OptionType for this options. * @param defaultValue the defaultValue for the option. In this version of the method, the default @@ -149,6 +170,29 @@ public interface Options { public void registerOption(String optionName, OptionType type, Object defaultValue, HelpLocation help, String description, PropertyEditor editor); + /** + * Register/binds the option to a theme color id. Changing the option's color via the options + * Gui will result in directly changing the theme color of the given color id. + * @param optionName the name of the color option + * @param colorId the theme color id whose color value is changed when the option's color is changed + * @param help the HelpLocation for this option + * @param description a description of the option + */ + public void registerThemeColorBinding(String optionName, String colorId, HelpLocation help, + String description); + + /** + * Register/binds the option to a theme font id. Changing the option's font via the options + * Gui will result in directly changing the theme color of the given font id. + * @param optionName the name of the font option + * @param fontId the theme color id whose color value is changed when the option's color + * is changed + * @param help the HelpLocation for this option + * @param description a description of the option + */ + public void registerThemeFontBinding(String optionName, String fontId, HelpLocation help, + String description); + /** * Register the options editor that will handle the editing for all the options or a sub group of options. * @param editor the custom editor panel to be used to edit the options or sub group of options. diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SubOptions.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SubOptions.java index 734bbccf2f..53b72c9fdb 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SubOptions.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SubOptions.java @@ -92,6 +92,18 @@ public class SubOptions implements Options { options.registerOption(prefix + optionName, type, defaultValue, help, description, editor); } + @Override + public void registerThemeColorBinding(String optionName, String colorId, HelpLocation help, + String description) { + options.registerThemeColorBinding(prefix + optionName, colorId, help, description); + } + + @Override + public void registerThemeFontBinding(String optionName, String fontId, HelpLocation help, + String description) { + options.registerThemeFontBinding(prefix + optionName, fontId, help, description); + } + @Override public void putObject(String optionName, Object obj) { options.putObject(prefix + optionName, obj); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ThemeColorOption.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ThemeColorOption.java new file mode 100644 index 0000000000..91fec39a35 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ThemeColorOption.java @@ -0,0 +1,70 @@ +/* ### + * 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 ghidra.framework.options; + +import java.awt.Color; + +import generic.theme.*; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; + +/** + * Options implementation for theme color options. A ThemeColorOption is an option that, when + * changed, affects the current theme and is saved in the theme, instead of being saved with + * normal non-theme related options. + */ +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); + this.colorId = colorId; + if (!Gui.hasColor(colorId)) { + Msg.warn(this, + "Registered a theme color option with a non-defined theme color id of \"" + + colorId + "\""); + } + + } + + @Override + public Color getCurrentValue() { + return new GColor(colorId); + } + + @Override + public Object getDefaultValue() { + return getCurrentValue(); + } + + @Override + public void doSetCurrentValue(Object value) { + ThemeManager.getInstance().setColor(colorId, (Color) value); + } + + @Override + public boolean isDefault() { + return !ThemeManager.getInstance().isChangedColor(colorId); + } + + @Override + public void restoreDefault() { + ThemeManager.getInstance().restoreColor(colorId); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ThemeFontOption.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ThemeFontOption.java new file mode 100644 index 0000000000..f073273478 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ThemeFontOption.java @@ -0,0 +1,71 @@ +/* ### + * 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 ghidra.framework.options; + +import java.awt.Font; + +import generic.theme.Gui; +import generic.theme.ThemeManager; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; + +/** + * Options implementation for theme font options. A ThemeFontOption is an option that, when + * changed, affects the current theme and is saved in the theme, instead of being saved with + * normal non-theme related options. + */ +public class ThemeFontOption extends Option { + + private String fontId; + + public ThemeFontOption(String optionName, String fontId, String description, + HelpLocation help) { + super(optionName, OptionType.FONT_TYPE, description, help, null, true, null); + this.fontId = fontId; + if (!Gui.hasFont(fontId)) { + Msg.warn(this, + "Registered a theme font option with a non-defined theme font id of \"" + + fontId + "\""); + } + + } + + @Override + public Font getCurrentValue() { + return Gui.getFont(fontId); + } + + @Override + public Object getDefaultValue() { + return getCurrentValue(); + } + + @Override + public void doSetCurrentValue(Object value) { + ThemeManager.getInstance().setFont(fontId, (Font) value); + } + + @Override + public boolean isDefault() { + return !ThemeManager.getInstance().isChangedFont(fontId); + } + + @Override + public void restoreDefault() { + ThemeManager.getInstance().restoreFont(fontId); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/ColorUtils.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/ColorUtils.java index 3e5dc984ab..79d4f26d90 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/ColorUtils.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/ColorUtils.java @@ -16,6 +16,7 @@ package ghidra.util; import java.awt.Color; +import java.util.Comparator; public class ColorUtils { @@ -167,28 +168,122 @@ public class ColorUtils { * @param ratio the amount of the first color to include in the final output * @return the new color */ - public static Color blend(Color c1, Color c2, float ratio) { + public static Color blend(Color c1, Color c2, double ratio) { if (c1 == null) { return c2; } if (c2 == null) { return c1; } - float rgb1[] = new float[3]; - float rgb2[] = new float[3]; - c1.getColorComponents(rgb1); - c2.getColorComponents(rgb2); + int red = blend(c1.getRed(), c2.getRed(), ratio); + int green = blend(c1.getGreen(), c2.getRed(), ratio); + int blue = blend(c1.getBlue(), c2.getBlue(), ratio); + int alpha = blend(c1.getAlpha(), c2.getAlpha(), ratio); + return new Color(red, green, blue, alpha); + } - float inverse = (float) 1.0 - ratio; + private static int blend(int colorValue1, int colorValue2, double ratio) { + double value = colorValue1 * ratio + colorValue2 * (1.0 - ratio); + int result = (int) (value + 0.5); + return Math.min(result, 255); + } - //@formatter:off - Color color = new Color( - rgb1[0] * ratio + rgb2[0] * inverse, - rgb1[1] * ratio + rgb2[1] * inverse, - rgb1[2] * ratio + rgb2[2] * inverse); - //@formatter:on + /** + * Returns a new color that is comprised of the given color's rgb value and the given alpha + * value. + * @param c the color + * @param alpha the alpha + * @return the new color + */ + public static Color withAlpha(Color c, int alpha) { + return new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha); + } - return color; + /** + * A color {@link Comparator} for ordering colors. + */ + public static Comparator COMPARATOR = new Comparator() { + + @Override + public int compare(Color c1, Color c2) { + int alpha1 = c1.getAlpha(); + int alpha2 = c2.getAlpha(); + + if (alpha1 == alpha2) { + return getHsbCompareValue(c1) - getHsbCompareValue(c2); + } + return alpha1 - alpha2; + } + + private int getHsbCompareValue(Color v) { + // compute a value the compares colors first by hue, then saturation, then brightness + // reduce noise by converting float values from 0-1 to integers 0 - 7 + float[] hsb = Color.RGBtoHSB(v.getRed(), v.getGreen(), v.getBlue(), null); + return 100 * (int) (10 * hsb[0]) + 10 * (int) (10 * hsb[1]) + (int) (10 * hsb[2]); + } + + }; + + /** + * Return the color object given a rgba value that includes the desired alpha value. + * @param rgba value where bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are + * blue + * @return the color object given a rgba value that includes the desired alpha value + */ + public static Color getColor(int rgba) { + return new Color(rgba, true); + } + + /** + * Return an opaque color object given for the given red, green, and blue values. + * @param red the red value (0 - 255) + * @param green the green value (0 - 255) + * @param blue the blue value (0 - 255) + * @return the color object for the given values + */ + public static Color getColor(int red, int green, int blue) { + return new Color(red, green, blue); + } + + /** + * Return the color object given for the given red, green, blue, and alpha values. + * @param red the red value (0 - 255) + * @param green the green value (0 - 255) + * @param blue the blue value (0 - 255) + * @param alpha the alpha (transparency) value (0 - 255) with 0 being fully transparent and 255 + * being fully opaque opaque + * @return the color object for the given values + */ + public static Color getColor(int red, int green, int blue, int alpha) { + return new Color(red, green, blue, alpha); + } + + /** + * Returns an opaque color with the given rgb value. The resulting color will have an alpha + * value of 0xff. + * + * @param rgb the value where bits 16-23 are red, 8-15 are green, 0-7 are blue. Bits 24-31 will + * be set to 0xff. + * @return an opaque color with the given rgb value + + */ + public static Color getOpaqueColor(int rgb) { + return new Color(rgb); + } + + /** + * Creates a new color by averaging the red, green, blue, and alpha values from the given + * colors. + * @param color1 the first color to average + * @param color2 the second color to average + * @return a new color that is the average of the two given colors + */ + public static Color average(Color color1, Color color2) { + int red = (color1.getRed() + color2.getRed()) / 2; + int green = (color1.getGreen() + color2.getGreen()) / 2; + int blue = (color1.getBlue() + color2.getBlue()) / 2; + int alpha = (color1.getAlpha() + color2.getAlpha()) / 2; + return new Color(red, green, blue, alpha); } /** diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/HTMLUtilities.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/HTMLUtilities.java index 182c781a44..90d8e28852 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/HTMLUtilities.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/HTMLUtilities.java @@ -141,17 +141,6 @@ public class HTMLUtilities { public static String HTML_SPACE = " "; public static String HTML_NEW_LINE = BR; - public static final String MAROON = "#990000"; - public static final String GREEN = "#009900"; - public static final String BLUE = "#000099"; - public static final String PURPLE = "#990099"; - public static final String DARK_CYAN = "#009999"; - public static final String OLIVE = "#999900"; - public static final String ORANGE = "#FF9900"; - public static final String PINK = "#FF9999"; - public static final String YELLOW = "#FFFF00"; - public static final String GRAY = "#888888"; - /** * Marks the given text as HTML in order to be rendered thusly by Java widgets. * diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/SaveableColor.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/SaveableColor.java index 540bc9a5a5..6a2f4f62c4 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/SaveableColor.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/SaveableColor.java @@ -17,97 +17,77 @@ package ghidra.util; import java.awt.Color; -public class SaveableColor extends PrivateSaveable -{ +public class SaveableColor extends PrivateSaveable { private Color color; private Class[] fields = new Class[] { - Integer.class, Integer.class, Integer.class + Integer.class, Integer.class, Integer.class }; - + public SaveableColor(Color color) { this.color = color; } + public SaveableColor() { } - /** - * @see Saveable#restore(ObjectStorage) - */ + @Override public void save(ObjectStorage objStorage) { objStorage.putInt(color.getRed()); objStorage.putInt(color.getBlue()); objStorage.putInt(color.getGreen()); } - + @Override public Class[] getObjectStorageFields() { - return fields; + return fields; } - - /** - * @see Saveable#save(ObjectStorage) - */ + @Override public void restore(ObjectStorage objStorage) { int red = objStorage.getInt(); int blue = objStorage.getInt(); int green = objStorage.getInt(); - color = new Color(red,green,blue); + color = new Color(red, green, blue); } public Color getColor() { return color; } - - /** - * @see ghidra.util.Saveable#getSchemaVersion() - */ + @Override public int getSchemaVersion() { return 0; } - /** - * @see ghidra.util.Saveable#isUpgradeable(int) - */ @Override public boolean isUpgradeable(int oldSchemaVersion) { return false; } - /** - * @see ghidra.util.Saveable#upgrade(ghidra.util.ObjectStorage, int, ghidra.util.ObjectStorage) - */ @Override - public boolean upgrade(ObjectStorage oldObjStorage, int oldSchemaVersion, ObjectStorage currentObjStorage) { + public boolean upgrade(ObjectStorage oldObjStorage, int oldSchemaVersion, + ObjectStorage currentObjStorage) { return false; } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ + @Override - public boolean equals(Object obj) { + public boolean equals(Object obj) { if (obj == this) { return true; } - if (obj == null || getClass() != obj.getClass() ) { + if (obj == null || getClass() != obj.getClass()) { return false; } - return color.equals(((SaveableColor)obj).color); + return color.getRGB() == ((SaveableColor) obj).color.getRGB(); } - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ + @Override - public int hashCode() { + public int hashCode() { return color.hashCode(); } - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ + @Override - public String toString() { + public String toString() { return color.toString(); } } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/WebColors.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/WebColors.java index e28748e217..e8ba4ef344 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/WebColors.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/WebColors.java @@ -18,8 +18,6 @@ package ghidra.util; import java.awt.Color; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Class for web color support. This class defines many of the colors used by html. This class @@ -27,7 +25,6 @@ import java.util.regex.Pattern; * those strings back to a color. */ public abstract class WebColors { - private static final Pattern HEX_PATTERN = Pattern.compile("(0x|#)[0-9A-Fa-f]{6}"); private static final Map nameToColorMap = new HashMap<>(); private static final Map colorToNameMap = new HashMap<>(); @@ -152,7 +149,7 @@ public abstract class WebColors { public static final Color MISTY_ROSE = registerColor("MistyRose", Color.decode("0xFFE4E1")); public static final Color BLANCHED_ALMOND = registerColor("BlanchedAlmond", Color.decode("0xFFEBCD")); public static final Color PAPAYA_WHIP = registerColor("PapayaWhip", Color.decode("0xFFEFD5")); - public static final Color LAVENDAR_BLUSH = registerColor("LavenderBlush", Color.decode("0xFFF0F5")); + public static final Color LAVENDER_BLUSH = registerColor("LavenderBlush", Color.decode("0xFFF0F5")); public static final Color SEASHELL = registerColor("SeaShell", Color.decode("0xFFF5EE")); public static final Color CORNSILK = registerColor("Cornsilk", Color.decode("0xFFF8DC")); public static final Color LEMON_CHIFFON = registerColor("LemonChiffon", Color.decode("0xFFFACD")); @@ -172,12 +169,12 @@ public abstract class WebColors { public static final Color MEDUM_AQUA_MARINE = registerColor("MediumAquaMarine", Color.decode("0x66CDAA")); public static final Color MEDIUM_TURQOISE = registerColor("MediumTurquoise", Color.decode("0x48D1CC")); public static final Color DARK_OLIVE_GREEN = registerColor("DarkOliveGreen", Color.decode("0x556B2F")); - public static final Color CORN_FLOWER_BLUE = registerColor("CornflowerBlue", Color.decode("0x6495ED")); + public static final Color CORNFLOWER_BLUE = registerColor("CornflowerBlue", Color.decode("0x6495ED")); //@formatter:on // cannot instantiate nor extend - private WebColors() { - } + private WebColors() { + } /** * Tries to find a color for the given String value. The String value can either be @@ -193,57 +190,213 @@ public abstract class WebColors { return color != null ? color : defaultColor; } - /** - * Tries to find a color for the given String value. The String value can either be - * a hex string (see {@link Color#decode(String)}) or a web color name as defined - * in {@link WebColors} - * - * @param value the string value to interpret as a color - * @return a color for the given string value or null if the string can't be translated - */ - public static Color getColor(String value) { - Color color = nameToColorMap.get(value); - if (color != null) { - return color; - } - // if the value matches an RGB hex string, turn that into a color - color = getHexColor(value); - if (color != null) { - return color; - } - return null; - } - /** * Converts a color to a string value. If there is a defined color for the given color value, * the color name will be returned. Otherwise, it will return a hex string for the color as - * defined by {@link Color#toString()}. The result of this call can be passed to - * {@link #getColor(String)} and be guaranteed that a color will be returned + * follows. If the color has an non-opaque alpha value, it will be of the form #rrggbb. If + * it has an alpha value,then the format will be #rrggbbaa. * * @param color the color to convert to a string. * @return the string representation for the given color. */ public static String toString(Color color) { - String name = colorToNameMap.get(color); - if (name != null) { - return name; - } - // this will format a color value as a 6 digit hex (e.g. #rrggbb) - return String.format("#%06X", color.getRGB() & 0xffffff); + return toString(color, true); } - private static Color getHexColor(String hexString) { - Matcher matcher = HEX_PATTERN.matcher(hexString); - if (matcher.matches()) { - return Color.decode(hexString); + /** + * Converts a color to a string value. If the color is a WebColor and the useNameIfPossible + * is true, the name of the color will be returned. OOtherwise, it will return a hex string for the color as + * follows. If the color has an non-opaque alpha value, it will be of the form #rrggbb. If + * it has an alpha value ,then the format will be #rrggbbaa. + * + * @param color the color to convert to a string. + * @param useNameIfPossible if true, the name of the color will be returned if the color is + * a WebColor + * @return the string representation for the given color. + */ + public static String toString(Color color, boolean useNameIfPossible) { + if (useNameIfPossible) { + String name = colorToNameMap.get(color); + if (name != null) { + return name; + } } - return null; + int rgb = color.getRGB() & 0xffffff; //mask off any alpha value + int alpha = color.getAlpha(); + if (alpha != 0xff) { + return String.format("#%06x%02x", rgb, alpha); + } + return String.format("#%06x", rgb); + } + + /** + * Returns the WebColor name for the given color. Returns null if the color is not a WebColor + * @param color the color to lookup a WebColor name. + * @return the WebColor name for the given color. Returns null if the color is not a WebColor + */ + public static String toWebColorName(Color color) { + return colorToNameMap.get(color); } private static Color registerColor(String name, Color color) { - nameToColorMap.put(name, color); + nameToColorMap.put(name.toLowerCase(), color); colorToNameMap.put(color, name); return color; } + /** + * Attempts to convert the given string into a color in a most flexible manner. It first checks + * if the given string matches the name of a known web color as defined above. If so it + * returns that color. Otherwise it tries to parse the string in any one of the following + * formats: + *

+	 * #rrggbb
+	 * #rrggbbaa
+	 * 0xrrggbb
+	 * 0xrrggbbaa
+	 * rgb(red, green, blue)
+	 * rgba(red, green, alpha)
+	 * 
+ * In the hex digit formats, the hex digits "rr", "gg", "bb", "aa" represent the values for red, + * green, blue, and alpha, respectively. In the "rgb" and "rgba" formats the red, green, and + * blue values are all integers between 0-255, while the alpha value is a float value from 0.0 to + * 1.0. + *

+ * @param colorString the color name + * @return a color for the given string or null + */ + public static Color getColor(String colorString) { + String value = colorString.trim().toLowerCase(); + Color color = nameToColorMap.get(value.toLowerCase()); + if (color != null) { + return color; + } + + return parseColor(value); + } + + private static Color parseColor(String colorString) { + if (colorString.startsWith("#") || colorString.startsWith("0x")) { + return parseHexColor(colorString); + } + if (colorString.startsWith("rgb(")) { + return parseRGBColor(colorString); + } + return parseRGBAColor(colorString); + } + + /** + * Parses the given string into a color. The string must be in one of the following formats: + *
+	 * #rrggbb
+	 * #rrggbbaa
+	 * 0xrrggbb 
+	 * 0xrrggbbaa
+	 * 
+ * + * Each of the hex digits "rr", "gg", "bb", and "aa" specify the red, green, blue, and alpha + * values respectively. + *

+ * + * @param hexString the string to parse into a color. + * @return the parsed Color or null if the input string was invalid. + */ + private static Color parseHexColor(String hexString) { + String value = hexString.trim(); + if (value.startsWith("#")) { + value = value.substring(1); + } + else if (value.startsWith("0x")) { + value = value.substring(2); + } + else { + return null; + } + + if (value.length() != 8 && value.length() != 6) { + return null; + } + + boolean hasAlpha = value.length() == 8; + if (hasAlpha) { + // alpha value is the last 2 digits, Color wants alpha to be in upper bits so re-arrange + value = value.substring(6) + value.substring(0, 6); + } + + try { + long colorValue = Long.parseLong(value, 16); + return new Color((int) colorValue, hasAlpha); + } + catch (NumberFormatException e) { + return null; + } + } + + /** + * Parses the given string into a color. The string must be in one of the following formats: + *
+	 * rgb(red, green, blue)
+	 * rgb(red, green, blue, alpha)
+	 * 
+ * Each of the values "red", "green", "blue", and "alpha" must be integer values between 0-255 + *

+ * @param rgbString the string to parse into a color. + * @return the parsed Color or null if the input string was invalid. + */ + private static Color parseRGBColor(String rgbString) { + String value = rgbString.trim().replaceAll(" ", ""); + if (!(value.startsWith("rgb(") && value.endsWith(")"))) { + return null; + } + // strip off to comma separated values + value = value.substring(4, value.length() - 1); + String[] split = value.split(","); + if (split.length != 3) { + return null; + } + try { + int red = Integer.parseInt(split[0]); + int green = Integer.parseInt(split[1]); + int blue = Integer.parseInt(split[2]); + return new Color(red, green, blue); + } + catch (IllegalArgumentException e) { + return null; + } + } + + private static Color parseRGBAColor(String rgbaString) { + String value = rgbaString.replaceAll(" ", ""); + if (!(value.startsWith("rgba(") && value.endsWith(")"))) { + return null; + } + // strip off to comma separated values + value = value.substring(5, value.length() - 1); + value = value.replaceAll(" ", ""); + String[] split = value.split(","); + if (split.length != 4) { + return null; + } + try { + int red = Integer.parseInt(split[0]); + int green = Integer.parseInt(split[1]); + int blue = Integer.parseInt(split[2]); + int alpha = parseAlpha(split[3]); + return new Color(red, green, blue, alpha); + } + catch (IllegalArgumentException e) { + return null; + } + } + + private static int parseAlpha(String string) { + // alpha strings can either be a float between 0.0 and 1.0 or an integer from 0 to 255. + // if it is a float, treat that value as a percentage of the 255 max value + // if it is an int, don't allow the value to be bigger than 255. + if (string.contains(".")) { + float value = Float.parseFloat(string); + return (int) (value * 0xff + 0.5) & 0xff; // convert to value in range (0-255) + } + return Integer.parseInt(string) & 0xff; // truncate any bits that would make it bigger than 255 + } } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/bean/GGlassPane.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/bean/GGlassPane.java index 6c601b5b08..8b67bf48c1 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/bean/GGlassPane.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/bean/GGlassPane.java @@ -144,7 +144,7 @@ public class GGlassPane extends JComponent { // Rectangle bounds = getBounds(); // Graphics2D g2 = (Graphics2D) g; // g2.setComposite( AlphaComposite.getInstance( AlphaComposite.SrcOver.getRule(), 0.5f ) ); -// g2.setColor( Color.BLUE ); +// g2.setColor( Palette.BLUE ); // g2.fill( bounds ); } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/WeakStore.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/WeakStore.java new file mode 100644 index 0000000000..32e579eed0 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/WeakStore.java @@ -0,0 +1,122 @@ +/* ### + * 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 ghidra.util.datastruct; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.*; + +/** + * Class for storing a weak reference to object instances. Objects of type T can be placed in this + * store and they will remain there until there are no references to that object. Note + * that this is not a Set and you can have multiple instances that are "equal" in this store.The + * main purpose of this store is to be able to get all objects in the store that are still + * referenced. This is useful when you need to visit all in use items. + *

+ * This class is thread safe. + * + * @param The type of objects stored in this WeakStore + */ +public class WeakStore { + protected ReferenceQueue refQueue; + private Link first; + private Link last; + private int size = 0; + + public WeakStore() { + refQueue = new ReferenceQueue<>(); + } + + /** + * Returns the number of objects of type T remaining in the store. Those that are remaining + * are either still referenced + * @return the number of objects still in the store that haven't yet been garbage collected + */ + public synchronized int size() { + processQueue(); + return size; + } + + /** + * returns a list of all the objects in this store + * @return a list of all the objects in this store + */ + public synchronized List getValues() { + processQueue(); + List values = new ArrayList<>(); + for (Link l = first; l != null; l = l.nextLink) { + T value = l.get(); + if (value != null) { + values.add(value); + } + } + return values; + } + + /** + * Adds the given value to the store + * @param value the instance being added to the store + */ + public synchronized void add(T value) { + Objects.requireNonNull(value); + + processQueue(); + Link newLink = new Link<>(last, value, null, refQueue); + if (last == null) { + first = newLink; + } + else { + last.nextLink = newLink; + } + last = newLink; + size++; + } + + @SuppressWarnings("unchecked") + private void processQueue() { + Link ref; + while ((ref = (Link) refQueue.poll()) != null) { + remove(ref); + } + } + + private void remove(Link link) { + if (link.previousLink == null) { + first = link.nextLink; + } + else { + link.previousLink.nextLink = link.nextLink; + } + if (link.nextLink == null) { + last = link.previousLink; + } + else { + link.nextLink.previousLink = link.previousLink; + } + size--; + } + + private static class Link extends WeakReference { + private Link nextLink; + private Link previousLink; + + public Link(Link previous, T value, Link next, ReferenceQueue refQueue) { + super(value, refQueue); + this.nextLink = next; + this.previousLink = previous; + } + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java b/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java index 8198341755..823271da59 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/IconProvider.java @@ -15,14 +15,15 @@ */ package resources; +import java.awt.Image; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import javax.swing.Icon; import javax.swing.ImageIcon; -import generic.Images; import generic.util.image.ImageUtils; import ghidra.util.Msg; @@ -35,18 +36,19 @@ import ghidra.util.Msg; */ public class IconProvider { - private ImageIcon icon; + private Icon icon; private URL url; private URL tempUrl; private boolean tempFileFailed; - public IconProvider(ImageIcon icon, URL url) { + public IconProvider(Icon icon, URL url) { this.icon = icon; this.url = url; } - public ImageIcon getIcon() { - return icon; + public Image getImage() { + ImageIcon imageIcon = ResourceManager.getImageIcon(icon); + return imageIcon.getImage(); } public boolean isInvalid() { @@ -94,7 +96,8 @@ public class IconProvider { try { File imageFile = File.createTempFile("temp.help.icon", null); imageFile.deleteOnExit(); // don't let this linger - ImageUtils.writeFile(icon.getImage(), imageFile); + ImageIcon imageIcon = ResourceManager.getImageIcon(icon); + ImageUtils.writeFile(imageIcon.getImage(), imageFile); return imageFile.toURI().toURL(); } catch (IOException e) { @@ -119,6 +122,6 @@ public class IconProvider { } private URL getDefaultUrl() { - return ResourceManager.getResource(Images.BOMB); + return ResourceManager.getResource(ResourceManager.BOMB); } } diff --git a/Ghidra/Framework/Generic/src/main/java/resources/Icons.java b/Ghidra/Framework/Generic/src/main/java/resources/Icons.java index d4a1af7313..1fbb24eaa0 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/Icons.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/Icons.java @@ -15,80 +15,82 @@ */ package resources; -import java.awt.*; import java.lang.reflect.Field; -import java.net.MalformedURLException; import java.net.URL; import javax.swing.Icon; import javax.swing.ImageIcon; +import generic.theme.GIcon; import ghidra.util.Msg; -import resources.icons.*; /** - * A class to get generic icons for standard actions. All methods in this class return an + * A class to get generic icons for standard actions. All methods in this class return an * icon that is 16x16 unless the method name ends in another size.' */ public class Icons { - public static final ImageIcon EMPTY_ICON = get("images/EmptyIcon16.gif"); + public static final Icon EMPTY_ICON = new GIcon("icon.empty"); - public static final ImageIcon HELP_ICON = get("images/help-browser.png"); + public static final Icon HELP_ICON = new GIcon("icon.help"); - public static final ImageIcon ADD_ICON = get("images/Plus2.png"); + public static final Icon ADD_ICON = new GIcon("icon.add"); + public static final Icon COPY_ICON = new GIcon("icon.copy"); + public static final Icon CUT_ICON = new GIcon("icon.cut"); + public static final Icon PASTE_ICON = new GIcon("icon.paste"); - public static final ImageIcon COLLAPSE_ALL_ICON = get("images/collapse_all.png"); - public static final ImageIcon EXPAND_ALL_ICON = get("images/expand_all.png"); + public static final Icon COLLAPSE_ALL_ICON = new GIcon("icon.collapse.all"); + public static final Icon EXPAND_ALL_ICON = new GIcon("icon.expand.all"); - public static final ImageIcon CONFIGURE_FILTER_ICON = get("images/exec.png"); - public static final ImageIcon DELETE_ICON = get("images/error.png"); - public static final ImageIcon ERROR_ICON = get("images/emblem-important.png"); + public static final Icon CONFIGURE_FILTER_ICON = new GIcon("icon.configure.filter"); + public static final Icon CLEAR_ICON = new GIcon("icon.clear"); + public static final Icon DELETE_ICON = new GIcon("icon.delete"); + public static final Icon ERROR_ICON = new GIcon("icon.error"); - public static final ImageIcon NAVIGATE_ON_INCOMING_EVENT_ICON = get("images/locationIn.gif"); - public static final ImageIcon NAVIGATE_ON_OUTGOING_EVENT_ICON = get("images/locationOut.gif"); + public static final Icon HOME_ICON = new GIcon("icon.home"); + public static final Icon NAVIGATE_ON_INCOMING_EVENT_ICON = new GIcon("icon.navigate.in"); + public static final Icon NAVIGATE_ON_OUTGOING_EVENT_ICON = new GIcon("icon.navigate.out"); - public static final ImageIcon NOT_ALLOWED_ICON = get("images/no.png"); - public static final ImageIcon OPEN_FOLDER_ICON = get("images/openSmallFolder.png"); - public static final ImageIcon REFRESH_ICON = get("images/reload3.png"); + public static final Icon NOT_ALLOWED_ICON = new GIcon("icon.not.allowed"); + public static final Icon OPEN_FOLDER_ICON = new GIcon("icon.folder.open"); + public static final Icon CLOSED_FOLDER_ICON = new GIcon("icon.folder.closed"); + public static final Icon REFRESH_ICON = new GIcon("icon.refresh"); - public static final ImageIcon SORT_ASCENDING_ICON = get("images/sortascending.png"); - public static final ImageIcon SORT_DESCENDING_ICON = get("images/sortdescending.png"); + public static final Icon SORT_ASCENDING_ICON = new GIcon("icon.sort.ascending"); + public static final Icon SORT_DESCENDING_ICON = new GIcon("icon.sort.descending"); - public static final ImageIcon STOP_ICON = get("images/process-stop.png"); - public static final ImageIcon STRONG_WARNING_ICON = get("images/software-update-urgent.png"); + public static final Icon STOP_ICON = new GIcon("icon.stop"); + public static final Icon STRONG_WARNING_ICON = new GIcon("icon.warning.strong"); + public static final Icon WARNING_ICON = new GIcon("icon.warning"); + public static final Icon INFO_ICON = new GIcon("icon.information"); - public static final ImageIcon LEFT_ICON = get("images/left.png"); - public static final ImageIcon RIGHT_ICON = get("images/right.png"); + public static final Icon LEFT_ICON = new GIcon("icon.left"); + public static final Icon RIGHT_ICON = new GIcon("icon.right"); + public static final Icon UP_ICON = new GIcon("icon.up"); + public static final Icon DOWN_ICON = new GIcon("icon.down"); /** An version of the LEFT_ICON with a different color */ - public static final ImageIcon LEFT_ALTERNATE_ICON = get("images/left.alternate.png"); + public static final Icon LEFT_ALTERNATE_ICON = new GIcon("icon.left.alt"); /** An version of the RIGHT_ICON with a different color */ - public static final ImageIcon RIGHT_ALTERNATE_ICON = get("images/right.alternate.png"); + public static final Icon RIGHT_ALTERNATE_ICON = new GIcon("icon.right.alt"); - public static final ImageIcon SAVE_AS = - ResourceManager.getImageIcon(new DotDotDotIcon(get("images/Disk.png"))); + public static final Icon SAVE_ICON = new GIcon("icon.save"); + public static final Icon SAVE_AS_ICON = new GIcon("icon.save.as"); - public static final ImageIcon MAKE_SELECTION_ICON = get("images/text_align_justify.png"); + public static final Icon MAKE_SELECTION_ICON = new GIcon("icon.make.selection"); - // Not necessarily re-usable, but this is needed for the help system; these should + // Not necessarily re-usable, but this is needed for the help system; these should // probably be moved to the client that uses them, while updating the // help system to use them there. - public static final ImageIcon ARROW_DOWN_RIGHT_ICON = - ResourceManager.getImageIcon(new RotateIcon(get("images/viewmagfit.png"), 90)); - public static final ImageIcon ARROW_UP_LEFT_ICON = - ResourceManager.getImageIcon(new RotateIcon(get("images/viewmagfit.png"), 275)); - public static final ImageIcon FILTER_NOT_ACCEPTED_ICON = - ResourceManager.getImageIcon(new MultiIcon(get("images/flag.png"), new TranslateIcon( - ResourceManager.loadImage("images/dialog-cancel.png", 10, 10), 6, 6))); - public static final ImageIcon APPLY_BLOCKED_MATCH_ICON = - ResourceManager.getImageIcon(new MultiIcon(get("images/kgpg.png"), new TranslateIcon( - ResourceManager.loadImage("images/checkmark_green.gif", 12, 12), 4, 0))); + public static final Icon ARROW_DOWN_RIGHT_ICON = new GIcon("icon.arrow.down.right"); + public static final Icon ARROW_UP_LEFT_ICON = new GIcon("icon.arrow.up.left"); + public static final Icon FILTER_NOT_ACCEPTED_ICON = new GIcon("icon.filter.not.accepted"); + public static final Icon APPLY_BLOCKED_MATCH_ICON = new GIcon("icon.blocked.match"); /** * Returns true if the given string is a Java code snippet that references this class - * + * * @param snippet the string to check * @return true if the given string is a Java code snippet that references this class */ @@ -97,9 +99,9 @@ public class Icons { } /** - * Returns an {@link IconProvider} for the given string value, which is usually the 'src' - * attribute of an IMG tag - * + * Returns an {@link IconProvider} for the given string value, which is usually the 'src' + * attribute of an IMG tag + * * @param snippet the snippet * @return the icon provider */ @@ -110,7 +112,7 @@ public class Icons { return null; } - ImageIcon icon = getIconByFieldName(fieldName); + Icon icon = getIconByFieldName(fieldName); if (icon == null) { return null; } @@ -123,30 +125,30 @@ public class Icons { * Gets the icon for the given icon path. The given path should be relative to the classpath. * If an icon by that name can't be found, the default "bomb" icon is returned instead. *

- * For example, an icon named foo.png would typically be stored in the module at + * For example, an icon named foo.png would typically be stored in the module at * "{modulePath}/src/main/resources/image/foo.png". To reference that icon, use the path * "images/foo.png", since "{modulePath}/src/main/resources" is in the classpath. - * + * * @param iconPath the icon path (relative to the classpath) - * @return The icon referenced by that path. + * @return The icon referenced by that path. */ public static ImageIcon get(String iconPath) { return ResourceManager.loadImage(iconPath); } /** - * Gets the icon for the given icon path and scale it to the specifed width and height. + * Gets the icon for the given icon path and scale it to the specified width and height. * The given path should be relative to the classpath. * If an icon by that name can't be found, the default "bomb" icon is returned instead. *

- * For example, an icon named foo.png would typically be stored in the module at + * For example, an icon named foo.png would typically be stored in the module at * "{modulePath}/src/main/resources/image/foo.png". To reference that icon, use the path * "images/foo.png", since "{modulePath}/src/main/resources" is in the classpath. - * + * * @param iconPath the icon path (relative to the classpath) * @param width the desired width after scaling * @param height the desired height after scaling - * @return The icon referenced by that path. + * @return The icon referenced by that path. */ public static ImageIcon get(String iconPath, int width, int height) { return ResourceManager.loadImage(iconPath, width, height); @@ -162,11 +164,12 @@ public class Icons { return fieldName; } - private static ImageIcon getIconByFieldName(String fieldName) { + private static Icon getIconByFieldName(String fieldName) { try { Field field = Icons.class.getField(fieldName); - ImageIcon icon = (ImageIcon) field.get(Icons.class); + Object object = field.get(Icons.class); + Icon icon = (Icon) object; return icon; } catch (Exception e) { @@ -176,61 +179,15 @@ public class Icons { } } - private static URL getUrlFromIcon(ImageIcon icon) { - if (icon == null) { - return null; + private static URL getUrlFromIcon(Icon icon) { + if (icon instanceof GIcon gIcon) { + URL url = gIcon.getUrl(); + if (url != null) { + return url; + } + Msg.debug(Icons.class, "Unable to get URL for icon"); } - - if (icon instanceof UrlImageIcon) { - return ((UrlImageIcon) icon).getUrl(); - } - - // Note: we embed the icon's URL in its description - String description = icon.getDescription(); - if (description == null) { - Msg.debug(Icons.class, "Unable to get URL for icon - icon description is missing"); - return null; - } - - try { - URL url = new URL(description); - return url; - } - catch (MalformedURLException e) { - Msg.trace(Icons.class, "Unable to get URL for icon: " + description); - return null; - } - - } - - // Creates a 16x16 icon with a scaled base icon and puts 3 dots below it. - private static class DotDotDotIcon implements Icon { - private Icon base; - - public DotDotDotIcon(Icon base) { - this.base = ResourceManager.getScaledIcon(base, 12, 12); - } - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - base.paintIcon(c, g, x, y); - g.setColor(new Color(50, 50, 50)); - g.fillRect(x + 6, y + 14, 2, 2); - g.fillRect(x + 9, y + 14, 2, 2); - g.fillRect(x + 12, y + 14, 2, 2); - - } - - @Override - public int getIconWidth() { - return 16; - } - - @Override - public int getIconHeight() { - return 16; - } - + return null; } private Icons() { diff --git a/Ghidra/Framework/Generic/src/main/java/resources/MultiIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/MultiIcon.java index 10ff12602d..0622b1678e 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/MultiIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/MultiIcon.java @@ -21,6 +21,8 @@ import java.util.Objects; import javax.swing.Icon; +import ghidra.util.ColorUtils; + /** * Icon class for for displaying overlapping icons. Icons are drawn in the order they * are added. @@ -146,7 +148,7 @@ public class MultiIcon implements Icon { if (disabled) { // Alpha blend to background Color bgColor = c.getBackground(); - g.setColor(new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), 128)); + g.setColor(ColorUtils.withAlpha(bgColor, 128)); g.fillRect(x, y, width, height); } } diff --git a/Ghidra/Framework/Generic/src/main/java/resources/MultiIconBuilder.java b/Ghidra/Framework/Generic/src/main/java/resources/MultiIconBuilder.java index 0f0abe84ae..7ff95d565d 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/MultiIconBuilder.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/MultiIconBuilder.java @@ -52,7 +52,7 @@ public class MultiIconBuilder { * @return this builder (for chaining) */ public MultiIconBuilder addIcon(Icon icon, int w, int h, QUADRANT quandrant) { - ImageIcon scaled = ResourceManager.getScaledIcon(icon, w, h); + Icon scaled = ResourceManager.getScaledIcon(icon, w, h); int x = (multiIcon.getIconWidth() - scaled.getIconWidth()) * quandrant.x; int y = (multiIcon.getIconHeight() - scaled.getIconHeight()) * quandrant.y; @@ -75,7 +75,7 @@ public class MultiIconBuilder { * @return this builder (for chaining) */ public MultiIconBuilder addIcon(Icon icon, int w, int h, int x, int y) { - ImageIcon scaled = ResourceManager.getScaledIcon(icon, w, h); + Icon scaled = ResourceManager.getScaledIcon(icon, w, h); TranslateIcon txIcon = new TranslateIcon(scaled, x, y); multiIcon.addIcon(txIcon); return this; @@ -127,6 +127,16 @@ public class MultiIconBuilder { return addIcon(icon, w, h, QUADRANT.LL); } + // TODO + public MultiIconBuilder addCenteredIcon(Icon icon) { + int x = (multiIcon.getIconWidth() - icon.getIconWidth()) / 2; + int y = (multiIcon.getIconHeight() - icon.getIconHeight()) / 2; + + TranslateIcon txIcon = new TranslateIcon(icon, x, y); + multiIcon.addIcon(txIcon); + return this; + } + /** * Add text overlaid on the base icon, aligned to the specified quadrant. * diff --git a/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java b/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java index 808ffec712..05a040d4cb 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/ResourceManager.java @@ -15,13 +15,13 @@ */ package resources; -import java.awt.Image; -import java.awt.MediaTracker; +import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.net.*; import java.nio.file.Path; import java.util.*; +import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors; @@ -30,7 +30,8 @@ import javax.swing.*; import org.apache.commons.lang3.StringUtils; -import generic.Images; +import generic.theme.GIcon; +import ghidra.framework.Application; import ghidra.util.Msg; import ghidra.util.SystemUtilities; import resources.icons.*; @@ -46,15 +47,17 @@ import utility.module.ModuleUtilities; * as opposed to using the flawed constructor {@link ImageIcon#ImageIcon(Image)}. */ public class ResourceManager { + public static final String BOMB = "images/core.png"; + public static final String BIG_BOMB = "images/core24.png"; + public static final String EXTERNAL_ICON_PREFIX = "[EXTERNAL]"; - private final static String DEFAULT_ICON_FILENAME = Images.BOMB; - private static ImageIcon DEFAULT_ICON; - private static Map iconMap = new HashMap<>(); + private static final Map iconMap = new HashMap<>(); private static List defaultSearchPaths; private static List testSearchPaths; private static ClassLoader classLoader = ResourceManager.class.getClassLoader(); + private static final ImageIcon DEFAULT_ICON = loadDefaultIcon(); /** * Finds a resource with a given name. This method returns null if no @@ -336,7 +339,25 @@ public class ResourceManager { * @param height the height of the new icon * @return A new, scaled ImageIcon */ - public static ImageIcon getScaledIcon(Icon icon, int width, int height) { + public static ImageIcon getScaledIcon(ImageIcon icon, int width, int height) { + return new ScaledImageIcon(icon, width, height); + } + + /** + * Creates a scaled Icon from the given icon with scaling of + * {@link Image#SCALE_AREA_AVERAGING}. If an EmptyIcon is passed, a new EmptyIcon is returned + * with the new dimensions. + * + * @param icon the icon to scale + * @param width the width of the new icon + * @param height the height of the new icon + * @return A new, scaled ImageIcon + */ + public static Icon getScaledIcon(Icon icon, int width, int height) { + if (icon instanceof EmptyIcon) { + return new EmptyIcon(width, height); + } + return new ScaledImageIcon(icon, width, height); } @@ -396,6 +417,9 @@ public class ResourceManager { if (icon instanceof ImageIcon) { return (ImageIcon) icon; } + if (icon instanceof GIcon) { + return ((GIcon) icon).getImageIcon(); + } return new DerivedImageIcon(icon); } @@ -415,26 +439,9 @@ public class ResourceManager { if (icon instanceof ImageIcon) { iconName = ((ImageIcon) icon).getDescription(); } - - /* - TODO - not sure why we wanted just the name and not the entire URL? Delete this - after a bit - - if (iconName == null) { - return null; + if (icon instanceof GIcon) { + return ((GIcon) icon).getId(); } - - int pos = iconName.lastIndexOf(File.separator); - if (pos >= 0) { - iconName = iconName.substring(pos + 1); - } - else { - pos = iconName.lastIndexOf("/"); - if (pos >= 0) { - iconName = iconName.substring(pos + 1); - } - } - */ return iconName; } @@ -474,49 +481,123 @@ public class ResourceManager { } /** - * Load the image specified by filename; returns the default bomb icon - * if problems occur trying to load the file. + * Attempts to load an icon from the given path. Returns the icon or null if no icon was + * found from the given path. This differs from {@link #loadImage(String)} in that + * loadImage will return the default Icon if one can't be found. Further, loadImage will cache + * even the default value, while findIcon only caches resolved icons. + *

* - * @param filename name of file to load, e.g., "images/home.gif" - * @return the image icon stored in the bytes + * @param path the icon to load, e.g., "images/home.gif" + * @return the ImageIcon if it exists or null */ - public static ImageIcon loadImage(String filename) { - ImageIcon icon = iconMap.get(filename); + public static ImageIcon findIcon(String path) { + + // use the wrapper so that images are not loaded until they are needed + ImageIcon icon = iconMap.get(path); if (icon == null) { - icon = doLoadIcon(filename, ResourceManager.getDefaultIcon()); - iconMap.put(filename, icon); + icon = doLoadIcon(path); + if (icon != null) { + iconMap.put(path, icon); + } } return icon; } - private static ImageIcon doLoadIcon(String filename, ImageIcon defaultIcon) { + /** + * Load the icon specified by iconPath. The iconPath can be either a path to a resource on + * the classpath or a relative or absolute path to an icon on the file system. If the iconPath + * is a path to a classpath resource, then it will be searched directly or also with an "images/" + * prepended to the path. For example, if there exists an icon "home.gif" on the classpath that + * was stored in the standard "images" resource directory, then it exists on the classpath + * as "images/home.gif". That icon will be found if the iconPath is either "images/home.gif" or + * just as "home.gif". + * + * @param iconPath name of file to load, e.g., "images/home.gif" + * @return an Icon from the given iconPath or null, if no such icon can be found + */ + + public static Icon loadIcon(String iconPath) { + ImageIcon icon = iconMap.get(iconPath); + if (icon == null) { + icon = doLoadIcon(iconPath); + iconMap.put(iconPath, icon == null ? DEFAULT_ICON : icon); + } + + return icon == DEFAULT_ICON ? null : icon; + } + + /** + * Load the image specified by filename; returns the default bomb icon + * if problems occur trying to load the file. + * + * @param iconPath name of file to load, e.g., "images/home.gif" + * @return the image icon stored in the bytes + */ + public static ImageIcon loadImage(String iconPath) { + ImageIcon icon = iconMap.get(iconPath); + if (icon == null) { + icon = doLoadIcon(iconPath); + iconMap.put(iconPath, icon == null ? DEFAULT_ICON : icon); + } + return icon == null ? new UnresolvedIcon(iconPath, DEFAULT_ICON) : icon; + } + + public static Set getLoadedUrlIcons() { + Set icons = new HashSet<>(); + for (Icon icon : iconMap.values()) { + if (icon instanceof UrlImageIcon) { + icons.add(icon); + } + } + + return icons; + } + + private static UrlImageIcon doLoadIcon(String path) { + + // if the has the "external prefix", it is an icon in the user's application directory + if (path.startsWith(EXTERNAL_ICON_PREFIX)) { + String relativePath = path.substring(EXTERNAL_ICON_PREFIX.length()); + File dir = Application.getUserSettingsDirectory(); + File iconFile = new File(dir, relativePath); + if (iconFile.exists()) { + try { + return new UrlImageIcon(path, iconFile.toURI().toURL()); + } + catch (MalformedURLException e) { + // handled below + } + } + return null; + } + // if only the name of an icon is given, but not a path, check to see if it is // a resource that lives under our "images/" folder - if (!filename.contains("/")) { - URL url = getResource("images/" + filename); + if (!path.contains("/")) { + URL url = getResource("images/" + path); if (url != null) { - return new UrlImageIcon(filename, url); + return new UrlImageIcon(path, url); } } // look for it directly with the given path - URL url = getResource(filename); + URL url = getResource(path); if (url != null) { - return new UrlImageIcon(filename, url); + return new UrlImageIcon(path, url); } // try using the filename as a file path - File imageFile = new File(filename); + File imageFile = new File(path); if (imageFile.exists()) { try { - return new UrlImageIcon(filename, imageFile.toURI().toURL()); + return new UrlImageIcon(path, imageFile.toURI().toURL()); } catch (MalformedURLException e) { // handled below } } - return defaultIcon; + return null; } /** @@ -549,14 +630,6 @@ public class ResourceManager { } public static ImageIcon getDefaultIcon() { - if (DEFAULT_ICON == null) { - URL url = getResource(DEFAULT_ICON_FILENAME); - if (url == null) { - Msg.error(ResourceManager.class, - "Could not find default icon: " + DEFAULT_ICON_FILENAME); - } - DEFAULT_ICON = new UrlImageIcon(DEFAULT_ICON_FILENAME, url); - } return DEFAULT_ICON; } @@ -566,6 +639,16 @@ public class ResourceManager { return list; } + private static ImageIcon loadDefaultIcon() { + URL url = getResource(BOMB); + if (url != null) { + return new UrlImageIcon(BOMB, url); + } + Msg.error(ResourceManager.class, + "Could not find default icon: " + BOMB); + return getImageIcon(new ColorIcon3D(Color.RED, 16, 16)); + } + private static void filterImages(Set set) { Iterator it = set.iterator(); while (it.hasNext()) { diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java index 61ffd4800d..5605b28b69 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/DerivedImageIcon.java @@ -23,6 +23,7 @@ import java.util.Objects; import javax.swing.Icon; import javax.swing.ImageIcon; +import generic.theme.GIcon; import generic.util.image.ImageUtils; import resources.ResourceManager; @@ -32,6 +33,7 @@ import resources.ResourceManager; public class DerivedImageIcon extends LazyImageIcon { private Icon sourceIcon; private Image sourceImage; + private Icon cachedDelegate; /** * Constructor for deriving from an icon @@ -52,6 +54,20 @@ public class DerivedImageIcon extends LazyImageIcon { this.sourceImage = Objects.requireNonNull(image); } + public Icon getSourceIcon() { + return sourceIcon; + } + + protected boolean sourceIconChanged() { + if (sourceIcon instanceof GIcon gIcon) { + if (cachedDelegate != gIcon.getDelegate()) { + cachedDelegate = gIcon.getDelegate(); + return true; + } + } + return false; + } + protected ImageIcon createImageIcon() { Image image = createImage(); String imageName = getFilename(); diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/EmptyIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/EmptyIcon.java index ea1bc3f932..220170db42 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/icons/EmptyIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/EmptyIcon.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,29 +17,55 @@ package resources.icons; import java.awt.Component; import java.awt.Graphics; +import java.util.Objects; import javax.swing.Icon; -public class EmptyIcon implements Icon { +public class EmptyIcon implements Icon { - private int width; - private int height; - - public EmptyIcon( int width, int height ) { - this.width = width; - this.height = height; - } - - public int getIconHeight() { - return height; - } + private int width; + private int height; - public int getIconWidth() { - return width; - } + public EmptyIcon(int width, int height) { + this.width = width; + this.height = height; + } - public void paintIcon( Component c, Graphics g, int x, int y ) { - // no-op - } + public int getIconHeight() { + return height; + } + + public int getIconWidth() { + return width; + } + + public void paintIcon(Component c, Graphics g, int x, int y) { + // no-op + } + + @Override + public int hashCode() { + return Objects.hash(height, width); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EmptyIcon other = (EmptyIcon) obj; + return height == other.height && width == other.width; + } + + @Override + public String toString() { + return "EmptyIcon(" + width + "," + height + ")"; + } } diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java index 8c02405404..0004f3446f 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/LazyImageIcon.java @@ -39,7 +39,7 @@ public abstract class LazyImageIcon extends ImageIcon implements FileBasedIcon { } private synchronized void init() { - if (!loaded) { + if (!loaded || sourceIconChanged()) { loaded = true; ImageIcon imageIcon = createImageIcon(); if (imageIcon == null) { @@ -52,6 +52,10 @@ public abstract class LazyImageIcon extends ImageIcon implements FileBasedIcon { protected abstract ImageIcon createImageIcon(); + protected boolean sourceIconChanged() { + return false; + } + @Override public String getFilename() { return getDescription(); diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/RotateIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/RotateIcon.java index 29e3886c94..7df10bb794 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/icons/RotateIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/RotateIcon.java @@ -60,4 +60,20 @@ public class RotateIcon implements Icon { } return description; } + + /** + * The source icon being rotated. + * @return the source icon being rotate + */ + public Icon getSourceIcon() { + return icon; + } + + /** + * Returns the rotation amount. + * @return the rotation amount + */ + public int getRotation() { + return degrees; + } } diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/TranslateIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/TranslateIcon.java index 52e5ed09e3..b624428ef8 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/icons/TranslateIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/TranslateIcon.java @@ -58,4 +58,29 @@ public class TranslateIcon implements Icon { public String toString() { return getClass().getSimpleName() + "[" + ResourceManager.getIconName(icon) + "]"; } + + // for testing + /** + * Returns the icon that is being translated + * @return the icon that is being translated + */ + public Icon getBaseIcon() { + return icon; + } + + /** + * Returns the amount the icon is being translated on the x axis; + * @return the amount the icon is being translated on the x axis; + */ + public int getX() { + return translateX; + } + + /** + * Returns the amount the icon is being translated on the y axis; + * @return the amount the icon is being translated on the y axis; + */ + public int getY() { + return translateY; + } } diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/UnresolvedIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/UnresolvedIcon.java new file mode 100644 index 0000000000..77f18b73fd --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/UnresolvedIcon.java @@ -0,0 +1,29 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package resources.icons; + +import javax.swing.ImageIcon; + +/** + * Icon class for when we can't find an icon for a path + */ +public class UnresolvedIcon extends DerivedImageIcon { + + public UnresolvedIcon(String path, ImageIcon icon) { + super("Unresolved: " + path, icon.getImage()); + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java b/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java index ceacdf1c8b..6904c7c547 100644 --- a/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java +++ b/Ghidra/Framework/Generic/src/main/java/resources/icons/UrlImageIcon.java @@ -30,6 +30,7 @@ import ghidra.util.Msg; * {@link LazyImageIcon} that is created from a URL to an icon file. */ public class UrlImageIcon extends LazyImageIcon { + private String originalPath; private URL imageUrl; /** @@ -38,14 +39,27 @@ public class UrlImageIcon extends LazyImageIcon { * @param url the {@link URL} to an icon resource file */ public UrlImageIcon(String path, URL url) { - super(path); + super(url.toExternalForm()); + this.originalPath = Objects.requireNonNull(path); this.imageUrl = Objects.requireNonNull(url); } + /** + * Returns the URL that was used to create this icon + * @return the URL that was used to create this icon + */ public URL getUrl() { return imageUrl; } + /** + * Returns the original path that was used to generate the URL (e.g. images/foo.png) + * @return the original path that was used to generate the URL (e.g. images/foo.png) + */ + public String getOriginalPath() { + return originalPath; + } + @Override protected ImageIcon createImageIcon() { String name = getFilename(); @@ -82,4 +96,25 @@ public class UrlImageIcon extends LazyImageIcon { } return null; } + + @Override + public int hashCode() { + return imageUrl.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + UrlImageIcon other = (UrlImageIcon) obj; + return Objects.equals(imageUrl, other.imageUrl); + } + } diff --git a/Ghidra/Framework/Docking/src/main/resources/images/EmptyIcon.gif b/Ghidra/Framework/Generic/src/main/resources/images/EmptyIcon.gif similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/EmptyIcon.gif rename to Ghidra/Framework/Generic/src/main/resources/images/EmptyIcon.gif diff --git a/Ghidra/Framework/Docking/src/main/resources/images/EmptyIcon16.gif b/Ghidra/Framework/Generic/src/main/resources/images/EmptyIcon16.gif similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/EmptyIcon16.gif rename to Ghidra/Framework/Generic/src/main/resources/images/EmptyIcon16.gif diff --git a/Ghidra/Framework/Project/src/main/resources/images/closedSmallFolder.png b/Ghidra/Framework/Generic/src/main/resources/images/closedSmallFolder.png similarity index 100% rename from Ghidra/Framework/Project/src/main/resources/images/closedSmallFolder.png rename to Ghidra/Framework/Generic/src/main/resources/images/closedSmallFolder.png diff --git a/Ghidra/Features/Base/src/main/resources/images/collapse_all.png b/Ghidra/Framework/Generic/src/main/resources/images/collapse_all.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/collapse_all.png rename to Ghidra/Framework/Generic/src/main/resources/images/collapse_all.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/disk.png b/Ghidra/Framework/Generic/src/main/resources/images/disk.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/disk.png rename to Ghidra/Framework/Generic/src/main/resources/images/disk.png diff --git a/Ghidra/Framework/Project/src/main/resources/images/disk_save_as.png b/Ghidra/Framework/Generic/src/main/resources/images/disk_save_as.png similarity index 100% rename from Ghidra/Framework/Project/src/main/resources/images/disk_save_as.png rename to Ghidra/Framework/Generic/src/main/resources/images/disk_save_as.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/down.png b/Ghidra/Framework/Generic/src/main/resources/images/down.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/down.png rename to Ghidra/Framework/Generic/src/main/resources/images/down.png diff --git a/Ghidra/Framework/Project/src/main/resources/images/edit-cut.png b/Ghidra/Framework/Generic/src/main/resources/images/edit-cut.png similarity index 100% rename from Ghidra/Framework/Project/src/main/resources/images/edit-cut.png rename to Ghidra/Framework/Generic/src/main/resources/images/edit-cut.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/edit-cut22.png b/Ghidra/Framework/Generic/src/main/resources/images/edit-cut22.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/edit-cut22.png rename to Ghidra/Framework/Generic/src/main/resources/images/edit-cut22.png diff --git a/Ghidra/Features/Base/src/main/resources/images/erase16.png b/Ghidra/Framework/Generic/src/main/resources/images/erase16.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/erase16.png rename to Ghidra/Framework/Generic/src/main/resources/images/erase16.png diff --git a/Ghidra/Framework/Generic/src/main/resources/images/go-home.png b/Ghidra/Framework/Generic/src/main/resources/images/go-home.png new file mode 100644 index 0000000000..a46fb22206 Binary files /dev/null and b/Ghidra/Framework/Generic/src/main/resources/images/go-home.png differ diff --git a/Ghidra/Framework/Docking/src/main/resources/images/information.png b/Ghidra/Framework/Generic/src/main/resources/images/information.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/information.png rename to Ghidra/Framework/Generic/src/main/resources/images/information.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/left.alternate.png b/Ghidra/Framework/Generic/src/main/resources/images/left.alternate.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/left.alternate.png rename to Ghidra/Framework/Generic/src/main/resources/images/left.alternate.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/left.png b/Ghidra/Framework/Generic/src/main/resources/images/left.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/left.png rename to Ghidra/Framework/Generic/src/main/resources/images/left.png diff --git a/Ghidra/Features/Base/src/main/resources/images/locationIn.gif b/Ghidra/Framework/Generic/src/main/resources/images/locationIn.gif similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/locationIn.gif rename to Ghidra/Framework/Generic/src/main/resources/images/locationIn.gif diff --git a/Ghidra/Features/Base/src/main/resources/images/locationOut.gif b/Ghidra/Framework/Generic/src/main/resources/images/locationOut.gif similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/locationOut.gif rename to Ghidra/Framework/Generic/src/main/resources/images/locationOut.gif diff --git a/Ghidra/Framework/Project/src/main/resources/images/page_paste.png b/Ghidra/Framework/Generic/src/main/resources/images/page_paste.png similarity index 100% rename from Ghidra/Framework/Project/src/main/resources/images/page_paste.png rename to Ghidra/Framework/Generic/src/main/resources/images/page_paste.png diff --git a/Ghidra/Features/Base/src/main/resources/images/page_white_copy.png b/Ghidra/Framework/Generic/src/main/resources/images/page_white_copy.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/page_white_copy.png rename to Ghidra/Framework/Generic/src/main/resources/images/page_white_copy.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/right.alternate.png b/Ghidra/Framework/Generic/src/main/resources/images/right.alternate.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/right.alternate.png rename to Ghidra/Framework/Generic/src/main/resources/images/right.alternate.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/right.png b/Ghidra/Framework/Generic/src/main/resources/images/right.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/right.png rename to Ghidra/Framework/Generic/src/main/resources/images/right.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/sortascending.png b/Ghidra/Framework/Generic/src/main/resources/images/sortascending.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/sortascending.png rename to Ghidra/Framework/Generic/src/main/resources/images/sortascending.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/sortdescending.png b/Ghidra/Framework/Generic/src/main/resources/images/sortdescending.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/sortdescending.png rename to Ghidra/Framework/Generic/src/main/resources/images/sortdescending.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/up.png b/Ghidra/Framework/Generic/src/main/resources/images/up.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/up.png rename to Ghidra/Framework/Generic/src/main/resources/images/up.png diff --git a/Ghidra/Features/Base/src/main/resources/images/viewmagfit.png b/Ghidra/Framework/Generic/src/main/resources/images/viewmagfit.png similarity index 100% rename from Ghidra/Features/Base/src/main/resources/images/viewmagfit.png rename to Ghidra/Framework/Generic/src/main/resources/images/viewmagfit.png diff --git a/Ghidra/Framework/Docking/src/main/resources/images/warning.png b/Ghidra/Framework/Generic/src/main/resources/images/warning.png similarity index 100% rename from Ghidra/Framework/Docking/src/main/resources/images/warning.png rename to Ghidra/Framework/Generic/src/main/resources/images/warning.png diff --git a/Ghidra/Framework/Generic/src/test/java/generic/constraint/DecisionTreeTest.java b/Ghidra/Framework/Generic/src/test/java/generic/constraint/DecisionTreeTest.java index d52adb1c35..1e1141558d 100644 --- a/Ghidra/Framework/Generic/src/test/java/generic/constraint/DecisionTreeTest.java +++ b/Ghidra/Framework/Generic/src/test/java/generic/constraint/DecisionTreeTest.java @@ -15,8 +15,7 @@ */ package generic.constraint; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.awt.Color; import java.io.ByteArrayInputStream; @@ -89,7 +88,7 @@ public class DecisionTreeTest extends AbstractGenericTest { @Before public void setUp() throws Exception { - decisionTree = new DecisionTree(); + decisionTree = new DecisionTree<>(); decisionTree.registerConstraintType("BLUE", BlueColorConstraint.class); decisionTree.registerConstraintType("GREEN", GreenColorConstraint.class); decisionTree.registerConstraintType("RED", RedColorConstraint.class); @@ -160,7 +159,7 @@ public class DecisionTreeTest extends AbstractGenericTest { @Test public void testMatchMultiple() { - Color c = new Color(255, 255, 0); + Color c = Color.YELLOW; DecisionSet decisionSet = decisionTree.getDecisionsSet(c, "NAME"); List decisions = decisionSet.getDecisions(); assertEquals(2, decisions.size()); @@ -179,7 +178,7 @@ public class DecisionTreeTest extends AbstractGenericTest { @Test public void testNoMatchUsingDefault() { - Color c = new Color(100, 100, 100); + Color c = Color.GRAY; DecisionSet decisionSet = decisionTree.getDecisionsSet(c, "NAME"); List decisions = decisionSet.getDecisions(); assertEquals(1, decisions.size()); diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/ColorValueTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/ColorValueTest.java new file mode 100644 index 0000000000..662e33e3e5 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/ColorValueTest.java @@ -0,0 +1,153 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.awt.Color; + +import org.junit.Before; +import org.junit.Test; + +import ghidra.util.WebColors; + +public class ColorValueTest { + + private GThemeValueMap values; + + @Before + public void setup() { + values = new GThemeValueMap(); + } + + @Test + public void testDirectValue() { + ColorValue value = new ColorValue("color.test", Color.RED); + values.addColor(value); + + assertEquals("color.test", value.getId()); + assertEquals(Color.RED, value.getRawValue()); + assertNull(value.getReferenceId()); + assertEquals(Color.RED, value.get(values)); + } + + @Test + public void testIndirectValue() { + values.addColor(new ColorValue("color.parent", Color.RED)); + ColorValue value = new ColorValue("color.test", "color.parent"); + values.addColor(value); + + assertEquals("color.test", value.getId()); + assertNull(value.getRawValue()); + assertEquals("color.parent", value.getReferenceId()); + assertEquals(Color.RED, value.get(values)); + } + + @Test + public void testIndirectMultiHopValue() { + values.addColor(new ColorValue("color.grandparent", Color.RED)); + values.addColor(new ColorValue("color.parent", "color.grandparent")); + ColorValue value = new ColorValue("color.test", "color.parent"); + values.addColor(value); + + assertNull(value.getRawValue()); + assertEquals("color.parent", value.getReferenceId()); + assertEquals(Color.RED, value.get(values)); + } + + @Test + public void testUnresolvedIndirectValue() { + ColorValue value = new ColorValue("color.test", "color.parent"); + values.addColor(value); + + assertNull(value.getRawValue()); + assertEquals("color.parent", value.getReferenceId()); + assertEquals(ColorValue.LAST_RESORT_DEFAULT, value.get(values)); + } + + @Test + public void testReferenceLoop() { + values.addColor(new ColorValue("color.grandparent", "color.test")); + values.addColor(new ColorValue("color.parent", "color.grandparent")); + ColorValue value = new ColorValue("color.test", "color.parent"); + assertEquals(ColorValue.LAST_RESORT_DEFAULT, value.get(values)); + } + + @Test + public void testGetSerializationString() { + ColorValue value = new ColorValue("color.test", Color.BLUE); + assertEquals("color.test = #0000ff // Blue", value.getSerializationString()); + + value = new ColorValue("foo.bar", Color.BLUE); + assertEquals("[color]foo.bar = #0000ff // Blue", value.getSerializationString()); + + value = new ColorValue("color.test", "xyz.abc"); + assertEquals("color.test = [color]xyz.abc", value.getSerializationString()); + } + + @Test + public void testParse() { + ColorValue value = ColorValue.parse("color.test", "#0000ff"); + assertEquals("color.test", value.getId()); + assertEquals(WebColors.BLUE, value.getRawValue()); + assertEquals(null, value.getReferenceId()); + + value = ColorValue.parse("[color]foo.bar", "#0000ff"); + assertEquals("foo.bar", value.getId()); + assertEquals(WebColors.BLUE, value.getRawValue()); + assertEquals(null, value.getReferenceId()); + + value = ColorValue.parse("color.test", "[color]xyz.abc"); + assertEquals("color.test", value.getId()); + assertEquals(null, value.getRawValue()); + assertEquals("xyz.abc", value.getReferenceId()); + } + + @Test + public void testIsColorKey() { + assertTrue(ColorValue.isColorKey("color.a.b.c")); + assertTrue(ColorValue.isColorKey("[color]a.b.c")); + assertFalse(ColorValue.isColorKey("a.b.c")); + } + + @Test + public void testInheritsFrom() { + ColorValue grandParent = new ColorValue("color.grandparent", Color.RED); + values.addColor(grandParent); + ColorValue parent = new ColorValue("color.parent", "color.grandparent"); + values.addColor(parent); + ColorValue value = new ColorValue("color.test", "color.parent"); + values.addColor(value); + + assertTrue(value.inheritsFrom("color.parent", values)); + assertTrue(value.inheritsFrom("color.grandparent", values)); + assertTrue(parent.inheritsFrom("color.grandparent", values)); + + assertFalse(value.inheritsFrom("color.test", values)); + assertFalse(parent.inheritsFrom("color.test", values)); + assertFalse(grandParent.inheritsFrom("color.test", values)); + } + + @Test + public void testCreatingValueFromGColor() { + ColorValue parent = new ColorValue("color.parent", Color.RED); + values.addColor(parent); + Color gColor = new GColor("color.parent"); + ColorValue value = new ColorValue("color.value", gColor); + assertEquals("color.parent", value.getReferenceId()); + assertNull(value.getRawValue()); + } +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/FontModifierTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/FontModifierTest.java new file mode 100644 index 0000000000..8a498c2edf --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/FontModifierTest.java @@ -0,0 +1,192 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.awt.Font; +import java.text.ParseException; + +import org.junit.Test; + +public class FontModifierTest { + private Font baseFont = new Font("Dialog", Font.PLAIN, 12); + + @Test + public void testNoModifiers() throws ParseException { + assertNull(FontModifier.parse("")); + } + + @Test + public void testSizeModifier() throws ParseException { + FontModifier modifier = FontModifier.parse("[6]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(6, newFont.getSize()); + assertEquals(baseFont.getName(), newFont.getName()); + assertEquals(baseFont.getStyle(), newFont.getStyle()); + } + + @Test + public void testStyleModifierPlain() throws ParseException { + FontModifier modifier = FontModifier.parse("[plain]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(Font.PLAIN, newFont.getStyle()); + assertEquals(baseFont.getName(), newFont.getName()); + assertEquals(baseFont.getSize(), newFont.getSize()); + } + + @Test + public void testStyleModifierBold() throws ParseException { + FontModifier modifier = FontModifier.parse("[bold]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(Font.BOLD, newFont.getStyle()); + assertEquals(baseFont.getName(), newFont.getName()); + assertEquals(baseFont.getSize(), newFont.getSize()); + } + + @Test + public void testStyleModifierItalic() throws ParseException { + FontModifier modifier = FontModifier.parse("[ITALIC]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(Font.ITALIC, newFont.getStyle()); + assertEquals(baseFont.getName(), newFont.getName()); + assertEquals(baseFont.getSize(), newFont.getSize()); + } + + @Test + public void testStyleModifierBoldItalic() throws ParseException { + FontModifier modifier = FontModifier.parse("[BOLDitalic]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(Font.ITALIC | Font.BOLD, newFont.getStyle()); + assertEquals(baseFont.getName(), newFont.getName()); + assertEquals(baseFont.getSize(), newFont.getSize()); + } + + @Test + public void testStyleModifierBoldItalic2() throws ParseException { + FontModifier modifier = FontModifier.parse("[BOLD][italic]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(Font.ITALIC | Font.BOLD, newFont.getStyle()); + assertEquals(baseFont.getName(), newFont.getName()); + assertEquals(baseFont.getSize(), newFont.getSize()); + } + + @Test + public void testFamilyModification() throws ParseException { + FontModifier modifier = FontModifier.parse("[monospaced]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals("Monospaced", newFont.getFamily()); + assertEquals(baseFont.getStyle(), newFont.getStyle()); + assertEquals(baseFont.getSize(), newFont.getSize()); + } + + @Test + public void testSizeAndStyleModification() throws ParseException { + FontModifier modifier = FontModifier.parse("[16][bold]"); + assertNotNull(modifier); + Font newFont = modifier.modify(baseFont); + assertEquals(baseFont.getName(), newFont.getFamily()); + assertEquals(Font.BOLD, newFont.getStyle()); + assertEquals(16, newFont.getSize()); + + } + + @Test + public void testFamilyModificationMultiple() { + try { + FontModifier.parse("[monospaced][courier]"); + fail("Expecected Exception"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testStyleModifierIncompatableStyles() { + try { + FontModifier.parse("[plain][italic]"); + fail("Expected IllegalStateException"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString() { + try { + FontModifier.parse("asdfasf"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString2() { + try { + FontModifier.parse("[12]aa[13]"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString3() { + try { + FontModifier.parse("[12]aa13]"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString4() { + try { + FontModifier.parse("[12][plain]sz"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testGetSerializationString() { + //@formatter:off + assertEquals("[12]", new FontModifier(null, null, 12).getSerializationString()); + assertEquals("[plain]", new FontModifier(null, Font.PLAIN, null).getSerializationString()); + assertEquals("[bold]", new FontModifier(null, Font.BOLD, null).getSerializationString()); + assertEquals("[italic]", new FontModifier(null, Font.ITALIC, null).getSerializationString()); + assertEquals("[bold][italic]", new FontModifier(null, Font.BOLD | Font.ITALIC, null).getSerializationString()); + assertEquals("[Monospaced]",new FontModifier("Monospaced", null, null).getSerializationString()); + assertEquals("[Monospaced][12][plain]",new FontModifier("Monospaced", Font.PLAIN, 12).getSerializationString()); + //@formatter:on + } +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/FontValueTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/FontValueTest.java new file mode 100644 index 0000000000..d0e0330fe2 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/FontValueTest.java @@ -0,0 +1,143 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.awt.Font; +import java.text.ParseException; + +import org.junit.Before; +import org.junit.Test; + +public class FontValueTest { + private static Font FONT = new Font("Dialog", Font.PLAIN, 12); + private GThemeValueMap values; + + @Before + public void setup() { + values = new GThemeValueMap(); + } + + @Test + public void testDirectValue() { + FontValue value = new FontValue("font.test", FONT); + values.addFont(value); + + assertEquals("font.test", value.getId()); + assertEquals(FONT, value.getRawValue()); + assertNull(value.getReferenceId()); + assertEquals(FONT, value.get(values)); + } + + @Test + public void testIndirectValue() { + values.addFont(new FontValue("font.parent", FONT)); + FontValue value = new FontValue("font.test", "font.parent"); + values.addFont(value); + + assertEquals("font.test", value.getId()); + assertNull(value.getRawValue()); + assertEquals("font.parent", value.getReferenceId()); + assertEquals(FONT, value.get(values)); + } + + @Test + public void TestIndirectMultiHopValue() { + values.addFont(new FontValue("font.grandparent", FONT)); + values.addFont(new FontValue("font.parent", "font.grandparent")); + FontValue value = new FontValue("font.test", "font.parent"); + values.addFont(value); + + assertNull(value.getRawValue()); + assertEquals("font.parent", value.getReferenceId()); + assertEquals(FONT, value.get(values)); + } + + @Test + public void TestUnresolvedIndirectValue() { + FontValue value = new FontValue("font.test", "font.parent"); + values.addFont(value); + + assertNull(value.getRawValue()); + assertEquals("font.parent", value.getReferenceId()); + assertEquals(FontValue.LAST_RESORT_DEFAULT, value.get(values)); + } + + @Test + public void testReferenceLoop() { + values.addFont(new FontValue("font.grandparent", "font.test")); + values.addFont(new FontValue("font.parent", "font.grandparent")); + FontValue value = new FontValue("font.test", "font.parent"); + assertEquals(FontValue.LAST_RESORT_DEFAULT, value.get(values)); + } + + @Test + public void testGetSerializationString() { + FontValue value = new FontValue("font.test", FONT); + assertEquals("font.test = Dialog-PLAIN-12", value.getSerializationString()); + + value = new FontValue("foo.bar", FONT); + assertEquals("[font]foo.bar = Dialog-PLAIN-12", value.getSerializationString()); + + value = new FontValue("font.test", "xyz.abc"); + assertEquals("font.test = [font]xyz.abc", value.getSerializationString()); + } + + @Test + public void testParse() throws ParseException { + FontValue value = FontValue.parse("font.test", "Dialog-PLAIN-12"); + assertEquals("font.test", value.getId()); + assertEquals(FONT, value.getRawValue()); + assertEquals(null, value.getReferenceId()); + + value = FontValue.parse("[font]foo.bar", "Dialog-PLAIN-12"); + assertEquals("foo.bar", value.getId()); + assertEquals(FONT, value.getRawValue()); + assertEquals(null, value.getReferenceId()); + + value = FontValue.parse("font.test", "[font]xyz.abc"); + assertEquals("font.test", value.getId()); + assertEquals(null, value.getRawValue()); + assertEquals("xyz.abc", value.getReferenceId()); + } + + @Test + public void testIsFontKey() { + assertTrue(FontValue.isFontKey("font.a.b.c")); + assertTrue(FontValue.isFontKey("[font]a.b.c")); + assertFalse(FontValue.isFontKey("a.b.c")); + } + + @Test + public void testInheritsFrom() { + FontValue grandParent = new FontValue("font.grandparent", FONT); + values.addFont(grandParent); + FontValue parent = new FontValue("font.parent", "font.grandparent"); + values.addFont(parent); + FontValue value = new FontValue("font.test", "font.parent"); + values.addFont(value); + + assertTrue(value.inheritsFrom("font.parent", values)); + assertTrue(value.inheritsFrom("font.grandparent", values)); + assertTrue(parent.inheritsFrom("font.grandparent", values)); + + assertFalse(value.inheritsFrom("font.test", values)); + assertFalse(parent.inheritsFrom("font.test", values)); + assertFalse(grandParent.inheritsFrom("font.test", values)); + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/GThemeTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/GThemeTest.java new file mode 100644 index 0000000000..4c0d3801b5 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/GThemeTest.java @@ -0,0 +1,125 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.awt.Color; +import java.awt.Font; +import java.io.File; +import java.io.IOException; + +import javax.swing.Icon; + +import org.junit.Before; +import org.junit.Test; + +import generic.test.AbstractGenericTest; +import resources.ResourceManager; + +public class GThemeTest extends AbstractGenericTest { + + private static final Font COURIER = new Font("Courier", Font.BOLD, 14); + private static final Font DIALOG = new Font("Dialog", Font.PLAIN, 16); + private static final Color COLOR_WITH_ALPHA = new Color(10, 20, 30, 40); + private static final String ICON_PATH_1 = "images/error.png"; + private static final String ICON_PATH_2 = "images/exec.png"; + private static final Icon ICON1 = ResourceManager.loadImage(ICON_PATH_1); + private static final Icon ICON2 = ResourceManager.loadImage(ICON_PATH_2); + + private GTheme theme; + + @Before + public void setUp() { + theme = new GTheme("TestTheme"); + new Font("Courier", Font.BOLD, 12); + } + + @Test + public void testGetName() { + assertEquals("TestTheme", theme.getName()); + } + + @Test + public void testSetColor() { + theme.setColor("color.a.1", Color.BLUE); + assertEquals(Color.BLUE, theme.getColor("color.a.1").get(null)); + theme.setColor("color.a.1", Color.RED); + assertEquals(Color.RED, theme.getColor("color.a.1").get(null)); + } + + @Test + public void testSetFont() { + theme.setFont("font.a.1", DIALOG); + assertEquals(DIALOG, theme.getFont("font.a.1").get(null)); + } + + @Test + public void testSetIconPath() { + theme.setIcon("icon.a.1", ICON1); + assertEquals(ICON1, theme.getIcon("icon.a.1").get(null)); + } + + @Test + public void testSavingLoadingTheme() throws IOException { + theme = new GTheme("abc"); + theme.setColor("color.a.1", Color.RED); + theme.setColor("color.a.2", Color.BLUE); + theme.setColor("color.a.3", COLOR_WITH_ALPHA); + theme.setColorRef("color.a.4", "color.a.1"); + theme.setColor("foo.bar", Color.GREEN); + theme.setColorRef("foo.bar.xyz", "foo.bar"); + + theme.setFont("font.a.1", COURIER); + theme.setFont("font.a.2", DIALOG); + theme.setFontRef("font.a.3", "font.a.1"); + theme.setFont("x.y.z", COURIER); + theme.setFontRef("x.y.z.1", "x.y.z"); + + theme.setIcon("icon.a.1", ICON1); + theme.setIcon("icon.a.2", ICON2); + theme.setIconRef("icon.a.3", "icon.a.1"); + theme.setIcon("t.u.v", ICON1); + theme.setIconRef("t.u.v.1", "t.u.v"); + + File file = createTempFile("themeTest", ".theme"); + + new ThemeWriter(theme).writeThemeToFile(file); + theme = new ThemeReader(file).readTheme(); + + assertEquals("abc", theme.getName()); + assertEquals(LafType.getDefaultLookAndFeel(), theme.getLookAndFeelType()); + + assertEquals(Color.RED, theme.getColor("color.a.1").get(theme)); + assertEquals(Color.BLUE, theme.getColor("color.a.2").get(theme)); + assertEquals(COLOR_WITH_ALPHA, theme.getColor("color.a.3").get(theme)); + assertEquals("color.a.1", theme.getColor("color.a.4").getReferenceId()); + assertEquals(Color.RED, theme.getColor("color.a.4").get(theme)); + assertEquals(Color.GREEN, theme.getColor("foo.bar").get(theme)); + assertEquals(Color.GREEN, theme.getColor("foo.bar.xyz").get(theme)); + + assertEquals(COURIER, theme.getFont("font.a.1").get(theme)); + assertEquals(DIALOG, theme.getFont("font.a.2").get(theme)); + assertEquals(COURIER, theme.getFont("x.y.z").get(theme)); + assertEquals(COURIER, theme.getFont("x.y.z.1").get(theme)); + + assertEquals(ICON1, theme.getIcon("icon.a.1").get(theme)); + assertEquals(ICON2, theme.getIcon("icon.a.2").get(theme)); + assertEquals(ICON1, theme.getIcon("t.u.v").get(theme)); + assertEquals(ICON1, theme.getIcon("t.u.v.1").get(theme)); + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java new file mode 100644 index 0000000000..414d9b2332 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/IconModifierTest.java @@ -0,0 +1,189 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.awt.Dimension; +import java.awt.Point; +import java.text.ParseException; + +import javax.swing.Icon; + +import org.junit.Test; + +import resources.MultiIcon; +import resources.ResourceManager; +import resources.icons.RotateIcon; +import resources.icons.TranslateIcon; + +public class IconModifierTest { + private Icon baseIcon = ResourceManager.getDefaultIcon(); + private GThemeValueMap values = new GThemeValueMap(); + + @Test + public void testNoModifiers() throws Exception { + assertNull(IconModifier.parse("")); + } + + @Test + public void testSizeModifier() throws Exception { + IconModifier modifier = IconModifier.parse("[size(7,13)]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertEquals(7, modifiedIcon.getIconWidth()); + assertEquals(13, modifiedIcon.getIconHeight()); + } + + @Test + public void testSizeModifier2() throws Exception { + IconModifier modifier = IconModifier.parse("[SIZE(7,13)]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertEquals(7, modifiedIcon.getIconWidth()); + assertEquals(13, modifiedIcon.getIconHeight()); + } + + @Test + public void testMoveModifier() throws Exception { + IconModifier modifier = IconModifier.parse("[move(4, 3)]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertTrue(modifiedIcon instanceof TranslateIcon); + TranslateIcon translateIcon = (TranslateIcon) modifiedIcon; + + assertEquals(4, translateIcon.getX()); + assertEquals(3, translateIcon.getY()); + } + + @Test + public void testRotateModifier() throws Exception { + IconModifier modifier = IconModifier.parse("[rotate(90)]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertTrue(modifiedIcon instanceof RotateIcon); + RotateIcon rotateIcon = (RotateIcon) modifiedIcon; + + assertEquals(90, rotateIcon.getRotation()); + } + + @Test + public void testDisabledModifier() throws Exception { + IconModifier modifier = IconModifier.parse("[disabled]"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertNotEquals(baseIcon, modifiedIcon); + } + + @Test + public void testOverlayIcon() throws Exception { + IconModifier modifier = IconModifier.parse("{images/flag.png}"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertTrue(modifiedIcon instanceof MultiIcon); + MultiIcon multiIcon = (MultiIcon) modifiedIcon; + Icon[] icons = multiIcon.getIcons(); + assertEquals(2, icons.length); + assertEquals(baseIcon, icons[0]); + assertEquals(ResourceManager.loadImage("images/flag.png"), icons[1]); + } + + @Test + public void testOverlayIcon2() throws Exception { + IconModifier modifier = + IconModifier.parse("[size(20,25)]{images/flag.png[size(8,9)][move(4,4)]}"); + Icon modifiedIcon = modifier.modify(baseIcon, values); + assertTrue(modifiedIcon instanceof MultiIcon); + MultiIcon multiIcon = (MultiIcon) modifiedIcon; + Icon[] icons = multiIcon.getIcons(); + assertEquals(2, icons.length); + assertEquals(20, icons[0].getIconWidth()); + assertEquals(25, icons[0].getIconHeight()); + assertEquals(8, icons[1].getIconWidth()); + assertEquals(9, icons[1].getIconHeight()); + } + + @Test + public void testInvalidModifierString() { + try { + IconModifier.parse("dasdf"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString2() { + try { + IconModifier.parse("disabledx"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString3() { + try { + IconModifier.parse("[size(13,14,13)]"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString4() { + try { + IconModifier.parse("[size(14,12]"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString5() { + try { + IconModifier.parse("[size(14)]"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testInvalidModifierString6() { + try { + IconModifier.parse("[size(10,10)]move(3,4)]"); + fail("Expected IllegalArgumentExcption"); + } + catch (ParseException e) { + // expected + } + } + + @Test + public void testGetSerializationString() { + //@formatter:off + assertEquals("[size(5,9)]", new IconModifier(new Dimension(5,9), null, null, false).getSerializationString()); + assertEquals("[move(8,7)]", new IconModifier(null, new Point(8,7), null,false).getSerializationString()); + assertEquals("[disabled]", new IconModifier(null, null, null, true).getSerializationString()); + assertEquals("[size(5,0)][move(8,7)][disabled]", new IconModifier(new Dimension(5,0), new Point(8,7), null, true).getSerializationString()); + assertEquals("[rotate(90)]", new IconModifier(null, null, 90, false).getSerializationString()); + //@formatter:on + } +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/IconValueTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/IconValueTest.java new file mode 100644 index 0000000000..807365905a --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/IconValueTest.java @@ -0,0 +1,204 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package generic.theme; + +import static org.junit.Assert.*; + +import java.text.ParseException; + +import javax.swing.Icon; + +import org.junit.Before; +import org.junit.Test; + +import resources.MultiIcon; +import resources.ResourceManager; +import resources.icons.EmptyIcon; +import resources.icons.TranslateIcon; + +public class IconValueTest { + private static Icon ICON1 = ResourceManager.getDefaultIcon(); + private GThemeValueMap values; + + @Before + public void setup() { + values = new GThemeValueMap(); + } + + @Test + public void testDirectValue() { + IconValue value = new IconValue("icon.test", ICON1); + values.addIcon(value); + + assertEquals("icon.test", value.getId()); + assertEquals(ICON1, value.getRawValue()); + assertNull(value.getReferenceId()); + assertEquals(ICON1, value.get(values)); + } + + @Test + public void testIndirectValue() { + values.addIcon(new IconValue("icon.parent", ICON1)); + IconValue value = new IconValue("icon.test", "icon.parent"); + values.addIcon(value); + + assertEquals("icon.test", value.getId()); + assertNull(value.getRawValue()); + assertEquals("icon.parent", value.getReferenceId()); + assertEquals(ICON1, value.get(values)); + } + + @Test + public void TestIndirectMultiHopValue() { + values.addIcon(new IconValue("icon.grandparent", ICON1)); + values.addIcon(new IconValue("icon.parent", "icon.grandparent")); + IconValue value = new IconValue("icon.test", "icon.parent"); + values.addIcon(value); + + assertNull(value.getRawValue()); + assertEquals("icon.parent", value.getReferenceId()); + assertEquals(ICON1, value.get(values)); + } + + @Test + public void TestUnresolvedIndirectValue() { + IconValue value = new IconValue("icon.test", "icon.parent"); + values.addIcon(value); + + assertNull(value.getRawValue()); + assertEquals("icon.parent", value.getReferenceId()); + assertEquals(IconValue.LAST_RESORT_DEFAULT, value.get(values)); + } + + @Test + public void testReferenceLoop() { + values.addIcon(new IconValue("icon.grandparent", "icon.test")); + values.addIcon(new IconValue("icon.parent", "icon.grandparent")); + IconValue value = new IconValue("icon.test", "icon.parent"); + assertEquals(IconValue.LAST_RESORT_DEFAULT, value.get(values)); + } + + @Test + public void testGetSerializationString() { + IconValue value = new IconValue("icon.test", ICON1); + assertEquals("icon.test = images/core.png", value.getSerializationString()); + + value = new IconValue("foo.bar", ICON1); + assertEquals("[icon]foo.bar = images/core.png", value.getSerializationString()); + + value = new IconValue("icon.test", "xyz.abc"); + assertEquals("icon.test = [icon]xyz.abc", value.getSerializationString()); + } + + @Test + public void testParse() throws ParseException { + IconValue value = IconValue.parse("icon.test", "images/core.png"); + assertEquals("icon.test", value.getId()); + assertEquals(ICON1, value.getRawValue()); + assertEquals(null, value.getReferenceId()); + + value = IconValue.parse("[icon]foo.bar", "images/core.png"); + assertEquals("foo.bar", value.getId()); + assertEquals(ICON1, value.getRawValue()); + assertEquals(null, value.getReferenceId()); + + value = IconValue.parse("icon.test", "[icon]xyz.abc"); + assertEquals("icon.test", value.getId()); + assertEquals(null, value.getRawValue()); + assertEquals("xyz.abc", value.getReferenceId()); + } + + @Test + public void testParseWithOverlays() throws ParseException { + IconValue value = IconValue.parse("icon.test", + "images/core.png[size(25,25)]{images/flag.png[size(8,8)][move(4,4)]}"); + assertEquals("icon.test", value.getId()); + Icon icon = value.get(values); + assertTrue(icon instanceof MultiIcon); + MultiIcon multiIcon = (MultiIcon) icon; + Icon[] icons = multiIcon.getIcons(); + assertEquals(2, icons.length); + assertEquals(25, icons[0].getIconWidth()); + assertEquals(25, icons[0].getIconWidth()); + assertEquals(8, icons[1].getIconWidth()); + assertEquals(8, icons[1].getIconWidth()); + assertTrue(icons[1] instanceof TranslateIcon); + } + + @Test + public void testIsIconKey() { + assertTrue(IconValue.isIconKey("icon.a.b.c")); + assertTrue(IconValue.isIconKey("[icon]a.b.c")); + assertFalse(IconValue.isIconKey("a.b.c")); + } + + @Test + public void testInheritsFrom() { + IconValue grandParent = new IconValue("icon.grandparent", ICON1); + values.addIcon(grandParent); + IconValue parent = new IconValue("icon.parent", "icon.grandparent"); + values.addIcon(parent); + IconValue value = new IconValue("icon.test", "icon.parent"); + values.addIcon(value); + + assertTrue(value.inheritsFrom("icon.parent", values)); + assertTrue(value.inheritsFrom("icon.grandparent", values)); + assertTrue(parent.inheritsFrom("icon.grandparent", values)); + + assertFalse(value.inheritsFrom("icon.test", values)); + assertFalse(parent.inheritsFrom("icon.test", values)); + assertFalse(grandParent.inheritsFrom("icon.test", values)); + } + + @Test + public void testCreatingValueFromGIcon() { + IconValue parent = new IconValue("icon.parent", ICON1); + values.addIcon(parent); + Icon gIcon = new GIcon("icon.parent"); + IconValue value = new IconValue("icon.value", gIcon); + assertEquals("icon.parent", value.getReferenceId()); + assertNull(value.getRawValue()); + } + + @Test + public void testParseEmptyIcon() throws ParseException { + IconValue value = IconValue.parse("icon.test", "EMPTY_ICON"); + assertEquals("icon.test", value.getId()); + Icon icon = value.get(values); + assertEquals(new EmptyIcon(16, 16), icon); + } + + @Test + public void testParseEmptyIconWithSize() throws ParseException { + IconValue value = IconValue.parse("icon.test", "EMPTY_ICON[size(12,15)]"); + assertEquals("icon.test", value.getId()); + Icon icon = value.get(values); + assertEquals(new EmptyIcon(12, 15), icon); + } + + @Test + public void testGetSerializationStringWithEmptyIcon() { + IconValue value = new IconValue("icon.test", new EmptyIcon(16, 16)); + assertEquals("icon.test = EMPTY_ICON", value.getSerializationString()); + } + + @Test + public void testGetSerializationStringWithEmptyCustomSizeIcon() { + IconValue value = new IconValue("icon.test", new EmptyIcon(22, 13)); + assertEquals("icon.test = EMPTY_ICON[size(22,13)]", value.getSerializationString()); + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeEventTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeEventTest.java new file mode 100644 index 0000000000..9c83c32d68 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeEventTest.java @@ -0,0 +1,127 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.awt.Color; +import java.awt.Font; + +import javax.swing.Icon; + +import org.junit.Before; +import org.junit.Test; + +import resources.ResourceManager; + +public class ThemeEventTest { + private static Font FONT1 = new Font("Dialog", 12, Font.PLAIN); + private static Font FONT2 = new Font("Dialog", 14, Font.PLAIN); + private static Icon ICON1 = ResourceManager.loadImage("images/flag.png"); + private static Icon ICON2 = ResourceManager.loadImage("images/exec.png"); + + private GThemeValueMap values; + + @Before + public void setup() { + values = new GThemeValueMap(); + } + + @Test + public void testIsColorChangedDirect() { + ColorValue value = new ColorValue("color.value", Color.RED); + values.addColor(value); + ColorValue newValue = new ColorValue("color.value", Color.BLUE); + values.addColor(value); + + ColorChangedThemeEvent event = new ColorChangedThemeEvent(values, newValue); + assertTrue(event.isColorChanged("color.value")); + assertFalse(event.isColorChanged("color.othervalue")); + } + + @Test + public void testIsColorChangedIndirect() { + ColorValue parent = new ColorValue("color.parent", Color.RED); + values.addColor(parent); + ColorValue value = new ColorValue("color.value", "color.parent"); + values.addColor(value); + + ColorValue newValue = new ColorValue("color.parent", Color.BLUE); + values.addColor(value); + + ColorChangedThemeEvent event = new ColorChangedThemeEvent(values, newValue); + assertTrue(event.isColorChanged("color.parent")); + assertTrue(event.isColorChanged("color.value")); + assertFalse(event.isColorChanged("color.othervalue")); + } + + @Test + public void testIsFontChangedDirect() { + FontValue value = new FontValue("font.value", FONT1); + values.addFont(value); + FontValue newValue = new FontValue("font.value", FONT2); + values.addFont(value); + + FontChangedThemeEvent event = new FontChangedThemeEvent(values, newValue); + assertTrue(event.isFontChanged("font.value")); + assertFalse(event.isFontChanged("font.othervalue")); + } + + @Test + public void testIsFontChangedIndirect() { + FontValue parent = new FontValue("font.parent", FONT1); + values.addFont(parent); + FontValue value = new FontValue("font.value", "font.parent"); + values.addFont(value); + + FontValue newValue = new FontValue("font.parent", FONT2); + values.addFont(value); + + FontChangedThemeEvent event = new FontChangedThemeEvent(values, newValue); + assertTrue(event.isFontChanged("font.parent")); + assertTrue(event.isFontChanged("font.value")); + assertFalse(event.isFontChanged("font.othervalue")); + } + + @Test + public void testIsIconChangedDirect() { + IconValue value = new IconValue("ICON.value", ICON1); + values.addIcon(value); + IconValue newValue = new IconValue("icon.value", ICON2); + values.addIcon(value); + + IconChangedThemeEvent event = new IconChangedThemeEvent(values, newValue); + assertTrue(event.isIconChanged("icon.value")); + assertFalse(event.isIconChanged("icon.othervalue")); + } + + @Test + public void testIsIconChangedIndirect() { + IconValue parent = new IconValue("icon.parent", ICON1); + values.addIcon(parent); + IconValue value = new IconValue("icon.value", "icon.parent"); + values.addIcon(value); + + IconValue newValue = new IconValue("icon.parent", ICON2); + values.addIcon(value); + + IconChangedThemeEvent event = new IconChangedThemeEvent(values, newValue); + assertTrue(event.isIconChanged("icon.parent")); + assertTrue(event.isIconChanged("icon.value")); + assertFalse(event.isIconChanged("icon.othervalue")); + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeManagerTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeManagerTest.java new file mode 100644 index 0000000000..ec6ba59828 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeManagerTest.java @@ -0,0 +1,377 @@ +/* ### + * 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 generic.theme; + +import static ghidra.util.WebColors.*; +import static org.junit.Assert.*; + +import java.awt.Color; +import java.awt.Font; +import java.net.URL; +import java.util.*; + +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.plaf.UIResource; + +import org.junit.Before; +import org.junit.Test; + +import generic.theme.builtin.*; +import resources.ResourceManager; +import resources.icons.UrlImageIcon; + +public class ThemeManagerTest { + + private Font FONT = new Font("Dialog", Font.PLAIN, 13); + private Font SMALL_FONT = new Font("Dialog", Font.PLAIN, 4); + + private Icon ICON1 = ResourceManager.loadImage("images/exec.png"); + private Icon ICON2 = ResourceManager.loadImage("images/flag.png"); + + private GThemeValueMap defaultValues = new GThemeValueMap(); + private GThemeValueMap darkDefaultValues = new GThemeValueMap(); + private Set themes; + private GTheme METAL_THEME = new MetalTheme(); + private GTheme NIMBUS_THEME = new NimbusTheme(); + private GTheme WINDOWS_THEME = new WindowsTheme(); + private GTheme MAC_THEME = new MacTheme(); + private ThemeManager themeManager; + + @Before + public void setUp() { + + themes = new HashSet<>(); + themes.add(METAL_THEME); + themes.add(NIMBUS_THEME); + themes.add(WINDOWS_THEME); + themes.add(MAC_THEME); + + defaultValues.addColor(new ColorValue("color.test.bg", WHITE)); + defaultValues.addColor(new ColorValue("color.test.fg", RED)); + + defaultValues.addFont(new FontValue("font.test.foo", FONT)); + defaultValues.addIcon(new IconValue("icon.test.foo", ICON1)); + + darkDefaultValues.addColor(new ColorValue("color.test.bg", BLACK)); + darkDefaultValues.addColor(new ColorValue("color.test.fg", BLUE)); + themeManager = new DummyApplicationThemeManager(); + + } + + @Test + public void testDarkThemeColorOverride() { + GColor gColor = new GColor("color.test.bg"); + + assertColor(WHITE, gColor); + themeManager.setTheme(new GTheme("Test", LafType.FLAT_DARK, true)); + assertEquals(BLACK, gColor); + + themeManager.setTheme(new GTheme("Test2")); + assertEquals(WHITE, gColor); + } + + @Test + public void testThemeColorOverride() { + GColor gColor = new GColor("color.test.bg"); + + GTheme theme = new GTheme("Test"); + theme.setColor("color.test.bg", GREEN); + + assertColor(WHITE, gColor); + themeManager.setTheme(theme); + assertEquals(GREEN, gColor); + + themeManager.setTheme(new GTheme("Test2")); + assertEquals(WHITE, gColor); + } + + @Test + public void testThemeFontOverride() { + assertEquals(FONT, themeManager.getFont("font.test.foo")); + + GTheme theme = new GTheme("Test"); + theme.setFont("font.test.foo", SMALL_FONT); + themeManager.setTheme(theme); + + assertEquals(SMALL_FONT, themeManager.getFont("font.test.foo")); + + themeManager.setTheme(new GTheme("Test2")); + assertEquals(FONT, themeManager.getFont("font.test.foo")); + } + + @Test + public void testThemeIconOverride() { + GIcon gIcon = new GIcon("icon.test.foo"); + + GTheme theme = new GTheme("Test"); + theme.setIcon("icon.test.foo", ICON2); + + assertIcon(ICON1, gIcon); + themeManager.setTheme(theme); + assertIcon(ICON2, gIcon); + + themeManager.setTheme(new GTheme("Test2")); + assertIcon(ICON1, gIcon); + } + + @Test + public void testReloadGhidraDefaults() { + GColor gColor = new GColor("color.test.bg"); + assertColor(WHITE, gColor); + + defaultValues.addColor(new ColorValue("color.test.bg", YELLOW)); + themeManager.reloadApplicationDefaults(); + assertEquals(YELLOW, gColor); + } + + @Test + public void testRestoreThemeValues() { + GColor gColor = new GColor("color.test.bg"); + assertColor(WHITE, gColor); + + themeManager.setColor("color.test.bg", PURPLE); + assertColor(PURPLE, gColor); + + themeManager.restoreThemeValues(); + assertEquals(WHITE, gColor); + + } + + @Test + public void testGetAllThemes() { + assertEquals(themes, themeManager.getAllThemes()); + } + + @Test + public void testAddTheme() { + GTheme newTheme = new GTheme("Test"); + + Set allThemes = themeManager.getAllThemes(); + assertEquals(themes.size(), allThemes.size()); + assertFalse(allThemes.contains(newTheme)); + + themeManager.addTheme(newTheme); + allThemes = themeManager.getAllThemes(); + assertTrue(allThemes.contains(newTheme)); + } + + @Test + public void testDeleteTheme() { + GTheme newTheme = new GTheme("Test"); + Set allThemes = themeManager.getAllThemes(); + assertFalse(allThemes.contains(newTheme)); + + themeManager.addTheme(newTheme); + allThemes = themeManager.getAllThemes(); + assertTrue(allThemes.contains(newTheme)); + + themeManager.deleteTheme(newTheme); + allThemes = themeManager.getAllThemes(); + assertFalse(allThemes.contains(newTheme)); + } + + @Test + public void testGetSupportedThemes() { + Set supportedThemes = themeManager.getSupportedThemes(); + // since we put mac specific and windows specific themes, they can't all be here + // regardless of the current platform + assertTrue(supportedThemes.size() < themes.size()); + for (GTheme gTheme : supportedThemes) { + assertTrue(gTheme.hasSupportedLookAndFeel()); + } + } + + @Test + public void testGetLookAndFeelType() { + LafType lookAndFeelType = themeManager.getLookAndFeelType(); + // in the test setup, we defaulted to the MetalLookAndFeel + assertEquals(LafType.METAL, lookAndFeelType); + } + + @Test + public void testGetActiveTheme() { + GTheme activeTheme = themeManager.getActiveTheme(); + assertEquals(METAL_THEME, activeTheme); + } + + @Test + public void testGetThemeByName() { + GTheme theme = themeManager.getTheme("Nimbus Theme"); + assertEquals(NIMBUS_THEME, theme); + } + + @Test + public void testGetAllValues() { + GThemeValueMap allValues = themeManager.getCurrentValues(); + assertEquals(WHITE, allValues.getColor("color.test.bg").getRawValue()); + + themeManager.setColor("color.test.bg", PURPLE); + + allValues = themeManager.getCurrentValues(); + assertEquals(PURPLE, allValues.getColor("color.test.bg").getRawValue()); + + } + + @Test + public void testGetNonDefaultValues() { + // should be empty if we haven't changed any themeValues + GThemeValueMap nonDefaultValues = themeManager.getNonDefaultValues(); + assertTrue(nonDefaultValues.isEmpty()); + + // change some values and see that they show up in the nonDefaultValues + themeManager.setColor("color.test.bg", RED); + themeManager.setFont("font.test.foo", SMALL_FONT); + themeManager.setIcon("icon.test.foo", ICON2); + // also add in a totally new value + themeManager.setColor("color.test.xxx", GREEN); + + nonDefaultValues = themeManager.getNonDefaultValues(); + assertEquals(4, nonDefaultValues.size()); + assertEquals(RED, nonDefaultValues.getColor("color.test.bg").getRawValue()); + assertEquals(GREEN, nonDefaultValues.getColor("color.test.xxx").getRawValue()); + assertEquals(SMALL_FONT, nonDefaultValues.getFont("font.test.foo").getRawValue()); + assertEquals(ICON2, nonDefaultValues.getIcon("icon.test.foo").getRawValue()); + } + + @Test + public void testGetColor() { + assertEquals(WHITE, themeManager.getColor("color.test.bg")); + } + + @Test + public void testGetFont() { + assertEquals(FONT, themeManager.getFont("font.test.foo")); + } + + @Test + public void testGetIcon() { + assertEquals(ICON1, themeManager.getIcon("icon.test.foo")); + } + + @Test + public void testGetColorWithUnresolvedId() { + assertEquals(CYAN, themeManager.getColor("color.badid")); + } + + @Test + public void testGetIconWithUnresolvedId() { + assertEquals(ResourceManager.getDefaultIcon(), themeManager.getIcon("icon.badid")); + } + + @Test + public void testGetFontWithUnresolvedId() { + assertEquals(ThemeManager.DEFAULT_FONT, themeManager.getFont("font.badid")); + } + + @Test + public void testGetGColorUiResource() { + Color color = themeManager.getGColorUiResource("color.test.bg"); + assertTrue(color instanceof UIResource); + + // make sure there is only one instance for an id; + Color color2 = themeManager.getGColorUiResource("color.test.bg"); + assertTrue(color == color2); + } + + @Test + public void testGetGIconUiResource() { + Icon icon = themeManager.getGIconUiResource("icon.test.foo"); + assertTrue(icon instanceof UIResource); + + // make sure there is only one instance for an id; + Icon gIcon2 = themeManager.getGIconUiResource("icon.test.foo"); + assertTrue(icon == gIcon2); + } + + @Test + public void testGetApplicationLightDefaults() { + assertEquals(defaultValues, themeManager.getApplicationLightDefaults()); + } + + @Test + public void testGetApplicationDarkDefaults() { + // dark defaults are a combination of standard defaults overlayed with dark defaults + GThemeValueMap expected = new GThemeValueMap(); + expected.load(defaultValues); + expected.load(darkDefaultValues); + assertEquals(expected, themeManager.getApplicationDarkDefaults()); + } + + @Test + public void testRegisterFont() { + themeManager.setFont(new FontValue("font.test", SMALL_FONT)); + JLabel label = new JLabel("Test"); + assertNotEquals(SMALL_FONT, label.getFont()); + themeManager.registerFont(label, "font.test"); + assertEquals(SMALL_FONT, label.getFont()); + themeManager.setFont(new FontValue("font.test", FONT)); + assertEquals(FONT, label.getFont()); + } + + private void assertColor(Color color, GColor gColor) { + if (color.getRGB() != gColor.getRGB()) { + fail("RGB values don't match! Expected " + color + " but got " + gColor); + } + } + + private void assertIcon(Icon icon, GIcon gIcon) { + URL url = ((UrlImageIcon) icon).getUrl(); + URL gUrl = gIcon.getUrl(); + if (!url.equals(gUrl)) { + fail("Icons don't match. Expected " + url + ", but got " + gUrl); + } + } + + // ApplicationThemeManager that doesn't read in theme.properties files or preferences + class DummyApplicationThemeManager extends ApplicationThemeManager { + DummyApplicationThemeManager() { + themePreferences = new ThemePreferences() { + @Override + public GTheme load() { + return new MetalTheme(); + } + + @Override + public void save(GTheme theme) { + // do nothing + } + }; + themeFileLoader = new ThemeFileLoader() { + @Override + public void loadThemeDefaultFiles() { + // do nothing + } + + @Override + public Collection loadThemeFiles() { + return new HashSet<>(themes); + } + + @Override + public GThemeValueMap getDefaults() { + return defaultValues; + } + + @Override + public GThemeValueMap getDarkDefaults() { + return darkDefaultValues; + } + }; + doInitialize(); + } + } +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemePropertyFileReaderTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemePropertyFileReaderTest.java new file mode 100644 index 0000000000..c30ea39c52 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemePropertyFileReaderTest.java @@ -0,0 +1,216 @@ +/* ### + * 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 generic.theme; + +import static ghidra.util.WebColors.*; +import static org.junit.Assert.*; + +import java.awt.Color; +import java.awt.Font; +import java.io.IOException; +import java.io.StringReader; +import java.util.List; + +import javax.swing.Icon; + +import org.junit.Test; + +import resources.MultiIcon; +import resources.ResourceManager; + +public class ThemePropertyFileReaderTest { + + @Test + public void testDefaults() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Defaults]", + " color.b.1 = white", // WHITE + " color.b.2 = #ff0000", // RED + " color.b.3 = 0x008000", // GREEN + " color.b.4 = 0xff000080", // half alpha red + " color.b.5 = rgb(0,0,255)", // BLUE + " color.b.6 = rgba(255,0,0,0.5)", // half alpha red + " color.b.7 = color.b.1", // ref + " font.a.8 = dialog-PLAIN-14", + " font.a.9 = font.a.8", + " font.a.b = (font.a.8[20][BOLD])", + " icon.a.10 = core.png", + " icon.a.11 = icon.a.10", + " icon.a.12 = icon.a.10[size(17,21)]", + " icon.a.13 = core.png[size(17,21)]", + " icon.a.14 = icon.a.10{core.png[size(4,4)][move(8, 8)]}", + ""))); + //@formatter:on + + Color halfAlphaRed = new Color(0x80ff0000, true); + GThemeValueMap values = reader.getDefaultValues(); + assertEquals(15, values.size()); + + assertEquals(WHITE, getColor(values, "color.b.1")); + assertEquals(RED, getColor(values, "color.b.2")); + assertEquals(GREEN, getColor(values, "color.b.3")); + assertEquals(halfAlphaRed, getColor(values, "color.b.4")); + assertEquals(BLUE, getColor(values, "color.b.5")); + assertEquals(halfAlphaRed, getColor(values, "color.b.6")); + assertEquals(WHITE, getColor(values, "color.b.7")); + + assertEquals(new Font("dialog", Font.PLAIN, 14), getFont(values, "font.a.8")); + assertEquals(new Font("dialog", Font.PLAIN, 14), getFont(values, "font.a.9")); + assertEquals(new Font("dialog", Font.BOLD, 20), getFont(values, "font.a.b")); + + assertEquals(ResourceManager.loadImage("core.png"), getIcon(values, "icon.a.10")); + assertEquals(ResourceManager.loadImage("core.png"), getIcon(values, "icon.a.11")); + Icon icon = getIcon(values, "icon.a.12"); + assertEquals(17, icon.getIconWidth()); + assertEquals(21, icon.getIconHeight()); + + icon = getIcon(values, "icon.a.13"); + assertEquals(17, icon.getIconWidth()); + assertEquals(21, icon.getIconHeight()); + + icon = getIcon(values, "icon.a.14"); + assertTrue(icon instanceof MultiIcon); + + } + + @Test + public void testDarkDefaults() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Dark Defaults]", + " color.b.1 = white", // WHITE + " color.b.2 = #ff0000", // RED + " color.b.3 = 0x008000", // GREEN + " color.b.4 = 0xff000080", // half alpha red + " color.b.5 = rgb(0,0,255)", // BLUE + " color.b.6 = rgba(255,0,0,0.5)", // half alpha red + " color.b.7 = color.b.1", // ref + ""))); + //@formatter:on + + Color halfAlphaRed = new Color(0x80ff0000, true); + GThemeValueMap values = reader.getDarkDefaultValues(); + assertEquals(7, values.size()); + + assertEquals(WHITE, getColor(values, "color.b.1")); + assertEquals(RED, getColor(values, "color.b.2")); + assertEquals(GREEN, getColor(values, "color.b.3")); + assertEquals(halfAlphaRed, getColor(values, "color.b.4")); + assertEquals(BLUE, getColor(values, "color.b.5")); + assertEquals(halfAlphaRed, getColor(values, "color.b.6")); + assertEquals(WHITE, getColor(values, "color.b.7")); + } + + @Test + public void testBothDefaultsAndDarkDefaultsInSameFile() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Defaults]", + " color.b.1 = white", // WHITE + " color.b.2 = #ff0000", // RED + "[Dark Defaults]", + " color.b.1 = black", // BLACK + " color.b.2 = #0000ff", // BLUE + ""))); + //@formatter:on + + GThemeValueMap values = reader.getDefaultValues(); + assertEquals(2, values.size()); + + GThemeValueMap darkValues = reader.getDarkDefaultValues(); + assertEquals(2, values.size()); + + assertEquals(WHITE, getColor(values, "color.b.1")); + assertEquals(RED, getColor(values, "color.b.2")); + assertEquals(BLACK, getColor(darkValues, "color.b.1")); + assertEquals(BLUE, getColor(darkValues, "color.b.2")); + } + + @Test + public void testParseColorError() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Defaults]", + " color.b.1 = white", // WHITE + " color.b.2 = sdfsdf", // RED + ""))); + //@formatter:on + List errors = reader.getErrors(); + assertEquals(1, errors.size()); + assertEquals( + "Error parsing theme file \"test\" at line: 3, Could not parse Color value: sdfsdf", + errors.get(0)); + } + + @Test + public void testParseFontError() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Defaults]", + " font.b.1 = Dialog-PLAIN-14", + " font.b.2 = Dialog-PLANE-13", + " font.b.3 = Dialog-BOLD-ITALIC", + ""))); + //@formatter:on + List errors = reader.getErrors(); + assertEquals(2, errors.size()); + + } + + @Test + public void testParseFontModiferError() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Defaults]", + " font.b.1 = Dialog-PLAIN-14", + " font.b.2 = (font.b.1[)", + ""))); + //@formatter:on + List errors = reader.getErrors(); + assertEquals(1, errors.size()); + + } + + @Test + public void testIconNoRightHandValueError() throws IOException { + //@formatter:off + ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n", + "[Defaults]", + " icon.b.1 = core.png", + " icon.b.2 = ", + ""))); + //@formatter:on + List errors = reader.getErrors(); + assertEquals(1, errors.size()); + + } + + private Color getColor(GThemeValueMap values, String id) { + ColorValue color = values.getColor(id); + return color.get(values); + } + + private Font getFont(GThemeValueMap values, String id) { + FontValue font = values.getFont(id); + return font.get(values); + } + + private Icon getIcon(GThemeValueMap values, String id) { + IconValue icon = values.getIcon(id); + return icon.get(values); + } +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeValueUtilsTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeValueUtilsTest.java new file mode 100644 index 0000000000..0f147ccb3c --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/ThemeValueUtilsTest.java @@ -0,0 +1,60 @@ +/* ### + * 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 generic.theme; + +import static org.junit.Assert.*; + +import java.text.ParseException; +import java.util.List; + +import org.junit.Test; + +public class ThemeValueUtilsTest { + @Test + public void testParseGroupings() throws ParseException { + String source = "(ab (cd))(ef)(( gh))"; + List results = ThemeValueUtils.parseGroupings(source, '(', ')'); + assertEquals(3, results.size()); + assertEquals("ab (cd)", results.get(0)); + assertEquals("ef", results.get(1)); + assertEquals("( gh)", results.get(2)); + } + + @Test + public void testParseGroupingsParseError() { + String source = "(ab (cd))(ef)( gh))"; + try { + ThemeValueUtils.parseGroupings(source, '(', ')'); + fail("Expected parse Exception"); + } + catch (ParseException e) { + //expected + } + } + + @Test + public void testParseGroupingsParseError2() { + String source = " xx"; + try { + ThemeValueUtils.parseGroupings(source, '(', ')'); + fail("Expected parse Exception"); + } + catch (ParseException e) { + // expected + } + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/generic/theme/laf/ThemeGrouperTest.java b/Ghidra/Framework/Generic/src/test/java/generic/theme/laf/ThemeGrouperTest.java new file mode 100644 index 0000000000..6dfe6f4e23 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/generic/theme/laf/ThemeGrouperTest.java @@ -0,0 +1,104 @@ +/* ### + * 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 generic.theme.laf; + +import static ghidra.util.WebColors.*; +import static org.junit.Assert.*; + +import java.awt.Color; +import java.awt.Font; + +import org.junit.Before; +import org.junit.Test; + +import generic.theme.*; + +public class ThemeGrouperTest { + private static Font FONT1 = new Font("Dialog", Font.PLAIN, 12); + private static Font FONT2 = new Font("Dialog", Font.BOLD, 16); + + private ThemeGrouper grouper; + private GThemeValueMap values; + + @Before + public void setUp() { + grouper = new ThemeGrouper(); + values = new GThemeValueMap(); + } + + @Test + public void testGroupColorUsingPreferredSources() { + initColor("control", RED); + initColor("menu", RED); + initColor("Menu.background", RED); + grouper.group(values); + + ColorValue colorValue = values.getColor("Menu.background"); + assertEquals("menu", colorValue.getReferenceId()); + } + + @Test + public void testGroupColorUsingNonPreferredSourceWhenPreferredDoesntMatch() { + initColor("control", RED); + initColor("menu", BLUE); + initColor("Menu.background", RED); + grouper.group(values); + + ColorValue colorValue = values.getColor("Menu.background"); + assertEquals("control", colorValue.getReferenceId()); + } + + @Test + public void testGroupFontUsingPreferredSources() { + initFont("Button.font", FONT1); + initFont("RadioButton.font", FONT1); + initFont("Menu.font", FONT1); + initFont("MenuItem.font", FONT1); + grouper.group(values); + + assertEquals(FONT1, values.getFont("font.button").getRawValue()); + assertEquals(FONT1, values.getFont("font.menu").getRawValue()); + assertEquals("font.button", values.getFont("Button.font").getReferenceId()); + assertEquals("font.button", values.getFont("RadioButton.font").getReferenceId()); + assertEquals("font.menu", values.getFont("Menu.font").getReferenceId()); + assertEquals("font.menu", values.getFont("MenuItem.font").getReferenceId()); + } + + @Test + public void testGroupFontUsingNonPreferredSourceWhenPreferredDoesntMatch() { + initFont("Button.font", FONT1); + initFont("RadioButton.font", FONT1); + initFont("Menu.font", FONT2); + initFont("MenuItem.font", FONT1); + grouper.group(values); + + assertEquals(FONT1, values.getFont("font.button").getRawValue()); + assertEquals(FONT2, values.getFont("font.menu").getRawValue()); + assertEquals("font.button", values.getFont("Button.font").getReferenceId()); + assertEquals("font.button", values.getFont("RadioButton.font").getReferenceId()); + assertEquals("font.menu", values.getFont("Menu.font").getReferenceId()); + assertEquals("font.button", values.getFont("MenuItem.font").getReferenceId()); + } + + private void initColor(String id, Color color) { + values.addColor(new ColorValue(id, color)); + } + + private void initFont(String id, Font font) { + values.addFont(new FontValue(id, font)); + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/ghidra/util/WebColorsTest.java b/Ghidra/Framework/Generic/src/test/java/ghidra/util/WebColorsTest.java index 6968ef9a29..50784cdf8c 100644 --- a/Ghidra/Framework/Generic/src/test/java/ghidra/util/WebColorsTest.java +++ b/Ghidra/Framework/Generic/src/test/java/ghidra/util/WebColorsTest.java @@ -35,31 +35,30 @@ public class WebColorsTest { @Test public void testColorToStringFromColorWithNoDefinedEntry() { - assertEquals("#0123EF", WebColors.toString(new Color(0x01, 0x23, 0xEF))); + assertEquals("#0123ef", WebColors.toString(new Color(0x01, 0x23, 0xef))); } @Test - public void testGetColorFromName() { + public void testGetColor() { assertEquals(WebColors.NAVY, WebColors.getColor("Navy")); - } - - @Test - public void testGetColorFromHexString() { assertEquals(WebColors.NAVY, WebColors.getColor("0x000080")); - } - - @Test - public void testGetColorFromHexString2() { assertEquals(WebColors.NAVY, WebColors.getColor("#000080")); + assertEquals(WebColors.NAVY, WebColors.getColor("rgb(0,0,128)")); + assertEquals(WebColors.NAVY, WebColors.getColor("rgba(0,0,128,1.0)")); + assertEquals(WebColors.NAVY, WebColors.getColor("rgba(0,0,128, 255)")); + + assertEquals(new Color(0x123456), WebColors.getColor("0x123456")); + assertEquals(new Color(0x80102030, true), WebColors.getColor("rgba(16, 32, 48, 0.5)")); + + assertNull(WebColors.getColor("asdfasdfas")); } @Test - public void testGetColorWithNoDefinedValue() { - assertEquals(new Color(0x12, 0x34, 0x56), WebColors.getColor("0x123456")); - } - - @Test - public void testGetColorByBadName() { - assertNull(WebColors.getColor("ABCDEFG")); + public void testColorWithAlphaRoundTrip() { + Color c = new Color(0x44112233, true); + assertEquals(0x44, c.getAlpha()); + String string = WebColors.toString(c, false); + Color parsed = WebColors.getColor(string); + assertEquals(c, parsed); } } diff --git a/Ghidra/Framework/Generic/src/test/java/ghidra/util/datastruct/WeakStoreTest.java b/Ghidra/Framework/Generic/src/test/java/ghidra/util/datastruct/WeakStoreTest.java new file mode 100644 index 0000000000..aed0ca4694 --- /dev/null +++ b/Ghidra/Framework/Generic/src/test/java/ghidra/util/datastruct/WeakStoreTest.java @@ -0,0 +1,61 @@ +/* ### + * 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 ghidra.util.datastruct; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +import generic.test.AbstractGenericTest; + +public class WeakStoreTest extends AbstractGenericTest { + @Test + public void testStore() { + WeakStore store = new WeakStore<>(); + store.add(new Foo("AAA")); + store.add(new Foo("BBB")); + store.add(new Foo("CCC")); + + assertEquals(3, store.size()); + + List values = store.getValues(); + + assertEquals("AAA", values.get(0).getName()); + assertEquals("BBB", values.get(1).getName()); + assertEquals("CCC", values.get(2).getName()); + values = null; + + waitFor(() -> { + System.gc(); + return store.size() == 0; + }, "Weak store values were never garbage collected"); + } + + static class Foo { + String name; + + Foo(String name) { + this.name = name; + } + + String getName() { + return name; + } + } + +} diff --git a/Ghidra/Framework/Generic/src/test/java/resources/icons/MultiIconBuilderTest.java b/Ghidra/Framework/Generic/src/test/java/resources/icons/MultiIconBuilderTest.java index 67564899e9..df0df3f998 100644 --- a/Ghidra/Framework/Generic/src/test/java/resources/icons/MultiIconBuilderTest.java +++ b/Ghidra/Framework/Generic/src/test/java/resources/icons/MultiIconBuilderTest.java @@ -23,6 +23,7 @@ import javax.swing.JOptionPane; import org.junit.Test; +import generic.theme.GThemeDefaults.Colors.Palette; import resources.MultiIconBuilder; import resources.QUADRANT; @@ -62,8 +63,8 @@ public class MultiIconBuilderTest { public void showIconText() { for (QUADRANT quad : QUADRANT.values()) { ImageIcon icon = - new MultiIconBuilder(makeQuandrantIcon(32, 32, Color.gray, Color.white)) - .addText("Abcfg", font, Color.red, quad) + new MultiIconBuilder(makeQuandrantIcon(32, 32, Palette.GRAY, Palette.WHITE)) + .addText("Abcfg", font, Palette.RED, quad) .build(); JOptionPane.showMessageDialog(null, "" + quad + " aligned", "Icon text overlay test", JOptionPane.OK_OPTION, icon); @@ -73,8 +74,8 @@ public class MultiIconBuilderTest { //@Test public void showIconOverlay() { for (QUADRANT quad : QUADRANT.values()) { - ImageIcon icon = new MultiIconBuilder(makeEmptyIcon(32, 32, Color.gray)) - .addIcon(makeEmptyIcon(8, 8, Color.red), 8, 8, quad) + ImageIcon icon = new MultiIconBuilder(makeEmptyIcon(32, 32, Palette.GRAY)) + .addIcon(makeEmptyIcon(8, 8, Palette.RED), 8, 8, quad) .build(); JOptionPane.showMessageDialog(null, "" + quad + " aligned", "Icon_icon overlay test", JOptionPane.OK_OPTION, icon); @@ -84,8 +85,8 @@ public class MultiIconBuilderTest { //@Test public void showScaledIconOverlay() { for (QUADRANT quad : QUADRANT.values()) { - ImageIcon icon = new MultiIconBuilder(makeEmptyIcon(32, 32, Color.gray)) - .addIcon(makeQuandrantIcon(32, 32, Color.red, Color.black), 14, 14, quad) + ImageIcon icon = new MultiIconBuilder(makeEmptyIcon(32, 32, Palette.GRAY)) + .addIcon(makeQuandrantIcon(32, 32, Palette.RED, Palette.BLACK), 14, 14, quad) .build(); JOptionPane.showMessageDialog(null, "" + quad + " aligned", "Scaled icon_icon overlay test", @@ -97,8 +98,8 @@ public class MultiIconBuilderTest { public void testIconOverlay() { // doesn't verify anything other than it doesn't fall down go boom for (QUADRANT quad : QUADRANT.values()) { - ImageIcon icon = new MultiIconBuilder(makeEmptyIcon(32, 32, Color.gray)) - .addIcon(makeQuandrantIcon(32, 32, Color.red, Color.black), 14, 14, quad) + ImageIcon icon = new MultiIconBuilder(makeEmptyIcon(32, 32, Palette.GRAY)) + .addIcon(makeQuandrantIcon(32, 32, Palette.RED, Palette.BLACK), 14, 14, quad) .build(); icon.getDescription(); } @@ -109,8 +110,8 @@ public class MultiIconBuilderTest { // doesn't verify anything other than it doesn't fall down go boom for (QUADRANT quad : QUADRANT.values()) { ImageIcon icon = - new MultiIconBuilder(makeQuandrantIcon(32, 32, Color.gray, Color.white)) - .addText("Abcfg", font, Color.red, quad) + new MultiIconBuilder(makeQuandrantIcon(32, 32, Palette.GRAY, Palette.WHITE)) + .addText("Abcfg", font, Palette.RED, quad) .build(); icon.getDescription(); } diff --git a/Ghidra/Framework/Graph/certification.manifest b/Ghidra/Framework/Graph/certification.manifest index b693379ab1..dcf8979d70 100644 --- a/Ghidra/Framework/Graph/certification.manifest +++ b/Ghidra/Framework/Graph/certification.manifest @@ -5,6 +5,7 @@ ##MODULE IP: Oxygen Icons - LGPL 3.0 Module.manifest||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| +data/graph.theme.properties||GHIDRA||||END| src/main/docs/README.txt||GHIDRA||||END| src/main/docs/VerticesAndEdges.png||GHIDRA||||END| src/main/docs/VerticesAndEdges.xml||GHIDRA||||END| diff --git a/Ghidra/Framework/Graph/data/graph.theme.properties b/Ghidra/Framework/Graph/data/graph.theme.properties new file mode 100644 index 0000000000..a7c99e2955 --- /dev/null +++ b/Ghidra/Framework/Graph/data/graph.theme.properties @@ -0,0 +1,66 @@ +[Defaults] + +# visual graph +color.bg.visualgraph = color.bg +color.bg.visualgraph.satellite = lightgray +color.bg.highlight.visualgraph = rgba(255,255,0,155) // somewhat transparent yellow +color.bg.visualgraph.message = rgb(138, 185, 241) // jordy blue + +color.bg.visualgraph.drop.shadow.dark = black +color.bg.visualgraph.drop.shadow.light = gray + +color.bg.visualgraph.satellite.vertex = #018786 +color.fg.visualgraph.message = color.palette.black + +color.bg.visualgraph.dockingvertex = #03DAC6 +color.fg.visualgraph.dockingvertex = black +color.visualgraph.dockingvertex.cursor = red + +color.visualgraph.view.primary.edge.draw = color.palette.green // draw and emphasized +color.visualgraph.view.primary.edge.focused = color.palette.green // when an edge is in a focused path +color.visualgraph.view.primary.edge.selected = color.palette.lime // when an edge is selected +color.visualgraph.view.primary.edge.hovered = color.palette.lime // dashed lines; when an edge is in the hovered path +color.visualgraph.view.satellite.edge.draw = color.palette.green +color.visualgraph.view.satellite.edge.focused = color.palette.green +color.visualgraph.view.satellite.edge.selected = color.palette.lime +color.visualgraph.view.satellite.edge.hovered = color.palette.lime + + + +# graph display +color.graphdisplay.vertex.default = green +color.graphdisplay.edge.default = green +color.graphdisplay.vertex.selected = blue +color.graphdisplay.edge.selected = blue + +icon.graph.satellite = network-wireless-16.png +icon.graph.satellite.large = network-wireless.png +icon.graph.layout.default = color_swatch.png + +font.graphdisplay.default = dialog-bold-18 +font.graph.component.message = SansSerif-BOLDITALIC-18 + +[Dark Defaults] + +color.bg.highlight.visualgraph = rgba(120,120,120,155) // light gray with dark bg = dark gray +color.bg.visualgraph.message = rgb(65, 146, 242) // dark blue close to jordy blue +color.fg.visualgraph.message = color.palette.lightgray + +color.bg.visualgraph.drop.shadow.dark = black +color.bg.visualgraph.drop.shadow.light = gray + +color.bg.visualgraph.satellite.vertex = #018786 + +color.bg.visualgraph.dockingvertex = #018786 +color.fg.visualgraph.dockingvertex = black // unchanged +color.visualgraph.dockingvertex.cursor = pink // arbitrary + +color.visualgraph.view.primary.edge.draw = #75CCB9 // color.palette.green // draw and emphasized +color.visualgraph.view.primary.edge.focused = #75CCB9 // color.palette.green // when an edge is in a focused path +color.visualgraph.view.primary.edge.selected = #BBFFCC // when an edge is selected +color.visualgraph.view.primary.edge.hovered = #BBFFCC // dashed lines; when an edge is in the hovered path +color.visualgraph.view.satellite.edge.draw = #75CCB9 +color.visualgraph.view.satellite.edge.focused = #75CCB9 +color.visualgraph.view.satellite.edge.selected = #BBFFCC +color.visualgraph.view.satellite.edge.hovered = #BBFFCC + diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/featurette/VgSatelliteFeaturette.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/featurette/VgSatelliteFeaturette.java index 8b404bb0f9..8ad2748914 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/featurette/VgSatelliteFeaturette.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/featurette/VgSatelliteFeaturette.java @@ -24,13 +24,13 @@ import javax.swing.JComponent; import docking.*; import docking.action.MenuData; import docking.action.ToggleDockingAction; +import generic.theme.GIcon; import ghidra.framework.options.SaveState; import ghidra.graph.VisualGraph; import ghidra.graph.VisualGraphComponentProvider; import ghidra.graph.viewer.*; import ghidra.graph.viewer.actions.*; import ghidra.util.HelpLocation; -import resources.ResourceManager; /** * A sub-feature that provides a satellite viewer to {@link VisualGraphComponentProvider}s @@ -52,7 +52,7 @@ public class VgSatelliteFeaturette { //@formatter:on - private static final Icon ICON = ResourceManager.loadImage("images/network-wireless-16.png"); + private static final Icon ICON = new GIcon("icon.graph.satellite"); private static final String DISPLAY_SATELLITE = "DISPLAY_SATELLITE"; private static final String DOCK_SATELLITE = "DOCK_SATELLITE"; diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/GraphComponent.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/GraphComponent.java index 39e307c99f..17035b15a3 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/GraphComponent.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/GraphComponent.java @@ -39,8 +39,13 @@ import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer; import edu.uci.ics.jung.visualization.decorators.ToStringLabeller; import edu.uci.ics.jung.visualization.picking.PickedState; import edu.uci.ics.jung.visualization.picking.ShapePickSupport; +import edu.uci.ics.jung.visualization.renderers.BasicEdgeRenderer; import edu.uci.ics.jung.visualization.renderers.Renderer; +import edu.uci.ics.jung.visualization.renderers.Renderer.Vertex; import edu.uci.ics.jung.visualization.util.Caching; +import generic.theme.*; +import generic.theme.GThemeDefaults.Colors; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.VisualGraph; import ghidra.graph.event.VisualGraphChangeListener; import ghidra.graph.viewer.edge.*; @@ -59,7 +64,6 @@ import ghidra.util.HelpLocation; import ghidra.util.exception.AssertException; import help.HelpService; import resources.Icons; -import resources.ResourceManager; import util.CollectionUtils; /** @@ -91,6 +95,7 @@ public class GraphComponent, G e private static final Integer SATELLITE_PROVIDER_BUTTON_LAYER = Integer.valueOf(199); private static final Integer SATELLITE_VIEWER_LAYER = Integer.valueOf(200); private static final Integer STALE_GRAPH_VIEW_LAYER = Integer.valueOf(300); + private static final Icon LARGE_SATELLITE_ICON = new GIcon("icon.graph.satellite.large"); private JPanel staleGraphViewPanel; private MessagePaintable messagePaintable = new MessagePaintable(); @@ -193,21 +198,6 @@ public class GraphComponent, G e GraphViewer viewer = new GraphViewer<>(layout, viewerSize); - Renderer renderer = viewer.getRenderer(); - renderer.setVertexRenderer(new VisualVertexRenderer<>()); - - RenderContext renderContext = viewer.getRenderContext(); - - Color normal = Color.GREEN.darker().darker(); - Color selected = Color.GREEN; - renderContext.setEdgeDrawPaintTransformer(e -> e.isSelected() ? selected : normal); - renderContext.setArrowDrawPaintTransformer(e -> e.isSelected() ? selected : normal); - renderContext.setArrowFillPaintTransformer(e -> e.isSelected() ? selected : normal); - - PickedState pickedVertexState = viewer.getPickedVertexState(); - renderContext.setVertexFillPaintTransformer( - new PickableVertexPaintTransformer<>(pickedVertexState, Color.WHITE, Color.YELLOW)); - viewer.setGraphOptions(vgOptions); return viewer; @@ -258,10 +248,38 @@ public class GraphComponent, G e protected void decoratePrimaryViewer(GraphViewer viewer, VisualGraphLayout layout) { Renderer renderer = viewer.getRenderer(); - renderer.setEdgeRenderer(layout.getEdgeRenderer()); + BasicEdgeRenderer edgeRenderer = layout.getEdgeRenderer(); + renderer.setEdgeRenderer(edgeRenderer); RenderContext renderContext = viewer.getRenderContext(); + GColor drawColor = new GColor("color.visualgraph.view.primary.edge.draw"); + GColor focusedColor = new GColor("color.visualgraph.view.primary.edge.focused"); + GColor selectedColor = new GColor("color.visualgraph.view.primary.edge.selected"); + GColor hoveredColor = new GColor("color.visualgraph.view.primary.edge.hovered"); + if (edgeRenderer instanceof VisualEdgeRenderer) { + VisualEdgeRenderer visualEdgeRenderer = + (VisualEdgeRenderer) renderer.getEdgeRenderer(); + visualEdgeRenderer.setDrawColorTransformer(e -> drawColor); + visualEdgeRenderer.setFocusedColorTransformer(e -> focusedColor); + visualEdgeRenderer.setSelectedColorTransformer(e -> selectedColor); + visualEdgeRenderer.setHoveredColorTransformer(e -> hoveredColor); + + } + else { + Function edgeColorTransformer = + e -> e.isSelected() ? selectedColor : drawColor; + renderContext.setEdgeDrawPaintTransformer(edgeColorTransformer); + renderContext.setArrowDrawPaintTransformer(edgeColorTransformer); + renderContext.setArrowFillPaintTransformer(edgeColorTransformer); + } + + VisualVertexRenderer vertexRenderer = new VisualVertexRenderer<>(); + renderer.setVertexRenderer(vertexRenderer); + PickedState pickedVertexState = viewer.getPickedVertexState(); + vertexRenderer.setVertexFillPaintTransformer( + new PickableVertexPaintTransformer<>(pickedVertexState, Palette.WHITE, Palette.YELLOW)); + // this will paint thicker, but with the shape being used...which can look odd //renderContext.setEdgeFillPaintTransformer(null); PickedState pickedEdgeState = viewer.getPickedEdgeState(); @@ -318,9 +336,26 @@ public class GraphComponent, G e RenderContext renderContext = viewer.getRenderContext(); Renderer renderer = viewer.getRenderer(); - renderer.setVertexRenderer(viewer.getPreferredVertexRenderer()); - renderer.setEdgeRenderer(new VisualGraphEdgeSatelliteRenderer<>( - (VisualEdgeRenderer) layout.getEdgeRenderer())); + Vertex vertexRenderer = viewer.getPreferredVertexRenderer(); + + renderContext + .setVertexFillPaintTransformer( + v -> new GColor("color.bg.visualgraph.satellite.vertex")); + + renderer.setVertexRenderer(vertexRenderer); + VisualGraphEdgeSatelliteRenderer visualEdgeRenderer = + new VisualGraphEdgeSatelliteRenderer<>( + (VisualEdgeRenderer) layout.getEdgeRenderer()); + renderer.setEdgeRenderer(visualEdgeRenderer); + + visualEdgeRenderer.setDrawColorTransformer( + e -> new GColor("color.visualgraph.view.satellite.edge.draw")); + visualEdgeRenderer.setFocusedColorTransformer( + e -> new GColor("color.visualgraph.view.satellite.edge.focused")); + visualEdgeRenderer.setSelectedColorTransformer( + e -> new GColor("color.visualgraph.view.satellite.edge.selected")); + visualEdgeRenderer.setHoveredColorTransformer( + e -> new GColor("color.visualgraph.view.satellite.edge.hovered")); Function edgeTransformer = layout.getEdgeShapeTransformer(); renderContext.setEdgeShapeTransformer(edgeTransformer); @@ -374,7 +409,7 @@ public class GraphComponent, G e mainPanel.add(layeredPane, BorderLayout.CENTER); - satellite.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + satellite.setBorder(BorderFactory.createLineBorder(Colors.Java.BORDER)); undockedSatellitePanel = new JPanel(new BorderLayout()); undockedSatellitePanel.addComponentListener(new ComponentAdapter() { @@ -418,7 +453,7 @@ public class GraphComponent, G e private EmptyBorderButton buildShowUndockedProviderButton() { String tooltip = "Bring satellite view to the front"; - Icon icon = ResourceManager.loadImage("images/network-wireless.png"); + Icon icon = LARGE_SATELLITE_ICON; JLabel iconLabel = new GIconLabel(icon); iconLabel.setOpaque(false); iconLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); @@ -966,7 +1001,8 @@ public class GraphComponent, G e private class MessagePaintable implements Paintable { - private final Color backgroundColor = new Color(134, 180, 238); + private static final String FONT_ID = "font.graph.component.message"; + private final Color backgroundColor = new GColor("color.bg.visualgraph.message"); private String message = null; @Override @@ -981,7 +1017,7 @@ public class GraphComponent, G e // this composite softens the text and color of the message g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SrcOver.getRule(), .60f)); - Font font = new Font("Sanf Serif", Font.BOLD | Font.ITALIC, 18); + Font font = Gui.getFont(FONT_ID); g.setFont(font); Rectangle stringBounds = @@ -1009,14 +1045,11 @@ public class GraphComponent, G e g2.setPaint(bottomToTopGradiant); g2.fillRect(backgroundX, upperY, backgroundWidth, backgroundHeight); - g2.setPaint(Color.BLACK); + g2.setPaint(Palette.BLACK); int textX = startX + (isGraphViewStale() ? staleGraphViewPanel.getBounds().width + 5 : 0); g2.drawString(message, textX, startY); -// ImageIcon icon = ResourceManager.loadImage("images/dragon_head.png"); -// g2.drawImage(icon.getImage(), backgroundX, upperY, null); - g2.setComposite(originalComposite); } diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/SatelliteGraphViewer.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/SatelliteGraphViewer.java index 71f04eb432..d8cc1f7295 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/SatelliteGraphViewer.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/SatelliteGraphViewer.java @@ -37,7 +37,7 @@ public class SatelliteGraphViewer graphViewer; private boolean docked; - private VisualGraphOptions options; + protected VisualGraphOptions options; public SatelliteGraphViewer(GraphViewer master, Dimension preferredSize) { super(master, preferredSize); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualEdgeRenderer.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualEdgeRenderer.java index 3109df70f5..a339a20779 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualEdgeRenderer.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualEdgeRenderer.java @@ -18,6 +18,7 @@ package ghidra.graph.viewer.edge; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; +import java.util.Objects; import javax.swing.JComponent; @@ -34,6 +35,7 @@ import edu.uci.ics.jung.visualization.transform.LensTransformer; import edu.uci.ics.jung.visualization.transform.MutableTransformer; import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator; import edu.uci.ics.jung.visualization.util.VertexShapeFactory; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.VisualGraph; import ghidra.graph.viewer.VisualEdge; import ghidra.graph.viewer.VisualVertex; @@ -75,6 +77,15 @@ import ghidra.graph.viewer.vertex.VisualGraphVertexShapeTransformer; * have to be changed, such as the {@link AbstractVisualGraphLayout}, which needs the centering * offsets to handle vertex clipping. * + *

When painting edges this renderer will paint colors based on the following states: default, + * emphasized, hovered, focused and selected. A focused edge is one that is part of the path + * between focused vertices(such as when the vertex is hovered), whereas a selected edge is one + * that has been selected by the user (see {@link VisualEdge} for details). An edge is + * 'emphasized' when the user mouses over the edge (which is when the edge is hovered, not when the + * vertex is hovered. Each of these states may have a different color that can be changed by + * calling the various setter methods on this renderer. When painting, these colors are used along + * with various different strokes to paint in an overlay fashion. + * * @param the vertex type * @param the edge type */ @@ -88,8 +99,10 @@ public abstract class VisualEdgeRenderer drawColorTransformer = e -> Palette.BLACK; + private Function focusedColorTransformer = e -> Palette.GRAY; + private Function selectedColorTransformer = e -> Palette.GRAY; + private Function hoveredColorTransformer = e -> Palette.LIGHT_GRAY; private VisualEdgeArrowRenderingSupport arrowRenderingSupport = new VisualEdgeArrowRenderingSupport<>(); @@ -106,20 +119,77 @@ public abstract class VisualEdgeRenderer transformer) { + this.drawColorTransformer = Objects.requireNonNull(transformer); } - public Color getBaseColor(Graph g, E e) { - return defaultBaseColor; + /** + * Returns the current draw color. This is also the color used to paint an 'emphasized' edge. + * @param g the graph + * @param e the edge + * @return the color + */ + public Color getDrawColor(Graph g, E e) { + return this.drawColorTransformer.apply(e); } - public void setHighlightColor(Color highlightColor) { - this.defaultHighlightColor = highlightColor; + /** + * Sets the color provider to use when drawing this edge when the edge is focused. + * @param transformer the color provider + */ + public void setFocusedColorTransformer(Function transformer) { + this.focusedColorTransformer = Objects.requireNonNull(transformer); } - public Color getHighlightColor(Graph g, E e) { - return defaultHighlightColor; + /** + * Returns the current color to use when the edge is focused. + * @param g the graph + * @param e the edge + * @return the color + */ + public Color getFocusedColor(Graph g, E e) { + return focusedColorTransformer.apply(e); + } + + /** + * Sets the color provider to use when drawing this edge when the edge is selected. + * @param transformer the color provider + */ + public void setSelectedColorTransformer(Function transformer) { + this.selectedColorTransformer = Objects.requireNonNull(transformer); + } + + /** + * Returns the current color to use when the edge is selected. + * @param g the graph + * @param e the edge + * @return the color + */ + public Color getSelectedColor(Graph g, E e) { + return selectedColorTransformer.apply(e); + } + + /** + * Sets the color provider to use when drawing this edge when the edge is in the hovered path. + * @param transformer the color provider + */ + public void setHoveredColorTransformer(Function transformer) { + this.hoveredColorTransformer = Objects.requireNonNull(transformer); + } + + /** + * Returns the current color to use when the edge is in the hovered path. + * @param g the graph + * @param e the edge + * @return the color + */ + public Color getHoveredColor(Graph g, E e) { + return hoveredColorTransformer.apply(e); } // template method @@ -167,12 +237,13 @@ public abstract class VisualEdgeRenderer rc, Graph graph, E e, float x1, diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/routing/ArticulatedEdgeRouter.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/routing/ArticulatedEdgeRouter.java index 3671dfd0d8..f7d77557a0 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/routing/ArticulatedEdgeRouter.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/routing/ArticulatedEdgeRouter.java @@ -31,6 +31,8 @@ import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.util.Pair; import edu.uci.ics.jung.visualization.VisualizationServer; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.viewer.VisualEdge; import ghidra.graph.viewer.VisualVertex; import ghidra.graph.viewer.renderer.DebugShape; @@ -220,6 +222,7 @@ class ArticulatedEdgeRouter> return createLineEdge(start, end, edge); } + @SuppressWarnings("unchecked") E newEdge = (E) edge.cloneEdge(edge.getStart(), edge.getEnd()); moveArticulationsAroundVertices(intersectingVertices, newEdge, goLeft); @@ -229,7 +232,6 @@ class ArticulatedEdgeRouter> /** * Returns a mapping edges to vertices that touch them. * - * @param viewer the viewer containing the graph * @param edgeCollection the edges to check for occlusion * @return a mapping of occluded edges (a subset of the provided edges) to those vertices that * occlude them. @@ -319,35 +321,34 @@ class ArticulatedEdgeRouter> private Color getRoutingBoxColor(E edge) { if (isTrueEdge(edge)) { - return Color.MAGENTA; + return Palette.MAGENTA; } - return Color.ORANGE; + return Palette.ORANGE; } // // private Color getIntersectingBoxColor(E edge) { // if (isTrueEdge(edge)) { -// return Color.RED; +// return Palette.RED; // } -// return Color.PINK; +// return Palette.PINK; // } private Color getPhantomEdgeColor(E edge, boolean isLeft) { if (isLeft) { if (isTrueEdge(edge)) { - return new Color(0x999900); + return new GColor("color.palette.darkkhaki"); } - return new Color(0x009900); + return Palette.GREEN; } if (isTrueEdge(edge)) { - return new Color(0x3300CC); + return new GColor("color.palette.darkblue"); } - return new Color(0x3399FF); + return new GColor("color.palette.dodgerblue"); } private boolean isTrueEdge(E edge) { return true; - // return edge.getFlowType().isJump(); // a jump is a 'true' edge } } diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/JungPickingGraphMousePlugin.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/JungPickingGraphMousePlugin.java index cf7f3c6206..947b28ac7d 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/JungPickingGraphMousePlugin.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/JungPickingGraphMousePlugin.java @@ -29,6 +29,7 @@ import edu.uci.ics.jung.visualization.VisualizationServer.Paintable; import edu.uci.ics.jung.visualization.VisualizationViewer; import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin; import edu.uci.ics.jung.visualization.picking.PickedState; +import generic.theme.GThemeDefaults.Colors.Palette; /** * PickingGraphMousePlugin supports the picking of graph elements @@ -94,7 +95,7 @@ public class JungPickingGraphMousePlugin extends AbstractGraphMousePlugin /** * color for the picking rectangle */ - protected Color lensColor = Color.cyan; + protected Color lensColor = Palette.CYAN; /** * create an instance with default settings diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/VisualGraphMouseTrackingGraphMousePlugin.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/VisualGraphMouseTrackingGraphMousePlugin.java index 15406fa43f..be37a93487 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/VisualGraphMouseTrackingGraphMousePlugin.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/event/mouse/VisualGraphMouseTrackingGraphMousePlugin.java @@ -25,6 +25,7 @@ import docking.DockingUtils; import edu.uci.ics.jung.visualization.*; import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin; import edu.uci.ics.jung.visualization.transform.MutableTransformer; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.viewer.*; import ghidra.graph.viewer.renderer.*; @@ -92,6 +93,7 @@ public class VisualGraphMouseTrackingGraphMousePlugin { //@formatter:on - private static final Icon DEFAULT_ICON = ResourceManager.loadImage("images/color_swatch.png"); + private static final Icon DEFAULT_ICON = new GIcon("icon.graph.layout.default"); protected abstract Layout createLayout(G g); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/VisualGraphLayout.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/VisualGraphLayout.java index 327061b03f..108392a5b4 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/VisualGraphLayout.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/VisualGraphLayout.java @@ -76,6 +76,7 @@ public interface VisualGraphLayout calculateLocations(VisualGraph graph, TaskMonitor monitor); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/options/VisualGraphOptions.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/options/VisualGraphOptions.java index 5ad0e2c952..8272f256cc 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/options/VisualGraphOptions.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/options/VisualGraphOptions.java @@ -18,6 +18,7 @@ package ghidra.graph.viewer.options; import java.awt.Color; import docking.DockingUtils; +import generic.theme.GColor; import ghidra.framework.options.Options; import ghidra.util.HelpLocation; @@ -56,7 +57,7 @@ public class VisualGraphOptions { "new graphs and already rendered graphs are zoomed and positioned. See the help for " + "more details."; - public static final Color DEFAULT_GRAPH_BACKGROUND_COLOR = Color.WHITE; + public static final GColor DEFAULT_GRAPH_BACKGROUND_COLOR = new GColor("color.bg.visualgraph"); protected Color graphBackgroundColor = DEFAULT_GRAPH_BACKGROUND_COLOR; protected boolean useAnimation = true; @@ -74,6 +75,10 @@ public class VisualGraphOptions { return graphBackgroundColor; } + public boolean isDefaultBackgroundColor(Color c) { + return DEFAULT_GRAPH_BACKGROUND_COLOR.equals(c); + } + public boolean getScrollWheelPans() { return scrollWheelPans; } @@ -117,7 +122,8 @@ public class VisualGraphOptions { options.registerOption(SCROLL_WHEEL_PANS_KEY, getScrollWheelPans(), help, SCROLL_WHEEL_PANS_DESCRIPTION); - options.registerOption(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR, help, + options.registerThemeColorBinding(GRAPH_BACKGROUND_COLOR_KEY, + DEFAULT_GRAPH_BACKGROUND_COLOR.getId(), help, GRAPH_BACKGROUND_COLOR_DESCRPTION); } diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/DebugShape.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/DebugShape.java index 03c1cae595..157c9d953c 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/DebugShape.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/DebugShape.java @@ -19,11 +19,11 @@ import java.awt.*; import java.awt.geom.Rectangle2D; import java.util.concurrent.atomic.AtomicInteger; -import javax.swing.SwingUtilities; - import edu.uci.ics.jung.visualization.VisualizationServer; import edu.uci.ics.jung.visualization.VisualizationServer.Paintable; import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator; +import generic.theme.GThemeDefaults.Colors.Palette; +import ghidra.util.Swing; public class DebugShape implements Paintable { @@ -75,7 +75,7 @@ public class DebugShape implements Paintable { g.draw(shape); - g.setColor(Color.black); + g.setColor(Palette.BLACK); FontMetrics fontMetrics = g.getFontMetrics(); Rectangle2D stringBounds = fontMetrics.getStringBounds(text, g); Point location = shape.getBounds().getLocation(); @@ -88,12 +88,7 @@ public class DebugShape implements Paintable { private boolean shapeIsOutdated() { if (drawingIterationID != drawingIterationCounter.get()) { // we are no longer drawing this shape - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - viewer.removePostRenderPaintable(DebugShape.this); - } - }); + Swing.runLater(() -> viewer.removePostRenderPaintable(DebugShape.this)); return true; } return false; diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseClickedPaintableShape.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseClickedPaintableShape.java index 735bc4da37..0e4d8b437b 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseClickedPaintableShape.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseClickedPaintableShape.java @@ -19,12 +19,14 @@ import java.awt.Color; import java.awt.Point; import java.awt.geom.Ellipse2D; +import generic.theme.GThemeDefaults.Colors.Palette; + /** * A debugging shape painter that allows the user to see where a mouse clicked happened. */ public class MouseClickedPaintableShape extends PaintableShape { - private static final Color DEFAULT_COLOR = new Color(255, 200, 0, 127); // orangish + private static final Color DEFAULT_COLOR = Palette.ORANGE.withAlpha(127); public MouseClickedPaintableShape(Point p, double tx, double ty) { this(p, tx, ty, DEFAULT_COLOR); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedLinePaintableShape.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedLinePaintableShape.java index 59bd05ff6a..4328bd4123 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedLinePaintableShape.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedLinePaintableShape.java @@ -20,6 +20,11 @@ import java.awt.geom.GeneralPath; import java.util.ArrayList; import java.util.List; +import generic.theme.GThemeDefaults.Colors.Palette; + +/** + * Paints a line showing the start and end points of a drag operation. + */ public class MouseDraggedLinePaintableShape extends PaintableShape { private List points = new ArrayList<>(); @@ -27,7 +32,7 @@ public class MouseDraggedLinePaintableShape extends PaintableShape { public MouseDraggedLinePaintableShape(Point start, Point end, double tx, double ty) { super(tx, ty); - this.color = new Color(0, 200, 0, 137); + this.color = Palette.GREEN.withAlpha(127); this.stroke = new BasicStroke(20); points.add(start); @@ -89,7 +94,7 @@ public class MouseDraggedLinePaintableShape extends PaintableShape { g.draw(shape); // g.fill(shape); -// g.setColor(new Color(20, 200, 20, 147)); +// g.setColor(Palette.GREEN.withAlpha(127);); // controls.forEach(c -> { // // int x = c.x; @@ -101,7 +106,7 @@ public class MouseDraggedLinePaintableShape extends PaintableShape { // g.fill(r); // }); // -// g.setColor(Color.pink); +// g.setColor(Palette.PINK); // points.forEach(p -> { // int x = p.x; // int y = p.y; diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedPaintableShape.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedPaintableShape.java index 7f8ec92266..d77c315e81 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedPaintableShape.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/MouseDraggedPaintableShape.java @@ -18,16 +18,21 @@ package ghidra.graph.viewer.renderer; import java.awt.*; import java.awt.geom.Rectangle2D; +import generic.theme.GColor; + +/** + * Paints a rectangle showing the start and end points of a drag. + */ public class MouseDraggedPaintableShape extends PaintableShape { - private static final Color START_COLOR = new Color(200, 0, 80, 25); - private static final Color END_COLOR = new Color(200, 0, 80, 200); + private static final GColor BASE_COLOR = new GColor("color.palette.crimson"); + private static final Color START_COLOR = BASE_COLOR.withAlpha(25); + private static final Color END_COLOR = BASE_COLOR.withAlpha(200); private Paint paint; public MouseDraggedPaintableShape(Point start, Point end, double tx, double ty) { super(tx, ty); - this.color = new Color(200, 0, 80, 147); this.stroke = new BasicStroke(15); int x1 = start.x; diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/PaintableShape.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/PaintableShape.java index 83c52860e2..1ebbbe1e04 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/PaintableShape.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/PaintableShape.java @@ -18,13 +18,15 @@ package ghidra.graph.viewer.renderer; import java.awt.*; import java.util.Objects; +import generic.theme.GThemeDefaults.Colors.Palette; + /** * A base class for shapes that can be painted on the graph. See {@link MouseDebugPaintable}. */ public class PaintableShape { protected Shape shape; - protected Color color = new Color(255, 200, 0, 127); // orange with alpha; + protected Color color = Palette.ORANGE.withAlpha(127); protected Stroke stroke; protected double tx; diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualGraphRenderer.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualGraphRenderer.java index a6e46ad8bc..61f844bbb3 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualGraphRenderer.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualGraphRenderer.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,6 +26,7 @@ import edu.uci.ics.jung.visualization.*; import edu.uci.ics.jung.visualization.layout.ObservableCachingLayout; import edu.uci.ics.jung.visualization.renderers.Renderer; import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.viewer.*; import ghidra.graph.viewer.edge.BasicEdgeLabelRenderer; import ghidra.graph.viewer.layout.*; @@ -143,8 +144,8 @@ public class VisualGraphRenderer GraphicsDecorator g = renderContext.getGraphicsContext(); Color originalColor = g.getColor(); - Color gridColor = Color.ORANGE; - Color textColor = Color.BLACK; + Color gridColor = Palette.ORANGE; + Color textColor = Palette.BLACK; boolean isCondensed = locationMap.isCondensed(); Row lastRow = locationMap.lastRow(); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualVertexSatelliteRenderer.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualVertexSatelliteRenderer.java index 9b406a4e71..ca00b63872 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualVertexSatelliteRenderer.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/renderer/VisualVertexSatelliteRenderer.java @@ -17,9 +17,13 @@ package ghidra.graph.viewer.renderer; import java.awt.*; +import com.google.common.base.Function; + import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.visualization.RenderContext; import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors; import ghidra.graph.viewer.VisualEdge; import ghidra.graph.viewer.VisualVertex; import ghidra.graph.viewer.vertex.AbstractVisualVertexRenderer; @@ -27,10 +31,14 @@ import ghidra.graph.viewer.vertex.AbstractVisualVertexRenderer; /** * A renderer for vertices for the satellite view. This is really just a basic renderer * that adds emphasis capability, as seen in the primary function graph renderer. + * @param the vertex type + * @param the edge type */ public class VisualVertexSatelliteRenderer> extends AbstractVisualVertexRenderer { + private Color highlightColor = new GColor("color.bg.highlight.visualgraph"); + /** * Overridden to handle painting emphasis. */ @@ -63,6 +71,27 @@ public class VisualVertexSatelliteRenderer rc, V v, Shape shape) { + GraphicsDecorator g = rc.getGraphicsContext(); + Paint oldPaint = g.getPaint(); + + Function fillXform = getVertexFillPaintTransformer(); + if (fillXform == null) { + fillXform = rc.getVertexFillPaintTransformer(); + } + + Paint fillPaint = fillXform.apply(v); + if (fillPaint == null) { + super.paintShapeForVertex(rc, v, shape); + return; + } + + g.setPaint(fillPaint); + g.fill(shape); + g.setPaint(oldPaint); + } + @Override protected Shape prepareFinalVertexShape(RenderContext rc, V v, Layout layout, int[] coords) { @@ -83,10 +112,7 @@ public class VisualVertexSatelliteRenderer highlightRenderer = new VisualVertexSatelliteRenderer<>(); @@ -56,10 +55,6 @@ public class CachingSatelliteGraphViewer layout = masterViewer.getGraphLayout(); if (layout instanceof ObservableCachingLayout) { ObservableCachingLayout cachingLayout = (ObservableCachingLayout) layout; @@ -76,7 +71,7 @@ public class CachingSatelliteGraphViewer getPreferredVertexRenderer() { - return new VisualVertexSatelliteRenderer() { + return new VisualVertexSatelliteRenderer<>() { @Override protected void paintHighlight(RenderContext rc, V vertex, GraphicsDecorator g, Rectangle bounds) { @@ -100,16 +95,16 @@ public class CachingSatelliteGraphViewer> extends BasicVertexRenderer { + private static final Color HIGHLIGHT_COLOR = new GColor("color.bg.highlight.visualgraph"); + private static final Color DROP_SHADOW_DARK = + new GColor("color.bg.visualgraph.drop.shadow.dark"); + private static final Color DROP_SHADOW_LIGHT = + new GColor("color.bg.visualgraph.drop.shadow.light"); + + private Function vertexFillPaintTransformer; + + /** + * Sets the optional transformer used to convert a vertex into a color + * @param transformer the transformer + */ + public void setVertexFillPaintTransformer(Function transformer) { + this.vertexFillPaintTransformer = transformer; + } + + public Function getVertexFillPaintTransformer() { + return vertexFillPaintTransformer; + } + /** * Creates a copy of the given {@link GraphicsDecorator} that may have scaling tweaked to * handle {@link VisualVertex#getEmphasis()} emphasized vertices. + * @param g the graphics + * @param vertex the vertex + * @param rc the render context + * @param layout the graph layout + * @return the new graphics */ protected GraphicsDecorator getEmphasisGraphics(GraphicsDecorator g, V vertex, RenderContext rc, Layout layout) { @@ -96,8 +122,7 @@ public class AbstractVisualVertexRenderer rc) { diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/DockingVisualVertex.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/DockingVisualVertex.java index 277b6de5cd..199ac7704a 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/DockingVisualVertex.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/DockingVisualVertex.java @@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener; import javax.swing.*; import docking.GenericHeader; +import generic.theme.GColor; import ghidra.graph.viewer.VisualVertex; import ghidra.util.MathUtilities; @@ -54,8 +55,9 @@ public class DockingVisualVertex extends AbstractVisualVertex { }; textArea.setText(name); textArea.setPreferredSize(new Dimension(200, 50)); - textArea.setBackground(Color.YELLOW.darker()); - textArea.setCaretColor(Color.PINK); + textArea.setBackground(new GColor("color.bg.visualgraph.dockingvertex")); + textArea.setForeground(new GColor("color.fg.visualgraph.dockingvertex")); + textArea.setCaretColor(new GColor("color.visualgraph.dockingvertex.cursor")); textArea.setBorder(BorderFactory.createRaisedBevelBorder()); textArea.setLineWrap(true); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/VisualVertexRenderer.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/VisualVertexRenderer.java index 7827d795e3..c9d3aeec10 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/VisualVertexRenderer.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/vertex/VisualVertexRenderer.java @@ -26,6 +26,7 @@ import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.util.Context; import edu.uci.ics.jung.visualization.RenderContext; import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator; +import generic.theme.GThemeDefaults.Colors; import ghidra.graph.VisualGraph; import ghidra.graph.viewer.VisualEdge; import ghidra.graph.viewer.VisualVertex; @@ -108,10 +109,10 @@ public class VisualVertexRenderer rc, V vertex, GraphicsDecorator g, Shape shape) { - Function fillXform = rc.getVertexFillPaintTransformer(); + + Function fillXform = getVertexFillPaintTransformer(); + if (fillXform == null) { + fillXform = rc.getVertexFillPaintTransformer(); + } + Paint fillPaint = fillXform.apply(vertex); if (fillPaint == null) { return; @@ -147,9 +153,10 @@ public class VisualVertexRenderer edgePriorityMap = new HashMap<>(); private List changeListeners = new CopyOnWriteArrayList<>(); - private Color vertexSelectionColor = Color.green; - private Color edgeSelectionColor = Color.green; - private Color defaultVertexColor = Color.blue; - private Color defaultEdgeColor = Color.blue; + private Color vertexSelectionColor = new GColor("color.graphdisplay.vertex.selected"); + private Color edgeSelectionColor = new GColor("color.graphdisplay.edge.selected"); + private Color defaultVertexColor = new GColor("color.graphdisplay.vertex.default"); + private Color defaultEdgeColor = new GColor("color.graphdisplay.edge.default"); private String favoredEdgeType; private VertexShape defaultVertexShape = VertexShape.RECTANGLE; @@ -80,11 +81,16 @@ public class GraphDisplayOptions implements OptionsChangeListener { private String defaultLayoutAlgorithmName = LayoutAlgorithmNames.MIN_CROSS_COFFMAN_GRAHAM; private boolean useIcons = true; private GraphLabelPosition labelPosition = GraphLabelPosition.SOUTH; - private Font font = new Font("Dialog", Font.BOLD, 18); + private Font font = Gui.getFont("font.graphdisplay.default"); + private String themeFontId = null; private int arrowLength = 15; private int maxNodeCount = 500; // graph display struggles with too many nodes + private Map vertexRegistrations = new HashMap<>(); + private Map edgeRegistrations = new HashMap<>(); + private Map defaultRegistrations = new HashMap<>(); + /** * Constructs a new GraphTypeDisplayOptions for the given {@link GraphType} * @param graphType The {@link GraphType} for which to define display options @@ -155,6 +161,16 @@ public class GraphDisplayOptions implements OptionsChangeListener { this.defaultVertexColor = Objects.requireNonNull(color); } + /** + * Sets the default color to be used by vertices that don't have a vertex type set. The + * color is set via a themeColorId, which means the client defined a theme color for this. + * @param themeColorId the theme color id to use for the default vertex color + */ + public void setDefaultVertexColor(String themeColorId) { + this.defaultVertexColor = new GColor(themeColorId); + defaultRegistrations.put(DEFAULT_VERTEX_COLOR, themeColorId); + } + /** * Sets the default color to be used by edges that don't have a edge type set * @param color the default edge shape @@ -163,6 +179,16 @@ public class GraphDisplayOptions implements OptionsChangeListener { this.defaultEdgeColor = Objects.requireNonNull(color); } + /** + * Sets the default color to be used by vertices that don't have a vertex type set. The + * color is set via a themeColorId, which means the client defined a theme color for this. + * @param themeColorId the theme color id to use for the default vertex color + */ + public void setDefaultEdgeColor(String themeColorId) { + this.defaultEdgeColor = new GColor(themeColorId); + defaultRegistrations.put(DEFAULT_EDGE_COLOR, themeColorId); + } + /** * Returns the default color for edges that don't have an edge type set * @return the default color for edges that don't have an edge type set @@ -353,7 +379,9 @@ public class GraphDisplayOptions implements OptionsChangeListener { } /** - * Sets the color for vertices with the given vertex type + * Sets the color for vertices with the given vertex type. Note that this method does not + * allow the vertex color to be registered in tool options. + * See {@link #setVertexColor(String, String)}. * @param vertexType the vertex type for which to set its color * @param color the color to use for vertices with the given vertex type */ @@ -362,6 +390,18 @@ public class GraphDisplayOptions implements OptionsChangeListener { vertexColorMap.put(vertexType, Objects.requireNonNull(color)); } + /** + * Sets the vertex color using a theme color id. By using a theme color id, this property + * is eligible to be registered as a tool option. + * @param vertexType the vertex type for which to set its color + * @param themeColorId the theme color id of the color for this vertex type + */ + public void setVertexColor(String vertexType, String themeColorId) { + checkVertexType(vertexType); + vertexColorMap.put(vertexType, new GColor(Objects.requireNonNull(themeColorId))); + vertexRegistrations.put(vertexType, themeColorId); + } + private String getVertexShapeName(String vertexType) { VertexShape vertexShape = vertexShapeMap.getOrDefault(vertexType, defaultVertexShape); return vertexShape.getName(); @@ -386,6 +426,18 @@ public class GraphDisplayOptions implements OptionsChangeListener { return edgeColorMap.getOrDefault(edgeType, defaultEdgeColor); } + /** + * Sets the edge color using a theme color id. By using a theme color id, this property + * is eligible to be registered as a tool option. + * @param edgeType the edge type for which to set its color + * @param themeColorId the theme color id of the color for this edge type + */ + public void setEdgeColor(String edgeType, String themeColorId) { + checkEdgeType(edgeType); + edgeColorMap.put(edgeType, new GColor(Objects.requireNonNull(themeColorId))); + edgeRegistrations.put(edgeType, themeColorId); + } + /** * Sets the color for edges with the given edge type * @param edgeType the edge type for which to set its color @@ -459,13 +511,24 @@ public class GraphDisplayOptions implements OptionsChangeListener { } /** - * Sets the vertex selection color + * Sets the vertex selection color. Use this method only if this color does not appear in + * the tool options. * @param vertexSelectionColor the color to use for highlighting selected vertices */ public void setVertexSelectionColor(Color vertexSelectionColor) { this.vertexSelectionColor = vertexSelectionColor; } + /** + * Sets the vertex selection color using the theme color defined by the given color id. This + * method will allow the property to be registered to the tool options. + * @param themeColorId the color id to use for highlighting vertices. + */ + public void setVertexSelectionColor(String themeColorId) { + this.vertexSelectionColor = new GColor(themeColorId); + defaultRegistrations.put(VERTEX_SELECTION_COLOR, themeColorId); + } + /** * Returns the color for edge selections * @return the color fore edge selections @@ -475,13 +538,24 @@ public class GraphDisplayOptions implements OptionsChangeListener { } /** - * Sets the edge selection color + * Sets the edge selection color. Using the method means the color will not appear in the + * tool options. * @param edgeSelectionColor color to use for highlighting selected edges */ public void setEdgeSelectionColor(Color edgeSelectionColor) { this.edgeSelectionColor = edgeSelectionColor; } + /** + * Sets the edge selection color using the theme color defined by the given color id. This + * method will allow the property to be registered to the tool options. + * @param themeColorId the color id to use for highlighting edges. + */ + public void setEdgeSelectionColor(String themeColorId) { + this.edgeSelectionColor = new GColor(themeColorId); + defaultRegistrations.put(EDGE_SELECTION_COLOR, themeColorId); + } + /** * Returns the name of the default graph layout algorithm * @return the name of the default graph layout algorithms @@ -543,6 +617,11 @@ public class GraphDisplayOptions implements OptionsChangeListener { this.font = font; } + public void setFont(String themeFontId) { + this.themeFontId = themeFontId; + this.font = Gui.getFont(themeFontId); + } + /** * Returns the font being used to render vertex labels * @return the font being used to render vertex labels @@ -617,25 +696,48 @@ public class GraphDisplayOptions implements OptionsChangeListener { } /** - * Sets default values for vertex types + * Sets default values for vertex types. This method does not allow the vertexType color to + * be eligible to be registered as a tool option. * @param vertexType the vertex type whose default color and shape are being defined * @param vertexShape the default vertex shape for the given vertex type * @param color the default color for the given vertex type */ protected void configureVertexType(String vertexType, VertexShape vertexShape, Color color) { - checkVertexType(vertexType); - vertexShapeMap.put(vertexType, vertexShape); - vertexColorMap.put(vertexType, color); + setVertexColor(vertexType, color); + setVertexShape(vertexType, vertexShape); } /** - * Sets default values for edge types + * Sets default values for vertex types using theme color ids. This makes them eligible to be + * registered as tool options. + * @param vertexType the vertex type whose default color and shape are being defined + * @param vertexShape the default vertex shape for the given vertex type + * @param themeColorId the color id for the theme color to be used as the color. + */ + protected void configureVertexType(String vertexType, VertexShape vertexShape, + String themeColorId) { + setVertexColor(vertexType, themeColorId); + setVertexShape(vertexType, vertexShape); + } + + /** + * Sets default values for edge types. This method does not allow the vertexType color to + * be eligible to be registered as a tool option. * @param edgeType the edge type whose default color and shape are being defined * @param color the default color for the given edge type */ protected void configureEdgeType(String edgeType, Color color) { - checkEdgeType(edgeType); - edgeColorMap.put(edgeType, color); + setEdgeColor(edgeType, color); + } + + /** + * Sets default values for edge types using theme color ids. This makes them eligible to be + * registered as tool options. + * @param edgeType the edge type whose default color and shape are being defined + * @param themeColorId the color id for the theme color to be used as the color. + */ + protected void configureEdgeType(String edgeType, String themeColorId) { + setEdgeColor(edgeType, themeColorId); } /** @@ -727,9 +829,11 @@ public class GraphDisplayOptions implements OptionsChangeListener { Options options = rootOptions.getOptions(VERTEX_COLORS); for (String vertexType : graphType.getVertexTypes()) { - options.registerOption(vertexType, OptionType.COLOR_TYPE, - getVertexColor(vertexType), help, - "Choose the color for this vertex type"); + if (vertexRegistrations.containsKey(vertexType)) { + options.registerThemeColorBinding(vertexType, + vertexRegistrations.get(vertexType), help, + "Choose the color for this vertex type"); + } } List list = new ArrayList<>(graphType.getVertexTypes()); OptionsEditor editor = new ScrollableOptionsEditor(VERTEX_COLORS, list); @@ -744,8 +848,8 @@ public class GraphDisplayOptions implements OptionsChangeListener { for (String vertexType : graphType.getVertexTypes()) { StringWithChoicesEditor editor = new StringWithChoicesEditor(shapeNames); options.registerOption(vertexType, OptionType.STRING_TYPE, - getVertexShapeName(vertexType), help, - "Choose the shape for this vertex type", editor); + getVertexShapeName(vertexType), help, "Choose the shape for this vertex type", + editor); } List list = new ArrayList<>(graphType.getVertexTypes()); OptionsEditor editor = new ScrollableOptionsEditor(VERTEX_SHAPES, list); @@ -756,8 +860,11 @@ public class GraphDisplayOptions implements OptionsChangeListener { Options options = rootOptions.getOptions(EDGE_COLORS); for (String edgeType : graphType.getEdgeTypes()) { - options.registerOption(edgeType, OptionType.COLOR_TYPE, - getEdgeColor(edgeType), help, "Choose the color for this edge type"); + if (edgeRegistrations.containsKey(edgeType)) { + options.registerThemeColorBinding(edgeType, + edgeRegistrations.get(edgeType), + help, "Choose the color for this edge type"); + } } List list = new ArrayList<>(graphType.getEdgeTypes()); OptionsEditor editor = new ScrollableOptionsEditor(EDGE_COLORS, list); @@ -765,29 +872,49 @@ public class GraphDisplayOptions implements OptionsChangeListener { } private void registerMiscellaneousOptions(Options rootOptions, HelpLocation help) { + List optionNamesInDisplayOrder = new ArrayList<>(); Options options = rootOptions.getOptions(MISCELLANEOUS_OPTIONS); + optionNamesInDisplayOrder.add(MAX_NODES_SIZE); options.registerOption(MAX_NODES_SIZE, OptionType.INT_TYPE, maxNodeCount, help, "Graphs with more than this number of nodes will not be displayed. (Large graphs can cause Ghidra to become unstable/sluggish)"); StringWithChoicesEditor editor = new StringWithChoicesEditor(VertexShape.getShapeNames()); - options.registerOption(VERTEX_SELECTION_COLOR, OptionType.COLOR_TYPE, vertexSelectionColor, - help, "Color for highlighting selected vertices"); + if (defaultRegistrations.containsKey(VERTEX_SELECTION_COLOR)) { + optionNamesInDisplayOrder.add(VERTEX_SELECTION_COLOR); + options.registerThemeColorBinding(VERTEX_SELECTION_COLOR, + defaultRegistrations.get(VERTEX_SELECTION_COLOR), + help, "Color for highlighting selected vertices"); + } - options.registerOption(EDGE_SELECTION_COLOR, OptionType.COLOR_TYPE, edgeSelectionColor, - help, "Color for highlighting selected edge"); + if (defaultRegistrations.containsKey(EDGE_SELECTION_COLOR)) { + optionNamesInDisplayOrder.add(EDGE_SELECTION_COLOR); + options.registerThemeColorBinding(EDGE_SELECTION_COLOR, + defaultRegistrations.get(EDGE_SELECTION_COLOR), + help, "Color for highlighting selected edge"); + } + if (defaultRegistrations.containsKey(DEFAULT_VERTEX_COLOR)) { + optionNamesInDisplayOrder.add(DEFAULT_VERTEX_COLOR); + options.registerThemeColorBinding(DEFAULT_VERTEX_COLOR, + defaultRegistrations.get(DEFAULT_VERTEX_COLOR), + help, "Color for vertices that have no vertex type defined"); + } + + if (defaultRegistrations.containsKey(DEFAULT_EDGE_COLOR)) { + optionNamesInDisplayOrder.add(DEFAULT_EDGE_COLOR); + options.registerThemeColorBinding(DEFAULT_EDGE_COLOR, + defaultRegistrations.get(DEFAULT_EDGE_COLOR), + help, "Color for edge that have no edge type defined"); + } + + optionNamesInDisplayOrder.add(DEFAULT_VERTEX_SHAPE); options.registerOption(DEFAULT_VERTEX_SHAPE, OptionType.STRING_TYPE, - defaultVertexShape.getName(), - help, "Shape for vertices that have no vertex type defined", editor); - - options.registerOption(DEFAULT_VERTEX_COLOR, OptionType.COLOR_TYPE, defaultVertexColor, - help, "Color for vertices that have no vertex type defined"); - - options.registerOption(DEFAULT_EDGE_COLOR, OptionType.COLOR_TYPE, defaultEdgeColor, - help, "Color for edge that have no edge type defined"); + defaultVertexShape.getName(), help, + "Shape for vertices that have no vertex type defined", editor); + optionNamesInDisplayOrder.add(FAVORED_EDGE_TYPE); List edgeTypes = graphType.getEdgeTypes(); if (!edgeTypes.isEmpty()) { editor = new StringWithChoicesEditor(edgeTypes); @@ -795,32 +922,24 @@ public class GraphDisplayOptions implements OptionsChangeListener { "Favored edge is used to influence layout algorithms", editor); } + optionNamesInDisplayOrder.add(DEFAULT_LAYOUT_ALGORITHM); editor = new StringWithChoicesEditor(LayoutAlgorithmNames.getLayoutAlgorithmNames()); options.registerOption(DEFAULT_LAYOUT_ALGORITHM, OptionType.STRING_TYPE, defaultLayoutAlgorithmName, help, "Initial layout algorithm", editor); - options.registerOption(USE_ICONS, OptionType.BOOLEAN_TYPE, useIcons, help, - "If true, vertices are drawn using pre-rendered images versus compact shapes"); - + optionNamesInDisplayOrder.add(LABEL_POSITION); options.registerOption(LABEL_POSITION, OptionType.ENUM_TYPE, labelPosition, help, "Relative postion of labels to vertex shape (Only applicable if \"Use Icons\" is true"); - options.registerOption(FONT, OptionType.FONT_TYPE, font, help, - "Font to use for vertex labels"); + if (themeFontId != null) { + optionNamesInDisplayOrder.add(FONT); + options.registerThemeFontBinding(FONT, themeFontId, help, + "Font to use for vertex labels"); + } - List optionNamesInDisplayOrder = new ArrayList<>(); - - optionNamesInDisplayOrder.add(MAX_NODES_SIZE); - optionNamesInDisplayOrder.add(VERTEX_SELECTION_COLOR); - optionNamesInDisplayOrder.add(EDGE_SELECTION_COLOR); - optionNamesInDisplayOrder.add(DEFAULT_VERTEX_COLOR); - optionNamesInDisplayOrder.add(DEFAULT_EDGE_COLOR); - optionNamesInDisplayOrder.add(DEFAULT_VERTEX_SHAPE); - optionNamesInDisplayOrder.add(FAVORED_EDGE_TYPE); - optionNamesInDisplayOrder.add(DEFAULT_LAYOUT_ALGORITHM); - optionNamesInDisplayOrder.add(LABEL_POSITION); - optionNamesInDisplayOrder.add(FONT); optionNamesInDisplayOrder.add(USE_ICONS); + options.registerOption(USE_ICONS, OptionType.BOOLEAN_TYPE, useIcons, help, + "If true, vertices are drawn using pre-rendered images versus compact shapes"); OptionsEditor optionsEditor = new ScrollableOptionsEditor(MISCELLANEOUS_OPTIONS, optionNamesInDisplayOrder); diff --git a/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestGraphViewer.java b/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestGraphViewer.java index f1db1e2d4f..f7713d5aef 100644 --- a/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestGraphViewer.java +++ b/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestGraphViewer.java @@ -15,11 +15,11 @@ */ package ghidra.graph.support; -import java.awt.Color; import java.awt.Dimension; -import ghidra.graph.graphs.TestEdge; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.graphs.AbstractTestVertex; +import ghidra.graph.graphs.TestEdge; import ghidra.graph.viewer.GraphViewer; /** @@ -29,7 +29,7 @@ public class TestGraphViewer extends GraphViewer { public TestGraphViewer(TestGraphLayout layout, Dimension size) { super(layout, size); - setBackground(Color.WHITE); + setBackground(Palette.WHITE); } } diff --git a/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestVertexTooltipProvider.java b/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestVertexTooltipProvider.java index a48712666e..2b8d591c42 100644 --- a/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestVertexTooltipProvider.java +++ b/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TestVertexTooltipProvider.java @@ -15,7 +15,6 @@ */ package ghidra.graph.support; -import java.awt.Color; import java.awt.Dimension; import java.awt.event.MouseEvent; import java.util.*; @@ -27,6 +26,7 @@ import org.apache.commons.collections4.Factory; import org.apache.commons.collections4.map.LazyMap; import docking.widgets.label.GDHtmlLabel; +import generic.theme.GColor; import ghidra.graph.graphs.AbstractTestVertex; import ghidra.graph.graphs.TestEdge; import ghidra.graph.viewer.event.mouse.VertexTooltipProvider; @@ -110,7 +110,7 @@ public class TestVertexTooltipProvider SpyTooltipLabel(String text) { setText(text); setOpaque(true); - setBackground(Color.ORANGE.darker()); + setBackground(new GColor("color.palette.olive")); setPreferredSize(new Dimension(200, 100)); } diff --git a/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TextAreaTestVertex.java b/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TextAreaTestVertex.java index dbc736170e..988d143b8f 100644 --- a/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TextAreaTestVertex.java +++ b/Ghidra/Framework/Graph/src/test.slow/java/ghidra/graph/support/TextAreaTestVertex.java @@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener; import javax.swing.*; import docking.GenericHeader; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.graphs.AbstractTestVertex; /** @@ -39,8 +40,8 @@ public class TextAreaTestVertex extends AbstractTestVertex { textArea.setText(name); textArea.setPreferredSize(new Dimension(200, 50)); - textArea.setBackground(Color.YELLOW.darker()); - textArea.setCaretColor(Color.PINK); + textArea.setBackground(Palette.getColor("darkkhaki")); + textArea.setCaretColor(Palette.PINK); textArea.setBorder(BorderFactory.createRaisedBevelBorder()); textArea.setLineWrap(true); diff --git a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/GraphAlgorithmsVisualDebugger.java b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/GraphAlgorithmsVisualDebugger.java index ba9796834f..fda5028e57 100644 --- a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/GraphAlgorithmsVisualDebugger.java +++ b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/GraphAlgorithmsVisualDebugger.java @@ -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 createGraph() { return GraphFactory.createDirectedGraph(); diff --git a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/AlgorithmTestSteppingVertex.java b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/AlgorithmTestSteppingVertex.java index 6a5f9e3447..407a2933ec 100644 --- a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/AlgorithmTestSteppingVertex.java +++ b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/AlgorithmTestSteppingVertex.java @@ -22,6 +22,8 @@ import java.awt.image.BufferedImage; import javax.swing.*; +import generic.theme.GColor; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.graph.algo.GraphAlgorithmStatusListener.STATUS; import ghidra.graph.graphs.AbstractTestVertex; import ghidra.graph.viewer.vertex.VertexShapeProvider; @@ -86,11 +88,12 @@ public class AlgorithmTestSteppingVertex extends AbstractTestVertex private void buildShapes() { - defaultShape = buildCircleShape(Color.LIGHT_GRAY, "default"); - defaultWithPathShape = buildCircleShape(new Color(192, 216, 65), "default; was in path"); - scheduledShape = buildCircleShape(new Color(255, 248, 169), "scheduled"); - exploringShape = buildCircleShape(new Color(0, 147, 0), "exploring"); - blockedShape = buildCircleShape(new Color(249, 190, 190), "blocked"); + defaultShape = buildCircleShape(Palette.LIGHT_GRAY, "default"); + defaultWithPathShape = + buildCircleShape(new GColor("color.palette.yellowgreen"), "default; was in path"); + scheduledShape = buildCircleShape(new GColor("color.palette.khaki"), "scheduled"); + exploringShape = buildCircleShape(Palette.GREEN, "exploring"); + blockedShape = buildCircleShape(Palette.PINK, "blocked"); currentShape = defaultShape; } diff --git a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/TestGraphAlgorithmSteppingViewerPanel.java b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/TestGraphAlgorithmSteppingViewerPanel.java index 6f490e53a0..2569ba6226 100644 --- a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/TestGraphAlgorithmSteppingViewerPanel.java +++ b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/algo/viewer/TestGraphAlgorithmSteppingViewerPanel.java @@ -27,6 +27,7 @@ import org.apache.commons.collections4.bidimap.DualHashBidiMap; import edu.uci.ics.jung.visualization.decorators.EdgeShape; import edu.uci.ics.jung.visualization.renderers.Renderer; +import generic.theme.GThemeDefaults.Colors.Palette; import generic.util.image.ImageUtils; import ghidra.graph.*; import ghidra.graph.algo.GraphAlgorithmStatusListener; @@ -86,7 +87,7 @@ public class TestGraphAlgorithmSteppingViewerPanel> extend BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) image.getGraphics(); - g.setColor(Color.WHITE); + g.setColor(Palette.WHITE); g.fillRect(0, 0, w, h); try { diff --git a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/graphs/LabelTestVertex.java b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/graphs/LabelTestVertex.java index 1d0726fadf..451846c00d 100644 --- a/Ghidra/Framework/Graph/src/test/java/ghidra/graph/graphs/LabelTestVertex.java +++ b/Ghidra/Framework/Graph/src/test/java/ghidra/graph/graphs/LabelTestVertex.java @@ -15,12 +15,12 @@ */ package ghidra.graph.graphs; -import java.awt.Color; import java.awt.Dimension; import javax.swing.*; import docking.widgets.label.GDLabel; +import generic.theme.GThemeDefaults.Colors.Palette; /** * A test vertex that renders using a {@link JLabel}. @@ -33,7 +33,7 @@ public class LabelTestVertex extends AbstractTestVertex { super(name); label.setText(name); label.setPreferredSize(new Dimension(50, 50)); - label.setBackground(Color.YELLOW.darker()); + label.setBackground(Palette.GOLD); label.setOpaque(true); label.setBorder(BorderFactory.createRaisedBevelBorder()); label.setHorizontalAlignment(SwingConstants.CENTER); diff --git a/Ghidra/Framework/Graph/src/test/java/ghidra/service/graph/GraphDisplayOptionsTest.java b/Ghidra/Framework/Graph/src/test/java/ghidra/service/graph/GraphDisplayOptionsTest.java index 320bc70600..ae019bbed5 100644 --- a/Ghidra/Framework/Graph/src/test/java/ghidra/service/graph/GraphDisplayOptionsTest.java +++ b/Ghidra/Framework/Graph/src/test/java/ghidra/service/graph/GraphDisplayOptionsTest.java @@ -18,17 +18,18 @@ package ghidra.service.graph; import static org.junit.Assert.*; import java.awt.Color; +import java.awt.Font; import java.util.Arrays; import java.util.List; import org.junit.Before; import org.junit.Test; -import docking.FakeDockingTool; +import generic.theme.*; +import generic.theme.GThemeDefaults.Colors.Palette; import ghidra.framework.options.Options; import ghidra.framework.options.ToolOptions; import ghidra.util.HelpLocation; -import ghidra.util.WebColors; public class GraphDisplayOptionsTest { @@ -37,10 +38,26 @@ public class GraphDisplayOptionsTest { @Before public void setUp() { + // create a dummy theme manager that defines values for use in this test + DummyThemeManager themeManager = new DummyThemeManager(); + + // create a new graph definition and options using theme properties List vertexTypes = Arrays.asList("V1", "V2", "V3"); List 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 @@ -51,14 +68,14 @@ public class GraphDisplayOptionsTest { @Test public void testSetAndGetDefaultVertexColor() { - options.setDefaultVertexColor(Color.MAGENTA); - assertEquals(Color.MAGENTA, options.getDefaultVertexColor()); + options.setDefaultVertexColor(Palette.RED); + assertEquals(Palette.RED, options.getDefaultVertexColor()); } @Test public void testSetAndGetDefaultEdgeColor() { - options.setDefaultEdgeColor(Color.MAGENTA); - assertEquals(Color.MAGENTA, options.getDefaultEdgeColor()); + options.setDefaultEdgeColor(Palette.RED); + assertEquals(Palette.RED, options.getDefaultEdgeColor()); } @Test @@ -131,62 +148,62 @@ public class GraphDisplayOptionsTest { @Test public void testGetVertexColor() { - options.setVertexColor("V1", Color.RED); - options.setVertexColor("V2", Color.GREEN); + options.setVertexColor("V1", Palette.RED); + options.setVertexColor("V2", Palette.GREEN); AttributedVertex vertex = new AttributedVertex("Foo"); assertEquals(options.getDefaultVertexColor(), options.getVertexColor(vertex)); vertex.setVertexType("V1"); - assertEquals(Color.RED, options.getVertexColor(vertex)); + assertEquals(Palette.RED, options.getVertexColor(vertex)); vertex.setVertexType("V2"); - assertEquals(Color.GREEN, options.getVertexColor(vertex)); + assertEquals(Palette.GREEN, options.getVertexColor(vertex)); } @Test public void testGetVertexColorWithOverride() { - options.setVertexColor("V1", Color.RED); - options.setVertexColor("V2", Color.GREEN); + options.setVertexColor("V1", Palette.RED); + options.setVertexColor("V2", Palette.GREEN); options.setVertexColorOverrideAttributeKey("Color"); AttributedVertex vertex = new AttributedVertex("Foo"); vertex.setVertexType("V1"); - assertEquals(Color.RED, options.getVertexColor(vertex)); + assertEquals(Palette.RED, options.getVertexColor(vertex)); - vertex.setAttribute("Color", WebColors.toString(Color.BLUE)); + vertex.setAttribute("Color", Palette.BLUE.toString()); - assertEquals(Color.BLUE, options.getVertexColor(vertex)); + assertEquals(Palette.BLUE.getRGB(), options.getVertexColor(vertex).getRGB()); } @Test public void testGetEdgeColor() { - options.setEdgeColor("E1", Color.RED); - options.setEdgeColor("E2", Color.GREEN); + options.setEdgeColor("E1", Palette.RED); + options.setEdgeColor("E2", Palette.GREEN); AttributedEdge edge = new AttributedEdge("1"); assertEquals(options.getDefaultEdgeColor(), options.getEdgeColor(edge)); edge.setEdgeType("E1"); - assertEquals(Color.RED, options.getEdgeColor(edge)); + assertEquals(Palette.RED, options.getEdgeColor(edge)); edge.setEdgeType("E2"); - assertEquals(Color.GREEN, options.getEdgeColor(edge)); + assertEquals(Palette.GREEN, options.getEdgeColor(edge)); } @Test public void testGetEdgeColorWithOverride() { - options.setEdgeColor("E1", Color.RED); - options.setEdgeColor("E2", Color.GREEN); + options.setEdgeColor("E1", Palette.RED); + options.setEdgeColor("E2", Palette.GREEN); options.setEdgeColorOverrideAttributeKey("Color"); AttributedEdge edge = new AttributedEdge("1"); assertEquals(options.getDefaultEdgeColor(), options.getEdgeColor(edge)); edge.setEdgeType("E1"); - assertEquals(Color.RED, options.getEdgeColor(edge)); + assertEquals(Palette.RED, options.getEdgeColor(edge)); - edge.setAttribute("Color", WebColors.toString(Color.BLUE)); + edge.setAttribute("Color", Palette.BLUE.toString()); - assertEquals(Color.BLUE, options.getEdgeColor(edge)); + assertEquals(Palette.BLUE.getRGB(), options.getEdgeColor(edge).getRGB()); } @Test @@ -205,9 +222,10 @@ public class GraphDisplayOptionsTest { @Test public void testGetVertexColorForType() { - assertEquals(options.getDefaultVertexColor(), options.getVertexColor("V1")); - options.setVertexColor("V1", Color.RED); - assertEquals(Color.RED, options.getVertexColor("V1")); + assertEquals(options.getDefaultVertexColor().getRGB(), + options.getVertexColor("V1").getRGB()); + options.setVertexColor("V1", Palette.RED); + assertEquals(Palette.RED.getRGB(), options.getVertexColor("V1").getRGB()); } @Test @@ -220,8 +238,8 @@ public class GraphDisplayOptionsTest { @Test public void testGetEdgeColorForType() { assertEquals(options.getDefaultEdgeColor(), options.getEdgeColor("V1")); - options.setEdgeColor("E1", Color.RED); - assertEquals(Color.RED, options.getEdgeColor("E1")); + options.setEdgeColor("E1", Palette.RED); + assertEquals(Palette.RED, options.getEdgeColor("E1")); } @Test @@ -236,8 +254,8 @@ public class GraphDisplayOptionsTest { Options vertexColorOptions = graphDisplayOptions.getOptions("Vertex Colors"); List leafOptionNames = vertexColorOptions.getLeafOptionNames(); assertEquals(Arrays.asList("V1", "V2", "V3"), leafOptionNames); - assertEquals(options.getDefaultVertexColor(), - vertexColorOptions.getColor("V1", Color.WHITE)); + assertEquals(options.getDefaultVertexColor().getRGB(), + vertexColorOptions.getColor("V1", Palette.BLACK).getRGB()); Options vertexShapeOptions = graphDisplayOptions.getOptions("Vertex Shapes"); leafOptionNames = vertexShapeOptions.getLeafOptionNames(); @@ -248,8 +266,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", Color.WHITE)); + assertEquals(options.getDefaultEdgeColor().getRGB(), + edgeColorOptions.getColor("E1", Palette.WHITE).getRGB()); Options miscellaneousOptions = graphDisplayOptions.getOptions("Miscellaneous"); leafOptionNames = miscellaneousOptions.getLeafOptionNames(); @@ -260,22 +278,44 @@ public class GraphDisplayOptionsTest { } - @Test - public void testChangingToolOptionsAffectsGraph() { - FakeDockingTool tool = new FakeDockingTool(); - ToolOptions toolOptions = tool.getOptions("Graph"); - options.registerOptions(toolOptions, null); - options.initializeFromOptions(tool); + // Create a ThemeManager that it not fully initialized for speed. This class provides + // fake property theme values. + class DummyThemeManager extends StubThemeManager { + DummyThemeManager() { + installTestValues(); + installExpectedValues(); + installInGui(); + } - AttributedVertex vertex = new AttributedVertex("Foo"); - vertex.setVertexType("V1"); - assertEquals(Color.BLUE, options.getVertexColor(vertex)); + private void installExpectedValues() { + setColor(new ColorValue("color.vertex.selected", Color.BLACK)); + setColor(new ColorValue("color.edge.selected", Color.BLACK)); + setColor(new ColorValue("color.graphdisplay.vertex.default", Color.BLACK)); + setColor(new ColorValue("color.graphdisplay.edge.default", Color.BLACK)); + setFont(new FontValue("font.graph", new Font("monospaced", Font.PLAIN, 12))); - Options graphDisplayOptions = toolOptions.getOptions(options.getRootOptionsName()); - Options vertexColorOptions = graphDisplayOptions.getOptions("Vertex Colors"); - vertexColorOptions.setColor("V1", Color.CYAN); + } + + protected void installTestValues() { + setColor(new ColorValue("color.V1", Color.BLACK)); + setColor(new ColorValue("color.V2", Color.BLACK)); + setColor(new ColorValue("color.V3", Color.BLACK)); + setColor(new ColorValue("color.E1", Color.BLACK)); + setColor(new ColorValue("color.E2", Color.BLACK)); + setColor(new ColorValue("color.E3", Color.BLACK)); + setColor(new ColorValue("color.edge.default", Color.BLACK)); + setColor(new ColorValue("color.vertex.default", Color.BLACK)); + setColor(new ColorValue("color.edge.selected", Color.BLACK)); + setColor(new ColorValue("color.vertex.selected", Color.BLACK)); + setColor(new ColorValue("color.graphdisplay.vertex.selected", Color.BLACK)); + setColor(new ColorValue("color.graphdisplay.edge.selected", Color.BLACK)); + setColor(new ColorValue("color.vertex.selected", Color.BLACK)); + setColor(new ColorValue("color.vertex.selected", Color.BLACK)); + + setFont(new FontValue("font.graph", new Font("monospaced", Font.PLAIN, 12))); + setFont( + new FontValue("font.graphdisplay.default", new Font("monospaced", Font.PLAIN, 12))); + } - assertEquals(Color.CYAN, options.getVertexColor(vertex)); } - } diff --git a/Ghidra/Framework/Help/src/main/java/docking/DefaultHelpService.java b/Ghidra/Framework/Help/src/main/java/docking/DefaultHelpService.java index 42ff57ade0..b103ee06d0 100644 --- a/Ghidra/Framework/Help/src/main/java/docking/DefaultHelpService.java +++ b/Ghidra/Framework/Help/src/main/java/docking/DefaultHelpService.java @@ -74,6 +74,11 @@ public class DefaultHelpService implements HelpService { return false; } + @Override + public void reload() { + // no-op + } + private void displayHelpInfo(Object helpObj) { String msg = getHelpInfo(helpObj); Msg.showInfo(this, null, "Help Info", msg); diff --git a/Ghidra/Framework/Help/src/main/java/help/CustomFavoritesView.java b/Ghidra/Framework/Help/src/main/java/help/CustomFavoritesView.java index 29f2cb8cf6..6914f834ad 100644 --- a/Ghidra/Framework/Help/src/main/java/help/CustomFavoritesView.java +++ b/Ghidra/Framework/Help/src/main/java/help/CustomFavoritesView.java @@ -16,8 +16,7 @@ package help; import java.awt.Component; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; +import java.awt.event.*; import java.beans.PropertyChangeListener; import java.net.MalformedURLException; import java.net.URL; @@ -30,8 +29,7 @@ import javax.help.event.HelpModelEvent; import javax.help.plaf.HelpNavigatorUI; import javax.help.plaf.basic.BasicFavoritesCellRenderer; import javax.help.plaf.basic.BasicFavoritesNavigatorUI; -import javax.swing.JComponent; -import javax.swing.JTree; +import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import ghidra.util.Msg; @@ -70,6 +68,28 @@ public class CustomFavoritesView extends FavoritesView { public void setUI(HelpNavigatorUI ui) { super.setUI(new CustomFavoritesNavigatorUI(this)); } + + private Action superGetAddAction() { + return super.getAddAction(); + } + + @Override + public Action getAddAction() { + + // + // Switching themes triggers a UI update. Internally, the Java Help API is not + // correctly updating listeners, which results in that API having a reference to an old + // UI. Using our own custom action to retrieve the currently active action prevents + // this issue, since we are always getting the active target for actionPerformed(). + // + return new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + Action currentAction = superGetAddAction(); + currentAction.actionPerformed(e); + } + }; + } } class CustomFavoritesNavigatorUI extends BasicFavoritesNavigatorUI { diff --git a/Ghidra/Framework/Help/src/main/java/help/CustomTOCView.java b/Ghidra/Framework/Help/src/main/java/help/CustomTOCView.java index 942bffb27d..8b5841137b 100644 --- a/Ghidra/Framework/Help/src/main/java/help/CustomTOCView.java +++ b/Ghidra/Framework/Help/src/main/java/help/CustomTOCView.java @@ -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; @@ -74,6 +74,9 @@ public class CustomTOCView extends TOCView { } public HelpModel getHelpModel() { + if (ui == null) { + return null; + } return ui.getHelpModel(); } @@ -140,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); } @@ -181,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) { diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpBroker.java b/Ghidra/Framework/Help/src/main/java/help/GHelpBroker.java index 2912226ba5..29cafbbe0c 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpBroker.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpBroker.java @@ -24,9 +24,12 @@ import javax.help.*; import javax.swing.*; import javax.swing.text.Document; +import generic.theme.GIcon; import ghidra.util.Msg; import ghidra.util.bean.GGlassPane; -import resources.ResourceManager; +import resources.Icons; +import resources.MultiIconBuilder; +import resources.icons.EmptyIcon; // NOTE: for JH 2.0, this class has been rewritten to not // access the 'frame' and 'dialog' variable directly @@ -38,14 +41,14 @@ import resources.ResourceManager; public class GHelpBroker extends DefaultHelpBroker { // Create the zoom in/out icons that will be added to the default jHelp toolbar. - private static final ImageIcon ZOOM_OUT_ICON = - ResourceManager.loadImage("images/list-remove.png"); - private static final ImageIcon ZOOM_IN_ICON = ResourceManager.loadImage("images/list-add.png"); + private static final Icon ZOOM_OUT_ICON = new GIcon("icon.subtract"); + private static final Icon ZOOM_IN_ICON = Icons.ADD_ICON; private Dimension windowSize = new Dimension(1100, 700); protected JEditorPane htmlEditorPane; private Window activationWindow; + private boolean initialized; /** * Construct a new GhidraHelpBroker. @@ -89,6 +92,22 @@ public class GHelpBroker extends DefaultHelpBroker { } } + public void reload() { + clearHighlights(); + initialized = false; + if (isDisplayed()) { + setDisplayed(false); + setDisplayed(true); + } + } + + private void clearHighlights() { + TextHelpModel helpModel = (TextHelpModel) getCustomHelpModel(); + if (helpModel != null) { + helpModel.removeAllHighlights(); + } + } + protected void showNavigationAid(URL url) { // this base class does not have a navigation aid } @@ -134,7 +153,7 @@ public class GHelpBroker extends DefaultHelpBroker { } private void initializeScreenDevice() { - if (isInitialized()) { + if (initialized) { return; } @@ -179,20 +198,21 @@ public class GHelpBroker extends DefaultHelpBroker { initializeUIComponents(contentPane); } - private boolean isInitialized() { - return htmlEditorPane != null; - } - private void initializeUIComponents(Container contentPane) { - if (isInitialized()) { + if (initialized) { return;// already initialized } Component[] components = contentPane.getComponents(); JHelp jHelp = (JHelp) components[0]; - addCustomToolbarItems(jHelp); JHelpContentViewer contentViewer = jHelp.getContentViewer(); + JEditorPane activeHtmlPane = getHTMLEditorPane(contentViewer); + if (activeHtmlPane == htmlEditorPane && initialized) { + return; // already initialized + } + + addCustomToolbarItems(jHelp); htmlEditorPane = getHTMLEditorPane(contentViewer); // just creating the search wires everything together @@ -203,6 +223,7 @@ public class GHelpBroker extends DefaultHelpBroker { } installActions(jHelp); + initialized = true; } protected void installHelpSearcher(JHelp jHelp, HelpModel helpModel) { @@ -220,7 +241,11 @@ public class GHelpBroker extends DefaultHelpBroker { JToolBar toolbar = (JToolBar) component; toolbar.addSeparator(); - ImageIcon zoomOutIcon = ResourceManager.getScaledIcon(ZOOM_OUT_ICON, 24, 24); + ImageIcon icon = new MultiIconBuilder(new EmptyIcon(24, 24)) + .addCenteredIcon(ZOOM_OUT_ICON) + .build(); + + Icon zoomOutIcon = icon; JButton zoomOutBtn = new JButton(zoomOutIcon); zoomOutBtn.setToolTipText("Zoom out"); zoomOutBtn.addActionListener(e -> { @@ -232,7 +257,10 @@ public class GHelpBroker extends DefaultHelpBroker { }); toolbar.add(zoomOutBtn); - ImageIcon zoomInIcon = ResourceManager.getScaledIcon(ZOOM_IN_ICON, 24, 24); + icon = new MultiIconBuilder(new EmptyIcon(24, 24)) + .addCenteredIcon(ZOOM_IN_ICON) + .build(); + Icon zoomInIcon = icon; JButton zoomInBtn = new JButton(zoomInIcon); zoomInBtn.setToolTipText("Zoom in"); zoomInBtn.addActionListener(e -> { diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java b/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java index d40205bb97..bac98cf874 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java @@ -21,7 +21,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; -import ghidra.GhidraApplicationLayout; +import generic.theme.ApplicationThemeManager; 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 dependencyHelpPaths = new LinkedHashSet(); - private Collection helpInputDirectories = new LinkedHashSet(); + private Collection dependencyHelpPaths = new LinkedHashSet<>(); + private Collection 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() { + ApplicationThemeManager.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 allHelp = new ArrayList(helpInputDirectories); + List allHelp = new ArrayList<>(helpInputDirectories); for (File file : dependencyHelpPaths) { allHelp.add(file); } diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java b/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java index 9598c6100a..937802cdf1 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.ImageIcon; import javax.swing.JEditorPane; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; @@ -35,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; @@ -52,7 +53,8 @@ import utilities.util.FileUtilities; */ public class GHelpHTMLEditorKit extends HTMLEditorKit { - private static final String G_HELP_STYLE_SHEET = "help/shared/Frontpage.css"; + private static final String G_HELP_STYLE_SHEET = "Frontpage.css"; + private static final String DARK_G_HELP_STYLE_SHEET = "DarkStyle.css"; private static final Pattern EXTERNAL_URL_PATTERN = Pattern.compile("https?://.*"); @@ -319,12 +321,21 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { } private URL getGStyleSheetURL() { - URL GStyleSheetURL = ResourceManager.getResource(G_HELP_STYLE_SHEET); - if (GStyleSheetURL != null) { - return GStyleSheetURL; + + if (Gui.isDarkTheme()) { + return findStyleSheet(DARK_G_HELP_STYLE_SHEET); } - return findModuleFile("help/shared/FrontPage.css"); + return findStyleSheet(G_HELP_STYLE_SHEET); + } + + private URL findStyleSheet(String name) { + URL url = ResourceManager.getResource("help/shared/" + name); + if (url != null) { + return url; + } + + return findModuleFile("help/shared/" + name); } private URL findApplicationfile(String relativePath) { @@ -481,6 +492,12 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { } String srcString = src.toString(); + + // check if the srcString is a defined theme icon id + if (Gui.hasIcon(srcString)) { + return new GIcon(srcString).getUrl(); + } + if (isJavaCode(srcString)) { return installImageFromJavaCode(srcString); } @@ -496,8 +513,7 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { return null; } - ImageIcon imageIcon = iconProvider.getIcon(); - this.image = imageIcon.getImage(); + this.image = iconProvider.getImage(); URL url = iconProvider.getOrCreateUrl(); return url; diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java b/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java index 6b1cd1cc22..b847bc8834 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java @@ -54,8 +54,6 @@ import ghidra.util.SystemUtilities; */ public class GHelpSet extends HelpSet { - private static final String HOME_ID = "Misc_Welcome_to_Ghidra_Help"; - /** static map that contains all known help sets in the system. */ private static java.util.Map helpSetsToCombinedMaps = new java.util.HashMap<>(); private static java.util.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 //================================================================================================== diff --git a/Ghidra/Framework/Help/src/main/java/help/HelpApplicationLayout.java b/Ghidra/Framework/Help/src/main/java/help/HelpApplicationLayout.java new file mode 100644 index 0000000000..1872016f53 --- /dev/null +++ b/Ghidra/Framework/Help/src/main/java/help/HelpApplicationLayout.java @@ -0,0 +1,154 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package help; + +import java.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 getAdditionalApplicationRootDirs( + Collection roots) { + return Collections.emptyList(); + } + + protected Map 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 roots = + ModuleUtilities.findModuleRootDirectories(applicationRootDirs, new ArrayList<>()); + Map 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 cpNames = getClassPathModuleNames(); + Map filteredModules = new HashMap<>(); + Set> entrySet = allModules.entrySet(); + for (Entry entry : entrySet) { + GModule module = entry.getValue(); + if (cpNames.contains(module.getName())) { + filteredModules.put(entry.getKey(), module); + } + } + + return filteredModules; + } + + private Set getClassPathModuleNames() { + String cp = System.getProperty("java.class.path"); + String[] pathParts = cp.split(File.pathSeparator); + Set paths = new HashSet<>(Arrays.asList(pathParts)); + Set 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 getDefaultApplicationRootDirs() { + if (SystemUtilities.isInDevelopmentMode()) { + return ApplicationUtilities.findDefaultApplicationRootDirs(); + } + return CollectionUtils.asList(new ResourceFile(System.getProperty("user.dir"))); + } +} diff --git a/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java b/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java index a69d6c6128..965d52c451 100644 --- a/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java +++ b/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java @@ -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. + * + *

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 { diff --git a/Ghidra/Framework/Help/src/main/java/help/HelpService.java b/Ghidra/Framework/Help/src/main/java/help/HelpService.java index bdf2e643be..969c97730a 100644 --- a/Ghidra/Framework/Help/src/main/java/help/HelpService.java +++ b/Ghidra/Framework/Help/src/main/java/help/HelpService.java @@ -113,4 +113,9 @@ public interface HelpService { * initializing */ public boolean helpExists(); + + /** + * Called when a major system even happens, such as changing the system theme. + */ + public void reload(); } diff --git a/Ghidra/Framework/Help/src/main/java/help/screenshot/HelpScreenShotReportGenerator.java b/Ghidra/Framework/Help/src/main/java/help/screenshot/HelpScreenShotReportGenerator.java index e2a93f8d3e..3581859349 100644 --- a/Ghidra/Framework/Help/src/main/java/help/screenshot/HelpScreenShotReportGenerator.java +++ b/Ghidra/Framework/Help/src/main/java/help/screenshot/HelpScreenShotReportGenerator.java @@ -18,6 +18,8 @@ package help.screenshot; import java.io.*; import java.util.*; +import generic.theme.GThemeDefaults.Colors.Palette; + public class HelpScreenShotReportGenerator { // @@ -45,7 +47,7 @@ public class HelpScreenShotReportGenerator { System.out.println("Processing image files: " + images); StringTokenizer tokenizer = new StringTokenizer(images, ","); - List list = new ArrayList(); + List list = new ArrayList<>(); while (tokenizer.hasMoreTokens()) { list.add(tokenizer.nextToken()); } @@ -127,11 +129,11 @@ public class HelpScreenShotReportGenerator { writer.write(" \n"); writer.write(" \n"); writer.write(" \""
\n"); - writer.write("

"+oldFilePath+"
\n"); + writer.write("
"+oldFilePath+"
\n"); writer.write(" \n"); writer.write(" \n"); writer.write(" \""
\n"); - writer.write("
"+newFilePath+"
\n"); + writer.write("
"+newFilePath+"
\n"); writer.write(" \n"); writer.write(" \n"); //@formatter:on @@ -184,11 +186,16 @@ public class HelpScreenShotReportGenerator { writer.write("