GP-3764 - Added the ability to filter only on Data Type names

This commit is contained in:
dragonmacher 2023-09-27 15:30:24 -04:00
parent ed4604fde1
commit d6f4cd052e
6 changed files with 130 additions and 18 deletions

View File

@ -327,6 +327,13 @@
fields of <TT>Enum</TT> names and values, and <TT>Function</TT> parameter data types and fields of <TT>Enum</TT> names and values, and <TT>Function</TT> parameter data types and
names. You may turn this feature off if you find that your search yields too many results names. You may turn this feature off if you find that your search yields too many results
for data types that have common names, such as <TT>byte</TT>.</P> for data types that have common names, such as <TT>byte</TT>.</P>
<A name="Filter_Name_Only"></A>
<P>The <B>Filter on Name Only</B> action, when toggled on, will trigger the
filter field to search only using data type names. When toggled off, filtering will
be done using the display text of the node, which may include additional information, such
as an associated archive.
</P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H2><A name="conflict_mode"></A>Data Type Conflict Resolution Mode</H2> <H2><A name="conflict_mode"></A>Data Type Conflict Resolution Mode</H2>

View File

@ -94,7 +94,9 @@ public class DataTypesProvider extends ComponentProviderAdapter {
private ToggleDockingAction filterPointersAction; private ToggleDockingAction filterPointersAction;
private ToggleDockingAction previewWindowAction; private ToggleDockingAction previewWindowAction;
private ToggleDockingAction includeDataMembersInSearchAction; private ToggleDockingAction includeDataMembersInSearchAction;
private FilterOnNameOnlyAction filterOnNameOnlyAction;
private boolean includeDataMembersInFilter; private boolean includeDataMembersInFilter;
private boolean filterOnNameOnly;
public DataTypesProvider(DataTypeManagerPlugin plugin, String providerName) { public DataTypesProvider(DataTypeManagerPlugin plugin, String providerName) {
this(plugin, providerName, false); this(plugin, providerName, false);
@ -199,6 +201,9 @@ public class DataTypesProvider extends ComponentProviderAdapter {
includeDataMembersInSearchAction = new IncludeDataTypesInFilterAction(plugin, this, "5"); includeDataMembersInSearchAction = new IncludeDataTypesInFilterAction(plugin, this, "5");
addLocalAction(includeDataMembersInSearchAction); addLocalAction(includeDataMembersInSearchAction);
filterOnNameOnlyAction = new FilterOnNameOnlyAction(plugin, this, "6");
addLocalAction(filterOnNameOnlyAction);
addLocalAction(new ApplyFunctionDataTypesAction(plugin)); // Tree addLocalAction(new ApplyFunctionDataTypesAction(plugin)); // Tree
addLocalAction(new CaptureFunctionDataTypesAction(plugin)); // Tree addLocalAction(new CaptureFunctionDataTypesAction(plugin)); // Tree
addLocalAction(new SetFavoriteDataTypeAction(plugin)); // Data Type addLocalAction(new SetFavoriteDataTypeAction(plugin)); // Data Type
@ -820,23 +825,24 @@ public class DataTypesProvider extends ComponentProviderAdapter {
return selectedDataTypes; return selectedDataTypes;
} }
// this is a callback from the action--we need this to prevent callbacks, as the other // this is called from the action
// version of this method will update the action, which would trigger a callback
public void setIncludeDataTypeMembersInFilterCallback(boolean newValue) { public void setIncludeDataTypeMembersInFilterCallback(boolean newValue) {
includeDataMembersInFilter = newValue; includeDataMembersInFilter = newValue;
archiveGTree.setIncludeDataTypeMembersInSearch(includeDataMembersInFilter); archiveGTree.updateDataTransformer(this);
}
// this is called from the action
public void setFilterOnNameOnlyCallback(boolean newValue) {
filterOnNameOnly = newValue;
archiveGTree.updateDataTransformer(this);
} }
public void setIncludeDataTypeMembersInFilter(boolean newValue) { public void setIncludeDataTypeMembersInFilter(boolean newValue) {
includeDataMembersInFilter = newValue; includeDataMembersInSearchAction.setSelected(newValue);
archiveGTree.setIncludeDataTypeMembersInSearch(includeDataMembersInFilter); }
// make sure the action is in sync public void setFilterOnNameOnly(boolean newValue) {
ToggleDockingAction action = includeDataMembersInSearchAction; filterOnNameOnlyAction.setSelected(newValue);
boolean selected = action.isSelected();
if (selected != includeDataMembersInFilter) {
action.setSelected(includeDataMembersInFilter);
}
} }
public void setFilteringArrays(boolean b) { public void setFilteringArrays(boolean b) {
@ -847,10 +853,14 @@ public class DataTypesProvider extends ComponentProviderAdapter {
archiveGTree.enablePointerFilter(b); archiveGTree.enablePointerFilter(b);
} }
boolean includeDataMembersInSearch() { public boolean isIncludeDataMembersInSearch() {
return includeDataMembersInFilter; return includeDataMembersInFilter;
} }
public boolean isFilterOnNameOnly() {
return filterOnNameOnly;
}
@Override @Override
public JComponent getComponent() { public JComponent getComponent() {
return splitPane; return splitPane;
@ -978,4 +988,5 @@ public class DataTypesProvider extends ComponentProviderAdapter {
navigationHistory.add(new DataTypeUrl(dt)); navigationHistory.add(new DataTypeUrl(dt));
contextChanged(); contextChanged();
} }
} }

View File

@ -0,0 +1,54 @@
/* ###
* 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.datamgr;
import docking.action.MenuData;
import docking.action.ToggleDockingAction;
import docking.widgets.tree.GTreeNode;
import ghidra.util.HelpLocation;
/**
* Allows user to filter on only the data type name. When off, all information returned by
* {@link GTreeNode#getDisplayText()} is used for filtering.
*/
public class FilterOnNameOnlyAction extends ToggleDockingAction {
private final DataTypesProvider provider;
public FilterOnNameOnlyAction(DataTypeManagerPlugin plugin, DataTypesProvider provider,
String menuSubGroup) {
super("Filter on Name Only", plugin.getName());
this.provider = provider;
setMenuBarData(new MenuData(new String[] { "Filter on Name Only" }, null, "VeryLast",
MenuData.NO_MNEMONIC, menuSubGroup));
setDescription("Selected indicates to use only the data type name when filtering.");
setEnabled(true);
setSelected(false); // default to off!
setHelpLocation(new HelpLocation("DataTypeManagerPlugin", "Filter_Name_Only"));
}
@Override
public void setSelected(boolean newValue) {
if (isSelected() == newValue) {
return;
}
super.setSelected(newValue);
provider.setFilterOnNameOnlyCallback(newValue);
}
}

View File

@ -43,6 +43,9 @@ public class IncludeDataTypesInFilterAction extends ToggleDockingAction {
@Override @Override
public void setSelected(boolean newValue) { public void setSelected(boolean newValue) {
if (isSelected() == newValue) {
return;
}
super.setSelected(newValue); super.setSelected(newValue);
provider.setIncludeDataTypeMembersInFilterCallback(newValue); provider.setIncludeDataTypeMembersInFilterCallback(newValue);
} }

View File

@ -158,9 +158,21 @@ public class DataTypeArchiveGTree extends GTree {
reloadTree(); reloadTree();
} }
public void setIncludeDataTypeMembersInSearch(boolean includeDataTypes) { public void updateDataTransformer(DataTypesProvider provider) {
setDataTransformer(
includeDataTypes ? new DataTypeTransformer() : new DefaultGTreeDataTransformer()); boolean includeMembers = provider.isIncludeDataMembersInSearch();
boolean filterOnNameOnly = provider.isFilterOnNameOnly();
DefaultDtTreeDataTransformer transformer;
if (includeMembers) {
transformer = new DataTypeTransformer(filterOnNameOnly);
}
else {
transformer = new DefaultDtTreeDataTransformer(filterOnNameOnly);
}
setDataTransformer(transformer);
reloadTree(); reloadTree();
} }
@ -249,7 +261,28 @@ public class DataTypeArchiveGTree extends GTree {
// Inner Classes // Inner Classes
//================================================================================================== //==================================================================================================
private class DataTypeTransformer extends DefaultGTreeDataTransformer { private class DefaultDtTreeDataTransformer extends DefaultGTreeDataTransformer {
private boolean filterOnNameOnly;
DefaultDtTreeDataTransformer(boolean filterOnNameOnly) {
this.filterOnNameOnly = filterOnNameOnly;
}
@Override
protected String toString(GTreeNode node) {
if (filterOnNameOnly) {
return node.getName(); // the node name is the type name
}
return super.toString(node);
}
}
private class DataTypeTransformer extends DefaultDtTreeDataTransformer {
DataTypeTransformer(boolean filterOnNameOnly) {
super(filterOnNameOnly);
}
@Override @Override
public List<String> transform(GTreeNode node) { public List<String> transform(GTreeNode node) {

View File

@ -24,7 +24,7 @@ import ghidra.util.FilterTransformer;
public class DefaultGTreeDataTransformer implements FilterTransformer<GTreeNode> { public class DefaultGTreeDataTransformer implements FilterTransformer<GTreeNode> {
private ThreadLocal<List<String>> localizedResults = new ThreadLocal<List<String>>() { private ThreadLocal<List<String>> localizedResults = new ThreadLocal<List<String>>() {
@Override @Override
protected java.util.List<String> initialValue() { protected List<String> initialValue() {
return new ArrayList<String>(); return new ArrayList<String>();
} }
}; };
@ -33,7 +33,11 @@ public class DefaultGTreeDataTransformer implements FilterTransformer<GTreeNode>
public List<String> transform(GTreeNode node) { public List<String> transform(GTreeNode node) {
List<String> results = localizedResults.get(); List<String> results = localizedResults.get();
results.clear(); results.clear();
results.add(node.getDisplayText()); results.add(toString(node));
return results; return results;
} }
protected String toString(GTreeNode node) {
return node.getDisplayText();
}
} }