mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/GP-5826-dragonmacher-symbol-tree-flickering'
This commit is contained in:
commit
4d6bb0ddaa
3 changed files with 57 additions and 13 deletions
|
@ -605,15 +605,17 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
|||
// @formatter:off
|
||||
return new DomainObjectListenerBuilder(this)
|
||||
.ignoreWhen(this::ignoreEvents)
|
||||
.any(RESTORED).terminate(this::reloadTree)
|
||||
.any(RESTORED).terminate(this::reloadTree)
|
||||
.with(ProgramChangeRecord.class)
|
||||
.each(SYMBOL_RENAMED).call(this::processSymbolRenamed)
|
||||
.each(SYMBOL_DATA_CHANGED, SYMBOL_SCOPE_CHANGED).call(this::processSymbolChanged)
|
||||
.each(FUNCTION_CHANGED).call(this::processFunctionChanged)
|
||||
.each(SYMBOL_ADDED).call(this::processSymbolAdded)
|
||||
.each(SYMBOL_REMOVED).call(this::processSymbolRemoved)
|
||||
.each(EXTERNAL_ENTRY_ADDED, EXTERNAL_ENTRY_REMOVED)
|
||||
.call(this::processExternalEntryChanged)
|
||||
|
||||
// handle function changes specially so that we can perform coalesce changes
|
||||
.any(FUNCTION_CHANGED).call(this::processAllFunction)
|
||||
.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
@ -626,10 +628,24 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
|||
symbolRemoved((Symbol) pcr.getObject());
|
||||
}
|
||||
|
||||
private void processFunctionChanged(ProgramChangeRecord pcr) {
|
||||
Function function = (Function) pcr.getObject();
|
||||
Symbol symbol = function.getSymbol();
|
||||
symbolChanged(symbol);
|
||||
private void processAllFunction(DomainObjectChangedEvent e) {
|
||||
|
||||
// grab all function records and remove duplicates so that we can make 1 task for all
|
||||
// changes to a given function
|
||||
Set<Symbol> symbols = new HashSet<>();
|
||||
int n = e.numRecords();
|
||||
for (int i = 0; i < n; i++) {
|
||||
DomainObjectChangeRecord r = e.getChangeRecord(i);
|
||||
if (r instanceof FunctionChangeRecord fcr) {
|
||||
Function f = fcr.getFunction();
|
||||
Symbol s = f.getSymbol();
|
||||
symbols.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
for (Symbol s : symbols) {
|
||||
symbolChanged(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void processSymbolChanged(ProgramChangeRecord pcr) {
|
||||
|
@ -851,5 +867,4 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
|||
task.run(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import docking.widgets.tree.GTree;
|
|||
import docking.widgets.tree.GTreeNode;
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GColorUIResource;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
|
||||
public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent {
|
||||
|
||||
|
@ -71,10 +70,16 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent
|
|||
GTreeNode node = (GTreeNode) value;
|
||||
String text = node.getDisplayText();
|
||||
setText(text);
|
||||
|
||||
String toolTip = node.getToolTip();
|
||||
setToolTipText(toolTip);
|
||||
String fromHTML = HTMLUtilities.fromHTML(toolTip);
|
||||
getAccessibleContext().setAccessibleDescription(fromHTML);
|
||||
|
||||
// Note: attempting to use the tooltip text here by removing the html formatting can be
|
||||
// too slow for large functions. Also, the full preview text for larger symbol tool tips
|
||||
// can be overwhelming for screen readers. The text of the node is a reasonable value
|
||||
// to provide for screen readers.
|
||||
// String fromHTML = HTMLUtilities.fromHTML(toolTip);
|
||||
getAccessibleContext().setAccessibleDescription(node.getDisplayText());
|
||||
|
||||
Icon icon = getNodeIcon(node, expanded);
|
||||
if (icon == null) {
|
||||
|
|
|
@ -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,6 +21,7 @@ import java.util.function.*;
|
|||
import ghidra.util.Msg;
|
||||
import utilities.util.reflection.ReflectionUtilities;
|
||||
import utility.function.Callback;
|
||||
import utility.function.Dummy;
|
||||
|
||||
/**
|
||||
* Base class for creating a compact and efficient {@link DomainObjectListener}s. See
|
||||
|
@ -33,6 +34,7 @@ import utility.function.Callback;
|
|||
public abstract class AbstractDomainObjectListenerBuilder<R extends DomainObjectChangeRecord, B extends AbstractDomainObjectListenerBuilder<R, B>> {
|
||||
private String name;
|
||||
private BooleanSupplier ignoreCheck;
|
||||
private Consumer<DomainObjectChangedEvent> debugConsumer;
|
||||
private List<EventTrigger> terminateList = new ArrayList<>();
|
||||
private List<EventTrigger> onAnyList = new ArrayList<>();
|
||||
private Map<EventType, TypedRecordConsumer<? extends DomainObjectChangeRecord>> onEachMap =
|
||||
|
@ -63,6 +65,17 @@ public abstract class AbstractDomainObjectListenerBuilder<R extends DomainObject
|
|||
|
||||
protected abstract B self();
|
||||
|
||||
/**
|
||||
* Sets a consumer of events that is intended to be used for clients to add a callback for each
|
||||
* event. This is useful for temporarily inspecting events and adding breakpoints.
|
||||
* @param consumer the consumer to add
|
||||
* @return this builder (for chaining)
|
||||
*/
|
||||
public B debug(Consumer<DomainObjectChangedEvent> consumer) {
|
||||
this.debugConsumer = consumer;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a boolean supplier that can be checked to see if the client is in a state where
|
||||
* they don't want events to be processed at this time.
|
||||
|
@ -121,6 +134,7 @@ public abstract class AbstractDomainObjectListenerBuilder<R extends DomainObject
|
|||
|
||||
BuilderDomainObjectListener listener = new BuilderDomainObjectListener(name);
|
||||
listener.setIgnoreCheck(ignoreCheck);
|
||||
listener.setDebugConsumer(debugConsumer);
|
||||
if (!terminateList.isEmpty()) {
|
||||
listener.setTerminateList(terminateList);
|
||||
}
|
||||
|
@ -306,10 +320,11 @@ public abstract class AbstractDomainObjectListenerBuilder<R extends DomainObject
|
|||
static class BuilderDomainObjectListener implements DomainObjectListener {
|
||||
private String name;
|
||||
private BooleanSupplier ignoreCheck = () -> false;
|
||||
private Consumer<DomainObjectChangedEvent> debugConsumer = Dummy.consumer();
|
||||
private List<EventTrigger> terminateList;
|
||||
private List<EventTrigger> onAnyList;
|
||||
private Map<EventType, TypedRecordConsumer<? extends DomainObjectChangeRecord>> onEachMap;
|
||||
private EventType[] eachEventTypes; // all the "onEach" event types
|
||||
private EventType[] eachEventTypes; // all the "onEach" event types
|
||||
|
||||
BuilderDomainObjectListener(String name) {
|
||||
this.name = name;
|
||||
|
@ -323,6 +338,10 @@ public abstract class AbstractDomainObjectListenerBuilder<R extends DomainObject
|
|||
this.ignoreCheck = supplier != null ? supplier : () -> false;
|
||||
}
|
||||
|
||||
void setDebugConsumer(Consumer<DomainObjectChangedEvent> debugConsumer) {
|
||||
this.debugConsumer = Dummy.ifNull(debugConsumer);
|
||||
}
|
||||
|
||||
void setTerminateList(List<EventTrigger> terminatEventList) {
|
||||
this.terminateList = terminatEventList;
|
||||
}
|
||||
|
@ -339,10 +358,15 @@ public abstract class AbstractDomainObjectListenerBuilder<R extends DomainObject
|
|||
|
||||
@Override
|
||||
public void domainObjectChanged(DomainObjectChangedEvent event) {
|
||||
|
||||
// a way for clients to add conditional debug, print statements and breakpoints
|
||||
debugConsumer.accept(event);
|
||||
|
||||
// check if events are being ignored
|
||||
if (ignoreCheck.getAsBoolean()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check for terminating events first
|
||||
if (terminateList != null && processTerminateList(event)) {
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue