GP-835 - reduced the amount of work done by the Defined Strings table

Closes #2889
This commit is contained in:
dragonmacher 2021-04-02 17:02:27 -04:00
parent 472ad40077
commit 316ab7c5ab
3 changed files with 52 additions and 41 deletions

View file

@ -71,6 +71,12 @@
option, OR</li> option, OR</li>
<li>Select the <img src="Icons.REFRESH_ICON">button on the tool bar.</li> <li>Select the <img src="Icons.REFRESH_ICON">button on the tool bar.</li>
</ul> </ul>
<p><img border="0" src="../../shared/note.png">The refresh icon on the toolbar will
appear grayed-out by default. If potential changes to string data are detected,
the icon will become green in color. The toolbar button can be pressed in either state
for a full table reload.
</blockquote> </blockquote>
<h3><a name="Settings___"></a><a name="Default_Settings___"></a>Settings... and Default Settings...</h3> <h3><a name="Settings___"></a><a name="Default_Settings___"></a>Settings... and Default Settings...</h3>

View file

@ -15,12 +15,11 @@
*/ */
package ghidra.app.plugin.core.strings; package ghidra.app.plugin.core.strings;
import javax.swing.ImageIcon; import javax.swing.Icon;
import docking.ActionContext; import docking.ActionContext;
import docking.action.*; import docking.action.*;
import ghidra.app.CorePluginPackage; import ghidra.app.CorePluginPackage;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin; import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.plugin.core.data.DataSettingsDialog; import ghidra.app.plugin.core.data.DataSettingsDialog;
@ -38,6 +37,7 @@ import ghidra.util.table.SelectionNavigationAction;
import ghidra.util.table.actions.MakeProgramSelectionAction; import ghidra.util.table.actions.MakeProgramSelectionAction;
import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.SwingUpdateManager;
import resources.Icons; import resources.Icons;
import resources.ResourceManager;
/** /**
* Plugin that provides the "Defined Strings" table, where all the currently defined * Plugin that provides the "Defined Strings" table, where all the currently defined
@ -57,7 +57,11 @@ import resources.Icons;
//@formatter:on //@formatter:on
public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectListener { public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectListener {
private DockingAction selectAction; private static Icon REFRESH_ICON = Icons.REFRESH_ICON;
private static Icon REFRESH_NOT_NEEDED_ICON =
ResourceManager.getDisabledIcon(Icons.REFRESH_ICON, 60);
private DockingAction refreshAction;
private DockingAction showSettingsAction; private DockingAction showSettingsAction;
private DockingAction showDefaultSettingsAction; private DockingAction showDefaultSettingsAction;
private SelectionNavigationAction linkNavigationAction; private SelectionNavigationAction linkNavigationAction;
@ -82,7 +86,7 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
} }
private void createActions() { private void createActions() {
DockingAction refreshAction = new DockingAction("Refresh Strings", getName()) { refreshAction = new DockingAction("Refresh Strings", getName()) {
@Override @Override
public boolean isEnabledForContext(ActionContext context) { public boolean isEnabledForContext(ActionContext context) {
@ -91,12 +95,14 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
getToolBarData().setIcon(REFRESH_NOT_NEEDED_ICON);
reload(); reload();
} }
}; };
ImageIcon refreshIcon = Icons.REFRESH_ICON; refreshAction.setToolBarData(new ToolBarData(REFRESH_NOT_NEEDED_ICON));
refreshAction.setDescription("Reloads all string data from the program"); refreshAction.setDescription(
refreshAction.setToolBarData(new ToolBarData(refreshIcon)); "<html>Push at any time to refresh the current table of strings.<br>" +
"This button is highlighted when the data <i>may</i> be stale.<br>");
refreshAction.setHelpLocation(new HelpLocation("ViewStringsPlugin", "Refresh")); refreshAction.setHelpLocation(new HelpLocation("ViewStringsPlugin", "Refresh"));
tool.addLocalAction(provider, refreshAction); tool.addLocalAction(provider, refreshAction);
@ -152,13 +158,6 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
} }
private void selectData(ProgramSelection selection) {
ProgramSelectionPluginEvent pspe =
new ProgramSelectionPluginEvent("Selection", selection, currentProgram);
firePluginEvent(pspe);
processEvent(pspe);
}
@Override @Override
public void dispose() { public void dispose() {
reloadUpdateMgr.dispose(); reloadUpdateMgr.dispose();
@ -186,23 +185,28 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
} }
} }
private void markDataAsStale() {
provider.getComponent().repaint();
refreshAction.getToolBarData().setIcon(REFRESH_ICON);
}
@Override @Override
public void domainObjectChanged(DomainObjectChangedEvent ev) { public void domainObjectChanged(DomainObjectChangedEvent ev) {
if (ev.containsEvent(DomainObject.DO_OBJECT_RESTORED) || if (ev.containsEvent(DomainObject.DO_OBJECT_RESTORED) ||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_MOVED) || ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_MOVED) ||
ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED) || ev.containsEvent(ChangeManager.DOCR_MEMORY_BLOCK_REMOVED) ||
ev.containsEvent(ChangeManager.DOCR_CODE_REMOVED) ||
ev.containsEvent(ChangeManager.DOCR_DATA_TYPE_CHANGED)) { ev.containsEvent(ChangeManager.DOCR_DATA_TYPE_CHANGED)) {
reload(); markDataAsStale();
return;
} }
else if (ev.containsEvent(ChangeManager.DOCR_CODE_ADDED)) {
for (int i = 0; i < ev.numRecords(); ++i) { for (int i = 0; i < ev.numRecords(); ++i) {
DomainObjectChangeRecord doRecord = ev.getChangeRecord(i); DomainObjectChangeRecord doRecord = ev.getChangeRecord(i);
Object newValue = doRecord.getNewValue(); Object newValue = doRecord.getNewValue();
switch (doRecord.getEventType()) { switch (doRecord.getEventType()) {
case ChangeManager.DOCR_CODE_REMOVED: case ChangeManager.DOCR_CODE_REMOVED:
case ChangeManager.DOCR_COMPOSITE_ADDED:
ProgramChangeRecord pcRec = (ProgramChangeRecord) doRecord; ProgramChangeRecord pcRec = (ProgramChangeRecord) doRecord;
provider.remove(pcRec.getStart(), pcRec.getEnd()); provider.remove(pcRec.getStart(), pcRec.getEnd());
break; break;
@ -216,15 +220,15 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
break; break;
} }
} }
}
else if (ev.containsEvent(ChangeManager.DOCR_DATA_TYPE_SETTING_CHANGED)) { if (ev.containsEvent(ChangeManager.DOCR_DATA_TYPE_SETTING_CHANGED)) {
// Unusual code: because the table model goes directly to the settings values // Unusual code: because the table model goes directly to the settings values
// during each repaint, we don't need to figure out which row was changed. // during each repaint, we don't need to figure out which row was changed.
provider.getComponent().repaint(); provider.getComponent().repaint();
} }
} }
void reload() { private void reload() {
reloadUpdateMgr.update(); reloadUpdateMgr.update();
} }
} }

View file

@ -162,7 +162,7 @@ public class StringDataInstance {
return ((AbstractStringDataType) dt).getStringDataInstance(data, data, return ((AbstractStringDataType) dt).getStringDataInstance(data, data,
data.getLength()); data.getLength());
} }
if (dt instanceof Array && !data.isInitializedMemory()) { if (dt instanceof Array && data.isInitializedMemory()) {
ArrayStringable arrayStringable = ArrayStringable arrayStringable =
ArrayStringable.getArrayStringable(((Array) dt).getDataType()); ArrayStringable.getArrayStringable(((Array) dt).getDataType());
if (arrayStringable != null && arrayStringable.hasStringValue(data)) { if (arrayStringable != null && arrayStringable.hasStringValue(data)) {
@ -918,7 +918,8 @@ public class StringDataInstance {
if (byteOffset + charSize > stringBytes.length) { if (byteOffset + charSize > stringBytes.length) {
return false; return false;
} }
long origCodePointValue = DataConverter.getInstance(buf.isBigEndian()).getValue(stringBytes, long origCodePointValue = DataConverter.getInstance(buf.isBigEndian())
.getValue(stringBytes,
byteOffset, charSize); byteOffset, charSize);
return origCodePointValue == StringUtilities.UNICODE_REPLACEMENT; return origCodePointValue == StringUtilities.UNICODE_REPLACEMENT;
} }