diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java index b2d2372137..0f2c6ac04a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java @@ -91,6 +91,10 @@ public class DataTypeManagerHandler { private DataTypeManagerListenerDelegate listenerDelegate; private MyFolderListener folderListener; + // Updated anytime any datatype or category changes in any open archive, including the program + // archive. Currently used by data type tree nodes to know if their tooltip cache is stale. + private long modCount = 0; + public DataTypeManagerHandler(DataTypeManagerPlugin plugin) { this.plugin = plugin; this.tool = plugin.getTool(); @@ -126,6 +130,16 @@ public class DataTypeManagerHandler { tool.getProject().getProjectData().removeDomainFolderChangeListener(folderListener); } + /** + * Returns the current modification count which is incremented anytime any archive or any + * category or datatype it contains is changed in any way. This includes the datatypes in + * the current program. + * @return the current modification id. + */ + public long getModificationCount() { + return modCount; + } + /** * Notification that the given program is open. Add the root category * for the program to any provider that is open. @@ -1138,6 +1152,7 @@ public class DataTypeManagerHandler { @Override public void categoryAdded(DataTypeManager dtm, CategoryPath path) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.categoryAdded(dtm, path); } @@ -1145,6 +1160,7 @@ public class DataTypeManagerHandler { @Override public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.categoryMoved(dtm, oldPath, newPath); } @@ -1152,6 +1168,7 @@ public class DataTypeManagerHandler { @Override public void categoryRemoved(DataTypeManager dtm, CategoryPath path) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.categoryRemoved(dtm, path); } @@ -1160,6 +1177,7 @@ public class DataTypeManagerHandler { @Override public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.categoryRenamed(dtm, oldPath, newPath); } @@ -1167,6 +1185,7 @@ public class DataTypeManagerHandler { @Override public void dataTypeAdded(DataTypeManager dtm, DataTypePath path) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.dataTypeAdded(dtm, path); } @@ -1174,6 +1193,7 @@ public class DataTypeManagerHandler { @Override public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.dataTypeChanged(dtm, path); } @@ -1181,6 +1201,7 @@ public class DataTypeManagerHandler { @Override public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.dataTypeMoved(dtm, oldPath, newPath); } @@ -1188,6 +1209,7 @@ public class DataTypeManagerHandler { @Override public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.dataTypeRemoved(dtm, path); } @@ -1196,6 +1218,7 @@ public class DataTypeManagerHandler { @Override public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.dataTypeRenamed(dtm, oldPath, newPath); } @@ -1204,6 +1227,7 @@ public class DataTypeManagerHandler { @Override public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath, DataType newDataType) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.dataTypeReplaced(dtm, oldPath, newPath, newDataType); } @@ -1211,6 +1235,7 @@ public class DataTypeManagerHandler { @Override public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.favoritesChanged(dtm, path, isFavorite); } @@ -1219,6 +1244,7 @@ public class DataTypeManagerHandler { @Override public void sourceArchiveAdded(DataTypeManager dataTypeManager, SourceArchive dataTypeSource) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.sourceArchiveAdded(dataTypeManager, dataTypeSource); } @@ -1227,6 +1253,7 @@ public class DataTypeManagerHandler { @Override public void sourceArchiveChanged(DataTypeManager dataTypeManager, SourceArchive dataTypeSource) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.sourceArchiveChanged(dataTypeManager, dataTypeSource); } @@ -1234,6 +1261,7 @@ public class DataTypeManagerHandler { @Override public void programArchitectureChanged(DataTypeManager dataTypeManager) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.programArchitectureChanged(dataTypeManager); } @@ -1241,6 +1269,7 @@ public class DataTypeManagerHandler { @Override public void restored(DataTypeManager dataTypeManager) { + modCount++; for (DataTypeManagerChangeListener listener : dataTypeManagerListeners) { listener.restored(dataTypeManager); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java index 555bcd3413..3d0a4e4537 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveRootNode.java @@ -48,6 +48,15 @@ public class ArchiveRootNode extends DataTypeTreeNode { return archiveManager; } + /** + * Returns the modification count for any changes to any category or datatype in any + * open archive including the program. + * @return the modification count + */ + public long getModificationCount() { + return archiveManager.getModificationCount(); + } + public void setFilterState(DtFilterState dtFilterState) { this.dtFilterState = dtFilterState; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java index 0b1d25cab4..b6ceb9564a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeNode.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. @@ -40,7 +40,8 @@ public class DataTypeNode extends DataTypeTreeNode { private boolean useHighlight = false; private String toolTipText; - private long toolTipTimestamp; + // records the root node's mod count at the last time we computed the tooltip text. + private long lastModCount; public DataTypeNode(DataType dataType) { this.dataType = dataType; @@ -108,21 +109,30 @@ public class DataTypeNode extends DataTypeTreeNode { @Override public String getToolTip() { - - DataType baseType = DataTypeUtils.getBaseDataType(dataType); - long lastChangeTime = baseType.getLastChangeTime(); - if (lastChangeTime > toolTipTimestamp) { + if (archiveChanged()) { toolTipText = null; } if (toolTipText == null) { toolTipText = ToolTipUtils.getToolTipText(dataType); - toolTipTimestamp = lastChangeTime; } return toolTipText; } + private boolean archiveChanged() { + GTreeNode root = getRoot(); + if (root instanceof ArchiveRootNode archiveRootNode) { + long modCount = archiveRootNode.getModificationCount(); + if (lastModCount == modCount) { + return false; + } + lastModCount = modCount; + return true; + } + return false; + } + @Override public boolean isLeaf() { return true;