GP-2076 domain object event refactor

This commit is contained in:
ghidragon 2024-01-10 12:01:03 -05:00
parent daca354c47
commit 856aa904aa
143 changed files with 3621 additions and 3652 deletions

View file

@ -156,7 +156,7 @@ public abstract class DomainObjectAdapter implements DomainObject {
name = newName;
changed = true;
}
fireEvent(new DomainObjectChangeRecord(DO_OBJECT_RENAMED));
fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RENAMED));
}
private void clearDomainObj() {
@ -195,7 +195,7 @@ public abstract class DomainObjectAdapter implements DomainObject {
clearDomainObj();
DomainFile oldDf = domainFile;
domainFile = df;
fireEvent(new DomainObjectChangeRecord(DO_DOMAIN_FILE_CHANGED, oldDf, df));
fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.FILE_CHANGED, oldDf, df));
fileChangeListeners.invoke().domainFileChanged(this);
}
@ -314,7 +314,8 @@ public abstract class DomainObjectAdapter implements DomainObject {
if (eventsEnabled != v) {
eventsEnabled = v;
if (eventsEnabled) {
DomainObjectChangeRecord docr = new DomainObjectChangeRecord(DO_OBJECT_RESTORED);
DomainObjectChangeRecord docr =
new DomainObjectChangeRecord(DomainObjectEvent.RESTORED);
docs.fireEvent(docr);
for (DomainObjectChangeSupport queue : changeSupportMap.values()) {
queue.fireEvent(docr);

View file

@ -477,8 +477,8 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter
*/
protected boolean propertyChanged(String propertyName, Object oldValue, Object newValue) {
setChanged(true);
fireEvent(
new DomainObjectChangeRecord(DomainObject.DO_PROPERTY_CHANGED, propertyName, newValue));
fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.PROPERTY_CHANGED, propertyName,
newValue));
return true;
}
@ -534,7 +534,7 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter
}
if (wasSaved) {
fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_SAVED));
fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.SAVED));
DomainFile df = getDomainFile();
if (df instanceof GhidraFile) {

View file

@ -190,7 +190,7 @@ class DomainObjectChangeSupport {
Runnable errorTask = () -> {
List<DomainObjectChangeRecord> records =
Arrays.asList(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_ERROR, null, t));
Arrays.asList(new DomainObjectChangeRecord(DomainObjectEvent.ERROR, null, t));
DomainObjectChangedEvent ev = new DomainObjectChangedEvent(src, records);
for (DomainObjectListener l : listenersCopy) {
try {

View file

@ -92,7 +92,7 @@ class DomainObjectTransactionManager extends AbstractTransactionManager {
domainObj.clearCache(false);
}
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED));
if (notify) {
notifyEndTransaction();
}
@ -182,7 +182,7 @@ class DomainObjectTransactionManager extends AbstractTransactionManager {
if (notify) {
notifyEndTransaction();
}
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED));
transaction.restoreToolStates(true);
transaction = null;
}
@ -272,7 +272,7 @@ class DomainObjectTransactionManager extends AbstractTransactionManager {
if (domainObj.changeSet != null) {
domainObj.changeSet.redo();
}
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED));
undoList.addLast(t);
t.restoreToolStates(false);
if (notify) {
@ -291,7 +291,7 @@ class DomainObjectTransactionManager extends AbstractTransactionManager {
domainObj.changeSet.undo();
}
domainObj.clearCache(false);
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
domainObj.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED));
redoList.addLast(t);
t.restoreToolStates(true);
if (notify) {

View file

@ -31,48 +31,69 @@ import ghidra.util.task.TaskMonitor;
* data objects that are persistent. <CODE>DomainObject</CODE>s maintain an
* association with a <CODE>DomainFile</CODE>. A <CODE>DomainObject</CODE> that
* has never been saved will have a null <CODE>DomainFile</CODE>.
* <P>
* Note: Previously (before 11.1), domain object change event types were defined in this file as
* integer constants. Event ids have since been converted to enum types. The defines in this file
* have been converted to point to the new enum values to make it easier to convert to this new way
* and to clearly see how the old values map to the new enums. In future releases, these defines
* will be removed.
*/
public interface DomainObject {
/**
* Event type generated when the domain object is saved.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public final static EventType DO_OBJECT_SAVED = DomainObjectEvent.SAVED;
/**
* Event type generated when the domain file associated with
* the domain object changes.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public final static EventType DO_DOMAIN_FILE_CHANGED = DomainObjectEvent.FILE_CHANGED;
/**
* Event type generated when the object name changes.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public final static EventType DO_OBJECT_RENAMED = DomainObjectEvent.RENAMED;
/**
* Event type generated when domain object is restored.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public static final EventType DO_OBJECT_RESTORED = DomainObjectEvent.RESTORED;
/**
* Event type generated when a property on this DomainObject is changed.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public static final EventType DO_PROPERTY_CHANGED = DomainObjectEvent.PROPERTY_CHANGED;
/**
* Event type generated when this domain object is closed.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public static final EventType DO_OBJECT_CLOSED = DomainObjectEvent.CLOSED;
/**
* Event type generated when a fatal error occurs which renders the domain object invalid.
* @deprecated Event type numeric constants have been changed to enums. Use the enum directly.
*/
@Deprecated
public static final EventType DO_OBJECT_ERROR = DomainObjectEvent.ERROR;
/**
* Object to synchronize on for undo/redo operations.
*/
public final static Object undoLock = new Object();
/**
* Event type generated when the domain object is saved.
*/
public final static int DO_OBJECT_SAVED = 1;
/**
* Event type generated when the domain file associated with
* the domain object changes.
*/
public final static int DO_DOMAIN_FILE_CHANGED = 2;
/**
* Event type generated when the object name changes.
*/
public final static int DO_OBJECT_RENAMED = 3;
/**
* Event type generated when domain object is restored.
*/
public static final int DO_OBJECT_RESTORED = 4;
/**
* Event type generated when a property on this DomainObject is changed.
*/
public static final int DO_PROPERTY_CHANGED = 5;
/**
* Event type generated when this domain object is closed.
*/
public static final int DO_OBJECT_CLOSED = 6;
/**
* Event type generated when a fatal error occurs which renders the domain object invalid.
*/
public static final int DO_OBJECT_ERROR = 8;
/**
* Returns whether the object has changed.

View file

@ -19,82 +19,58 @@ import java.io.Serializable;
/**
* Information about a change that was made to a domain object. The
* record is delivered as part of the change notification. The event
* types correspond to the constants in
* {@link ghidra.program.util.ChangeManager ChangeManager}.
* @see ghidra.program.util.ChangeManager ChangeManager
* record is delivered as part of the change notification. The event types
* correspond to Enums defined in {@link DomainObjectEvent} and
* other Enums or objects that implement the {@link EventType} interface.
*
* Each event record contains the event type and optionally an old value and a new value.
* The old value and new value meaning are determined by the event type.
*/
public class DomainObjectChangeRecord implements Serializable {
private final static long serialVersionUID = 1;
private int eventType;
private int subEventType;
private EventType eventType;
private Object oldValue;
private Object newValue;
/**
* Construct a new DomainObjectChangeRecord.
* @param eventType the type of event
*/
public DomainObjectChangeRecord() {
this(0, 0, null, null);
public DomainObjectChangeRecord(EventType eventType) {
this(eventType, null, null);
}
/**
* Construct a new DomainObjectChangeRecord.
* @param type event type
*/
public DomainObjectChangeRecord(int type) {
this(type, 0, null, null);
}
/**
* Construct a new DomainObjectChangeRecord.
* @param type event type
* @param eventType the type of
* @param oldValue old value
* @param newValue new value
*/
public DomainObjectChangeRecord(int type, Object oldValue, Object newValue) {
this(type, 0, oldValue, newValue);
}
/**
* Construct a new DomainObjectChangeRecord.
* @param type event type
* @param subType sub-event type (use 0 if unspecified)
* @param oldValue old value
* @param newValue new value
*/
public DomainObjectChangeRecord(int type, int subType, Object oldValue, Object newValue) {
eventType = type;
subEventType = subType;
public DomainObjectChangeRecord(EventType eventType, Object oldValue, Object newValue) {
this.eventType = eventType;
this.oldValue = oldValue;
this.newValue = newValue;
}
/**
* Return the event type for this change record.
* Returns the event type for this change.
* @return the event type for this change
*/
public int getEventType() {
public EventType getEventType() {
return eventType;
}
/**
* Return the sub-event type for this change record.
* A value of 0 is the default if unspecified.
*/
public int getSubEventType() {
return subEventType;
}
/**
* Return the old value.
* Return the old value for this event or null if not applicable.
* @return the old value or null if not applicable
*/
public Object getOldValue() {
return oldValue;
}
/**
* Return the new value.
* Return the new value for this event or null if not applicable.
* @return the old value or null if not applicable for this event.
*/
public Object getNewValue() {
return newValue;
@ -102,13 +78,18 @@ public class DomainObjectChangeRecord implements Serializable {
@Override
public String toString() {
//@formatter:off
return "{\n" +
"\tnewValue: " + newValue + ",\n" +
"\toldValue: " + oldValue + ",\n" +
"\teventType: " + eventType + ",\n" +
"\tsubEventType: " + subEventType + "\n" +
"\n}";
//@formatter:on
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(": event = ");
buf.append(eventType);
if (oldValue != null) {
buf.append(", old = ");
buf.append(oldValue);
}
if (newValue != null) {
buf.append(", new = ");
buf.append(newValue);
}
return buf.toString();
}
}

View file

@ -16,6 +16,7 @@
package ghidra.framework.model;
import java.util.*;
import java.util.function.Consumer;
/**
* An event indicating a DomainObject has changed. This event is actually
@ -45,19 +46,52 @@ public class DomainObjectChangedEvent extends EventObject
super(src);
this.subEvents = subEvents;
for (DomainObjectChangeRecord record : subEvents) {
eventBits.set(record.getEventType());
eventBits.set(record.getEventType().getId());
}
}
/**
* Return the number of change records contained within this event.
* @return the number of change records contained within this event
*/
public int numRecords() {
return subEvents.size();
}
public boolean containsEvent(int eventType) {
return eventBits.get(eventType);
/**
* Returns true if this event contains a record with the given event type
* @param eventType the event type to check
* @return the number of change records contained within this event.
*/
public boolean contains(EventType eventType) {
return eventBits.get(eventType.getId());
}
/**
* Returns true if this event contains a record with any of the given event types.
* @param types the event types to check for
* @return true if this event contains a record with any of the given event types
*/
public boolean contains(EventType... types) {
for (EventType eventType : types) {
if (eventBits.get(eventType.getId())) {
return true;
}
}
return false;
}
/**
* Returns true if this event contains a record with the given event type.
* @param eventType the event type to check
* @return the number of change records contained within this event.
* @deprecated use {@link #contains(EventType)} instead. This is here to help
* transition older code from using integer constants for even types to the new enum way
* that uses enums instead.
*/
@Deprecated
public boolean containsEvent(EventType eventType) {
return eventBits.get(eventType.getId());
}
/**
@ -76,4 +110,21 @@ public class DomainObjectChangedEvent extends EventObject
public Iterator<DomainObjectChangeRecord> iterator() {
return subEvents.iterator();
}
/**
* Loops over all records in this event and calls the consumer for each record that matches
* the given type.
* @param type the event type to apply the consumer
* @param consumer the consumer to call for each record of the given type
*/
public void forEach(EventType type, Consumer<DomainObjectChangeRecord> consumer) {
if (!contains(type)) {
return;
}
for (DomainObjectChangeRecord docr : subEvents) {
if (docr.getEventType() == type) {
consumer.accept(docr);
}
}
}
}

View file

@ -0,0 +1,37 @@
/* ###
* 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.model;
/**
* Basic event types for all Domain Objects.
*/
public enum DomainObjectEvent implements EventType {
SAVED, // the DomainObject was saved
FILE_CHANGED, // the associated DomainFile changed (file moved, renamed, etc.)
RENAMED, // the DomainObject was renamed
RESTORED, // the DomainObject was changed, all data should be assumed stale
PROPERTY_CHANGED, // a generic property of this DomainObject changed
CLOSED, // the DomainObject was closed
ERROR; // a fatal error occurred
private final int id = DomainObjectEventIdGenerator.next();
@Override
public int getId() {
return id;
}
}

View file

@ -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 ghidra.framework.model;
/**
* Class for providing unique, compact ids for domain object event types.
*/
public class DomainObjectEventIdGenerator {
private static int nextId = 0;
public synchronized static int next() {
return ++nextId;
}
}

View file

@ -0,0 +1,39 @@
/* ###
* 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.model;
/**
* Interface for objects that represent event types. This interface has only one method and that
* method exists to facilitate fast checking if an event type is present in a collection of events.
* The value returned from getId() is arbitrary and can change from run to run. Its only purpose
* is to give each event type a unique compact id that can be used as an index into a bit set. It is
* important that implementers of this interface get their id values by calling
* {@link DomainObjectEventIdGenerator#next()} so that all event ids are coordinated and as
* small as possible.
* <P>
* The preferred implementation of EventType is an enum that enumerates the valid event types
* for any application sub-system. See {@link DomainObjectEvent} for an example implementation.
*
*/
public interface EventType {
/**
* Returns the unique id assigned to this event type. The value is guaranteed to be constant
* for any given run of the application, but can vary from run to run.
* @return the unique event id assigned to this EventType.
*/
public int getId();
}