mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-12 23:23:17 +00:00
GT-2763 - Table Sorting - updated help; removed old
DefaultSortedTableModel
This commit is contained in:
parent
4a8144c288
commit
da5f009c71
@ -128,13 +128,11 @@ src/main/help/help/topics/CallTreePlugin/images/CallTreeWindow.png||GHIDRA||||EN
|
||||
src/main/help/help/topics/CallTreePlugin/images/arrow_rotate_clockwise.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/collapse_all.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/depth-input.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/expand_all.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/go-home.png||Tango Icons - Public Domain|||tango icon set|END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/locationIn.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/locationOut.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/package.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/stopNode.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/CallTreePlugin/images/view-filter.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/help/help/topics/ClearPlugin/Clear.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/ClearPlugin/images/ClearFlow.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/ClearPlugin/images/ClearWithOptions.png||GHIDRA||||END|
|
||||
@ -153,7 +151,6 @@ src/main/help/help/topics/CodeBrowserPlugin/images/ClosedStructure.png||GHIDRA||
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowser.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowserColors.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowserReferencePopup.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowserTruncatedTextPopup.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowserWithFlowArrows.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowserWithMarkers.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/CodeBrowserPlugin/images/CodeBrowser_OperandHighlight.png||GHIDRA||||END|
|
||||
@ -214,7 +211,6 @@ src/main/help/help/topics/DataTypeEditors/images/disk.png||FAMFAMFAM Icons - CC
|
||||
src/main/help/help/topics/DataTypeEditors/images/down.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeEditors/images/edit-delete.png||Oxygen Icons - LGPL 3.0||||END|
|
||||
src/main/help/help/topics/DataTypeEditors/images/erase16.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeEditors/images/pencil16.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/DataTypeEditors/images/up.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_archives.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/data_type_manager_description.htm||GHIDRA||||END|
|
||||
@ -224,7 +220,6 @@ src/main/help/help/topics/DataTypeManagerPlugin/images/BookShelfOpen.png||GHIDRA
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/CommitDialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeConflict.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeManager.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/DataTypeTreeWithAssociations.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/DisassociateDialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/EditPaths.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataTypeManagerPlugin/images/FavoriteDts.png||GHIDRA||||END|
|
||||
@ -270,7 +265,6 @@ src/main/help/help/topics/DataWindowPlugin/data_window.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataWindowPlugin/images/DataWindow.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataWindowPlugin/images/DataWindowFilter.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DataWindowPlugin/images/text_align_justify.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/DataWindowPlugin/images/view-filter.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/help/help/topics/DbViewerPlugin/DbViewer.htm||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/DbViewerPlugin/images/DatabaseViewer.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/DisassembledViewPlugin/DisassembledViewPlugin.htm||GHIDRA||||END|
|
||||
@ -292,7 +286,6 @@ src/main/help/help/topics/EclipseIntegration/EclipseIntegration.htm||GHIDRA||||E
|
||||
src/main/help/help/topics/EquatePlugin/Equates.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/EquatePlugin/images/AfterApplyEnum.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/EquatePlugin/images/ApplyEnum.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/EquatePlugin/images/ApplyEnumPopup.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/EquatePlugin/images/BeforeApplyEnum.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/EquatePlugin/images/ConfirmEquateDelete.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/EquatePlugin/images/EquatesTable.png||GHIDRA||||END|
|
||||
@ -302,7 +295,6 @@ src/main/help/help/topics/EquatePlugin/images/SetEquate.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/ExporterPlugin/exporter.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/ExporterPlugin/images/Ascii_Options.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/ExporterPlugin/images/C_Options.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/ExporterPlugin/images/Export_Data_Panel.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/ExporterPlugin/images/Export_Dialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/ExporterPlugin/images/Intel_Hex_Options.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FallThroughPlugin/Override_Fallthrough.htm||GHIDRA||||END|
|
||||
@ -339,7 +331,6 @@ src/main/help/help/topics/FrontEndPlugin/images/ConnectTools.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/DeleteProject.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/EditPluginPath.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/EditProjectAccessList.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/EditProjectAccessPanel.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/MemoryUsage.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/NonSharedProjectInfo.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/OpenProject.png||GHIDRA||||END|
|
||||
@ -366,7 +357,6 @@ src/main/help/help/topics/FrontEndPlugin/images/VersionedFileCOnoServer.png||GHI
|
||||
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileCOwithServer.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/VersionedFileIcon.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/ViewOtherProjects.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/ViewProjectAccessPanel.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/closedBookBlue.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/connected.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/disconnected.gif||GHIDRA||||END|
|
||||
@ -378,7 +368,6 @@ src/main/help/help/topics/FrontEndPlugin/images/up.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FrontEndPlugin/images/user.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/FunctionComparison/FunctionComparison.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionComparison/images/FunctionComparisonWindow.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionComparison/images/FunctionComparisonWindowFromMap.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionComparison/images/FunctionScope.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionComparison/images/ListingCodeComparisonOptions.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionComparison/images/MultiFunctionComparisonWindow.png||GHIDRA||||END|
|
||||
@ -410,7 +399,6 @@ src/main/help/help/topics/FunctionTagPlugin/images/DeleteWarning.png||GHIDRA||||
|
||||
src/main/help/help/topics/FunctionTagPlugin/images/EditNotAllowedWarning.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionTagPlugin/images/EditTag.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionTagPlugin/images/FilterField.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionTagPlugin/images/FullWindow.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionTagPlugin/images/FunctionTagPlugin.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionTagPlugin/images/InputField.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/FunctionWindowPlugin/function_window.htm||GHIDRA||||END|
|
||||
@ -534,10 +522,6 @@ src/main/help/help/topics/OverviewPlugin/images/EntropyLegend.png||GHIDRA||||END
|
||||
src/main/help/help/topics/OverviewPlugin/images/EntropyOptions.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/OverviewPlugin/images/Equation.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/OverviewPlugin/images/OverviewPanel.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/OverviewPlugin/images/Program.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/OverviewPlugin/images/View.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/OverviewPlugin/images/zoom_in.png||FAMFAMFAM Icons - CC 2.5|||silk|END|
|
||||
src/main/help/help/topics/OverviewPlugin/images/zoom_out.png||FAMFAMFAM Icons - CC 2.5|||silk|END|
|
||||
src/main/help/help/topics/PDB/PDB.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/PDB/download_pdb_file.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/PDB/images/KnownSymbolServerURLsDialog.png||GHIDRA||||END|
|
||||
@ -689,11 +673,9 @@ src/main/help/help/topics/Search/images/DOSA_D.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/DOSA_O.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/DOSA_S.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/DirectReferences.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/DirectRefsOnSelection.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/MultipleSelectionError.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/QueryResultsSearch.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/SearchForAddressTables.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/SearchInThstructionPatternsResultsTable.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/SearchInstructionPatterns.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/SearchInstructionPatternsControlPanel.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/SearchInstructionPatternsInstructionTable.png||GHIDRA||||END|
|
||||
@ -716,7 +698,6 @@ src/main/help/help/topics/Search/images/SearchText.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/StringSearchDialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/StringSearchResults.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/binaryData.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/browser.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
|
||||
src/main/help/help/topics/Search/images/collapse.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/dialog-warning.png||Oxygen Icons - LGPL 3.0||||END|
|
||||
src/main/help/help/topics/Search/images/dialog-warning_red.png||Tango Icons - Public Domain||||END|
|
||||
@ -726,7 +707,6 @@ src/main/help/help/topics/Search/images/expand.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/font.png||FAMFAMFAM Icons - CC 2.5||||END|
|
||||
src/main/help/help/topics/Search/images/go-home.png||Tango Icons - Public Domain||||END|
|
||||
src/main/help/help/topics/Search/images/hexData.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/locationOut.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/magnifier.png||FAMFAMFAM Icons - CC 2.5||||END|
|
||||
src/main/help/help/topics/Search/images/page_white_copy.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/Search/images/reload.png||Nuvola Icons - LGPL 2.1||||END|
|
||||
@ -734,7 +714,6 @@ src/main/help/help/topics/Search/images/searchm_obj.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/Search/images/table_delete.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/Search/images/text_align_justify.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/Search/images/view-filter.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||
src/main/help/help/topics/Search/images/viewmag.png||Nuvola Icons - LGPL 2.1|||Nuvola icon set|END|
|
||||
src/main/help/help/topics/SelectBlockPlugin/Select_Block_Help.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/SelectBlockPlugin/images/Dialog.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/SelectBlockPlugin/images/ToBadAddr.png||GHIDRA||||END|
|
||||
@ -780,7 +759,6 @@ src/main/help/help/topics/SymbolTreePlugin/images/EditExternalLocation.png||GHID
|
||||
src/main/help/help/topics/SymbolTreePlugin/images/SymbolTree.png||GHIDRA||||END|
|
||||
src/main/help/help/topics/SymbolTreePlugin/images/openFolderGroup.png||Modified Nuvola Icons - LGPL 2.1||||END|
|
||||
src/main/help/help/topics/SymbolTreePlugin/images/sitemap_color.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
|
||||
src/main/help/help/topics/SymbolTreePlugin/locationIn.gif||GHIDRA||||END|
|
||||
src/main/help/help/topics/Tables/GhidraTableHeaders.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/Tables/images/BytesSettingsDialog.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/Tables/images/MultipleColumnSortDialog.png||GHIDRA||||END|
|
||||
|
@ -23,6 +23,8 @@
|
||||
If you are using a table that does not offer one of the above features, and you would like
|
||||
us to add that feature, then please contact the Ghidra team to request additional support.
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
<img src="../../shared/note.png" border="0">In addition to table header actions, many
|
||||
tables support a common set of actions when right-clicking in the body of the table, such
|
||||
@ -34,6 +36,7 @@
|
||||
<li><a href="#SelectAll">Select All (also available via <b>Ctrl-A</b></a>.</li>
|
||||
</ol>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
</blockquote>
|
||||
|
||||
@ -45,10 +48,12 @@
|
||||
sorted column is denoted by an icon that shows the sort direction.
|
||||
</p>
|
||||
|
||||
<p><img border="0" src="../../shared/note.png" alt="">
|
||||
<blockquote>
|
||||
<p><img border="0" src="../../shared/note.yellow.png" alt="">
|
||||
If you click a table column header and no sorting takes place, then that particular
|
||||
table does not support sorting on columns.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
When you click a column to sort the data, the default sort will be ascending. If you
|
||||
@ -73,17 +78,27 @@
|
||||
</p>
|
||||
<p>
|
||||
With multiple sorted columns, you may change the direction of any individual
|
||||
sort column by left-clicking that column. To remove a sort column from a multiple
|
||||
column sort, Ctrl-left-click that column.
|
||||
sort column by left-clicking that column.
|
||||
<blockquote>
|
||||
<p><img border="0" src="../../shared/tip.png" alt="">
|
||||
To remove a sort column from a multiple column sort, Ctrl-left-click that column.
|
||||
This will even work when only one column is sorted, <b><i>thus effectively disabling
|
||||
sorting for the table</i></b>.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p><img border="0" src="../../shared/note.png" alt="">
|
||||
It is possible to cancel some tables while they are loading or sorting their data.
|
||||
If this happens, you can trigger a reload of the data by sorting on one of the
|
||||
columns.
|
||||
</p>
|
||||
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<h2><a name="SelectColumns"></a>Choosing Columns</h2>
|
||||
|
||||
@ -159,19 +174,17 @@
|
||||
<blockquote>
|
||||
<p>
|
||||
Exports the current table to a comma-separated value (CSV) text file. The CSV file
|
||||
will export the selected columns in the order displayed.
|
||||
will export the selected columns in the order displayed. The first row of ouput will
|
||||
contain the table's column names.
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
<img src="../../shared/note.png" border="0">This action uses the current
|
||||
<img src="../../shared/note.yellow.png" border="0">This action uses the current
|
||||
table selection when deciding what to export. If no row is selected, then no data is
|
||||
exported. To select all rows, use the <b>Select All</b> action or press <b>Ctrl-A</b> on
|
||||
the keyboard.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="../../shared/note.png" border="0">
|
||||
Note: The first row will contain the column names.
|
||||
</p>
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
</p>
|
||||
</blockquote>
|
||||
|
@ -16,20 +16,18 @@
|
||||
package ghidra.app.plugin.core.data;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.*;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.widgets.combobox.GComboBox;
|
||||
import docking.widgets.dialogs.StringChoices;
|
||||
import docking.widgets.table.DefaultSortedTableModel;
|
||||
import docking.widgets.table.AbstractSortedTableModel;
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.model.data.Composite;
|
||||
@ -67,9 +65,6 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
private boolean appliedSettings;
|
||||
private Program program;
|
||||
|
||||
/**
|
||||
* Construct instance settings dialog.
|
||||
*/
|
||||
public DataSettingsDialog(Program program, ProgramSelection sel) throws CancelledException {
|
||||
super("Data Settings", true, false, true, false);
|
||||
this.program = program;
|
||||
@ -83,9 +78,6 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
buildPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct instance settings dialog.
|
||||
*/
|
||||
public DataSettingsDialog(Program program, Data data) {
|
||||
super("Data Settings", true, false, true, false);
|
||||
this.data = data;
|
||||
@ -111,9 +103,6 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
buildPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct default data type settings dialog.
|
||||
*/
|
||||
public DataSettingsDialog(Program program, DataType dataType) {
|
||||
super("Data Settings", true, false, true, false);
|
||||
this.dataType = dataType;
|
||||
@ -126,9 +115,6 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
setHelpLocation(new HelpLocation("DataPlugin", "Default_Data_Settings"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct default data type component settings dialog.
|
||||
*/
|
||||
DataSettingsDialog(Program program, DataTypeComponent dtc) {
|
||||
super("Data Settings", true, false, true, false);
|
||||
this.dtc = dtc;
|
||||
@ -204,12 +190,7 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
addOKButton();
|
||||
|
||||
JButton newApplyButton = new JButton("Apply");
|
||||
newApplyButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
applySettings();
|
||||
}
|
||||
});
|
||||
newApplyButton.addActionListener(e -> applySettings());
|
||||
addButton(newApplyButton);
|
||||
|
||||
addCancelButton();
|
||||
@ -219,17 +200,9 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
JPanel workPanel = new JPanel(new BorderLayout());
|
||||
workPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
settingsTableModel = new SettingsTableModel();
|
||||
|
||||
DefaultSortedTableModel sorter = new DefaultSortedTableModel(settingsTableModel);
|
||||
sorter.sortByColumn(SettingsTableModel.DEFAULT_SORT_COL);
|
||||
sorter.addTableModelListener(new TableModelListener() {
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
appliedSettings = false;
|
||||
}
|
||||
});
|
||||
settingsTable = new GhidraTable(sorter);
|
||||
settingsTableModel = new SettingsTableModel(settingsDefs);
|
||||
settingsTableModel.addTableModelListener(e -> appliedSettings = false);
|
||||
settingsTable = new GhidraTable(settingsTableModel);
|
||||
settingsTable.setAutoscrolls(true);
|
||||
settingsTable.setRowSelectionAllowed(false);
|
||||
settingsTable.setColumnSelectionAllowed(false);
|
||||
@ -251,18 +224,12 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
return workPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.util.bean.GhidraDialog#cancelCallback()
|
||||
*/
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
close();
|
||||
dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.util.bean.GhidraDialog#okCallback()
|
||||
*/
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
applySettings();
|
||||
@ -565,7 +532,7 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
|
||||
// For selection case we must ensure that settings has a non-null value even for defaults
|
||||
if (selection != null && settings.getValue(def.getName()) == null) {
|
||||
settings.setValue(def.getName(), new Long(def.getChoice(settings)));
|
||||
settings.setValue(def.getName(), Long.valueOf(def.getChoice(settings)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,81 +561,98 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
return newChoices;
|
||||
}
|
||||
|
||||
class SettingsTableModel extends AbstractTableModel {
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
class SettingsRowObject {
|
||||
|
||||
static final int DEFAULT_SORT_COL = 0;
|
||||
private SettingsDefinition definition;
|
||||
|
||||
SettingsRowObject(SettingsDefinition definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return definition.getName();
|
||||
}
|
||||
|
||||
Object getSettingsChoices() {
|
||||
if (definition instanceof EnumSettingsDefinition) {
|
||||
StringChoices choices = getChoices((EnumSettingsDefinition) definition);
|
||||
return choices;
|
||||
}
|
||||
else if (definition instanceof BooleanSettingsDefinition) {
|
||||
StringChoices choices = getChoices((BooleanSettingsDefinition) definition);
|
||||
return choices;
|
||||
}
|
||||
return "<Unsupported>";
|
||||
}
|
||||
|
||||
boolean useDefault() {
|
||||
if (definition instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition def = (EnumSettingsDefinition) definition;
|
||||
return def.getChoice(settings) == def.getChoice(defaultSettings);
|
||||
}
|
||||
else if (definition instanceof BooleanSettingsDefinition) {
|
||||
BooleanSettingsDefinition def = (BooleanSettingsDefinition) definition;
|
||||
return def.getValue(settings) == def.getValue(defaultSettings);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean setSettingsChoice(Object value) {
|
||||
if (definition instanceof EnumSettingsDefinition) {
|
||||
setChoice(value, (EnumSettingsDefinition) definition);
|
||||
return true;
|
||||
}
|
||||
else if (definition instanceof BooleanSettingsDefinition) {
|
||||
setChoice(value, (BooleanSettingsDefinition) definition);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear(SettingsImpl s) {
|
||||
definition.clear(s);
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingsTableModel extends AbstractSortedTableModel<SettingsRowObject> {
|
||||
|
||||
private List<SettingsRowObject> rows = new ArrayList<>();
|
||||
|
||||
SettingsTableModel(SettingsDefinition[] settingsDefs) {
|
||||
for (SettingsDefinition sd : settingsDefs) {
|
||||
rows.add(new SettingsRowObject(sd));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SettingsRowObject> getModelData() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Settings Definition Model";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
return columnIndex == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int col) {
|
||||
return col != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return (selection != null || editingDefaults) ? 2 : 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return settingsDefs != null ? settingsDefs.length : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
switch (col) {
|
||||
case 0:
|
||||
return settingsDefs[row].getName();
|
||||
case 1:
|
||||
if (settingsDefs[row] instanceof EnumSettingsDefinition) {
|
||||
return getChoices((EnumSettingsDefinition) settingsDefs[row]);
|
||||
}
|
||||
else if (settingsDefs[row] instanceof BooleanSettingsDefinition) {
|
||||
return getChoices((BooleanSettingsDefinition) settingsDefs[row]);
|
||||
}
|
||||
return "<Unsupported>";
|
||||
|
||||
case 2:
|
||||
if (settingsDefs[row] instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition def = (EnumSettingsDefinition) settingsDefs[row];
|
||||
return new Boolean(
|
||||
def.getChoice(settings) == def.getChoice(defaultSettings));
|
||||
}
|
||||
else if (settingsDefs[row] instanceof BooleanSettingsDefinition) {
|
||||
BooleanSettingsDefinition def =
|
||||
(BooleanSettingsDefinition) settingsDefs[row];
|
||||
return new Boolean(def.getValue(settings) == def.getValue(defaultSettings));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#setValueAt(Object, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void setValueAt(Object value, int row, int col) {
|
||||
switch (col) {
|
||||
case 1:
|
||||
if (settingsDefs[row] instanceof EnumSettingsDefinition) {
|
||||
setChoice(value, (EnumSettingsDefinition) settingsDefs[row]);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
else if (settingsDefs[row] instanceof BooleanSettingsDefinition) {
|
||||
setChoice(value, (BooleanSettingsDefinition) settingsDefs[row]);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
settingsDefs[row].clear(settings);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#getColumnName(int)
|
||||
*/
|
||||
@Override
|
||||
public String getColumnName(int col) {
|
||||
switch (col) {
|
||||
@ -682,40 +666,40 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#getColumnClass(int)
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getColumnClass(int col) {
|
||||
switch (col) {
|
||||
public Object getColumnValueForRow(SettingsRowObject t, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return String.class;
|
||||
return t.getName();
|
||||
case 1:
|
||||
return Settings.class;
|
||||
return t.getSettingsChoices();
|
||||
case 2:
|
||||
return Boolean.class;
|
||||
return t.useDefault();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isColumnSortable(int col) {
|
||||
return col == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#isCellEditable(int, int)
|
||||
*/
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int col) {
|
||||
return col != 0;
|
||||
public void setValueAt(Object value, int row, int col) {
|
||||
SettingsRowObject rowObject = rows.get(row);
|
||||
switch (col) {
|
||||
case 1:
|
||||
if (rowObject.setSettingsChoice(value)) {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
rowObject.clear(settings);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class SettingsEditor extends AbstractCellEditor implements TableCellEditor {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
final static int ENUM = 0;
|
||||
final static int BOOLEAN = 1;
|
||||
|
||||
@ -723,12 +707,7 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
private GComboBox<String> comboBox = new GComboBox<>();
|
||||
|
||||
SettingsEditor() {
|
||||
comboBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
fireEditingStopped();
|
||||
}
|
||||
});
|
||||
comboBox.addItemListener(e -> fireEditingStopped());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -755,9 +734,6 @@ public class DataSettingsDialog extends DialogComponentProvider {
|
||||
return enuum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable, java.lang.Object, boolean, int, int)
|
||||
*/
|
||||
@Override
|
||||
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
|
||||
int row, int column) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,6 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.references;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.table.AbstractSortedTableModel;
|
||||
import ghidra.app.cmd.refs.UpdateExternalNameCmd;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
@ -25,57 +30,40 @@ import ghidra.program.model.symbol.ExternalManager;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
/**
|
||||
* TableModel for the external program names and corresponding ghidra path names.
|
||||
*/
|
||||
class ExternalNamesTableModel extends AbstractTableModel {
|
||||
public class ExternalNamesTableModel extends AbstractSortedTableModel<ExternalPath> {
|
||||
|
||||
final static int NAME_COL = 0;
|
||||
final static int PATH_COL = 1;
|
||||
final static String EXTERNAL_NAME = "Name";
|
||||
final static String PATH_NAME = "Ghidra Program";
|
||||
private final List<String> columns = List.of(EXTERNAL_NAME, PATH_NAME);
|
||||
|
||||
private final String[] columnNames = { EXTERNAL_NAME, PATH_NAME };
|
||||
|
||||
private List<String> nameList = new ArrayList<String>();
|
||||
private List<String> pathNameList = new ArrayList<String>();
|
||||
private Program program;
|
||||
private PluginTool tool;
|
||||
private Program program;
|
||||
private List<ExternalPath> paths = new ArrayList<>();
|
||||
|
||||
public ExternalNamesTableModel(PluginTool tool) {
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return columnNames.length;
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return nameList.size();
|
||||
return columns.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return columnNames[column];
|
||||
return columns.get(column);
|
||||
}
|
||||
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
if (rowIndex >= nameList.size()) {
|
||||
return "";
|
||||
}
|
||||
switch (columnIndex) {
|
||||
case NAME_COL:
|
||||
return nameList.get(rowIndex);
|
||||
@Override
|
||||
public String getName() {
|
||||
return "External Programs Model";
|
||||
}
|
||||
|
||||
case PATH_COL:
|
||||
return pathNameList.get(rowIndex);
|
||||
}
|
||||
return "Unknown Column!";
|
||||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -87,55 +75,81 @@ class ExternalNamesTableModel extends AbstractTableModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
String extName = ((String) aValue).trim();
|
||||
public List<ExternalPath> getModelData() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
if ("".equals(extName)) {
|
||||
@Override
|
||||
public Object getColumnValueForRow(ExternalPath t, int columnIndex) {
|
||||
|
||||
switch (columnIndex) {
|
||||
case NAME_COL:
|
||||
return t.getName();
|
||||
case PATH_COL:
|
||||
return t.getPath();
|
||||
}
|
||||
return "Unknown Column!";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int row, int column) {
|
||||
|
||||
String newName = ((String) aValue).trim();
|
||||
if (StringUtils.isBlank(newName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameList.contains(extName)) {
|
||||
if (nameList.indexOf(extName) != rowIndex) {
|
||||
Window window = tool.getActiveWindow();
|
||||
Msg.showInfo(getClass(), window, "Duplicate Name", "Name already exists: " +
|
||||
extName);
|
||||
}
|
||||
int index = indexOf(newName);
|
||||
if (index >= 0) {
|
||||
Window window = tool.getActiveWindow();
|
||||
Msg.showInfo(getClass(), window, "Duplicate Name", "Name already exists: " + newName);
|
||||
return;
|
||||
}
|
||||
|
||||
Command cmd =
|
||||
new UpdateExternalNameCmd(nameList.get(rowIndex), extName, SourceType.USER_DEFINED);
|
||||
|
||||
ExternalPath path = paths.get(row);
|
||||
String oldName = path.getName();
|
||||
Command cmd = new UpdateExternalNameCmd(oldName, newName, SourceType.USER_DEFINED);
|
||||
if (!tool.execute(cmd, program)) {
|
||||
tool.setStatusInfo(cmd.getStatusMsg());
|
||||
}
|
||||
}
|
||||
|
||||
private int indexOf(String name) {
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
ExternalPath path = paths.get(i);
|
||||
if (path.getName().equals(name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setProgram(Program program) {
|
||||
this.program = program;
|
||||
updateTableData();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void updateTableData() {
|
||||
nameList.clear();
|
||||
pathNameList.clear();
|
||||
|
||||
paths.clear();
|
||||
|
||||
if (program == null) {
|
||||
fireTableDataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
ExternalManager extMgr = program.getExternalManager();
|
||||
String[] programNames = extMgr.getExternalLibraryNames();
|
||||
Arrays.sort(programNames);
|
||||
|
||||
for (int i = 0; i < programNames.length; i++) {
|
||||
if (Library.UNKNOWN.equals(programNames[i])) {
|
||||
for (String programName : programNames) {
|
||||
if (Library.UNKNOWN.equals(programName)) {
|
||||
continue;
|
||||
}
|
||||
nameList.add(programNames[i]);
|
||||
pathNameList.add(extMgr.getExternalLibraryPath(programNames[i]));
|
||||
|
||||
ExternalPath path =
|
||||
new ExternalPath(programName, extMgr.getExternalLibraryPath(programName));
|
||||
paths.add(path);
|
||||
}
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
/* ###
|
||||
* 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.references;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A simple container class used as a row object
|
||||
*/
|
||||
class ExternalPath {
|
||||
|
||||
private String name;
|
||||
private String path;
|
||||
|
||||
ExternalPath(String name, String path) {
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((path == null) ? 0 : path.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExternalPath other = (ExternalPath) obj;
|
||||
if (!Objects.equals(name, other.name)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(path, other.path)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -24,7 +24,6 @@ import java.util.List;
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.widgets.table.DefaultSortedTableModel;
|
||||
import ghidra.framework.model.DomainObjectListener;
|
||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
@ -35,7 +34,6 @@ import ghidra.util.table.GhidraTable;
|
||||
public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
private JPanel mainPanel;
|
||||
private ExternalNamesTableModel tableModel;
|
||||
private DefaultSortedTableModel sortedModel;
|
||||
private GhidraTable table;
|
||||
private Program program;
|
||||
|
||||
@ -106,9 +104,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
tableModel = new ExternalNamesTableModel(tool);
|
||||
|
||||
sortedModel = new DefaultSortedTableModel(tableModel);
|
||||
sortedModel.sortByColumn(ExternalNamesTableModel.NAME_COL);
|
||||
table = new GhidraTable(sortedModel);
|
||||
table = new GhidraTable(tableModel);
|
||||
|
||||
InputMap inputMap = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
|
||||
@ -150,40 +146,6 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
|
||||
panel.add(sp, BorderLayout.CENTER);
|
||||
|
||||
// addButton = new JButton("Add");
|
||||
// addButton.setMnemonic('A');
|
||||
// addButton.addActionListener(new ActionListener() {
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// clearStatusText();
|
||||
// tableModel.addDefaultRow();
|
||||
// }
|
||||
// });
|
||||
// ToolTipManager.setToolTipText(addButton,
|
||||
// "Link new External Program name to blank Ghidra Pathname");
|
||||
//
|
||||
// clearButton = new JButton("Clear");
|
||||
// clearButton.setMnemonic('C');
|
||||
// clearButton.addActionListener(new ActionListener() {
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// clear();
|
||||
// }
|
||||
// });
|
||||
// ToolTipManager.setToolTipText(clearButton, "Remove External Program Link");
|
||||
|
||||
// editButton = new JButton("Edit");
|
||||
// editButton.setMnemonic('E');
|
||||
// editButton.addActionListener(new ActionListener() {
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// editPathName();
|
||||
// }
|
||||
// });
|
||||
// ToolTipManager.setToolTipText(editButton, "Edit Ghidra Pathname");
|
||||
//
|
||||
// addButton(addButton);
|
||||
// addButton(editButton);
|
||||
// addButton(clearButton);
|
||||
// enableButtons();
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@ -201,9 +163,8 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
public List<String> getSelectedExternalNames() {
|
||||
List<String> externalNames = new ArrayList<>();
|
||||
int[] selectedRows = table.getSelectedRows();
|
||||
for (int selectedRow : selectedRows) {
|
||||
int index = sortedModel.getSortedIndex(selectedRow);
|
||||
String externalName = (String) tableModel.getValueAt(index, 0);
|
||||
for (int row : selectedRows) {
|
||||
String externalName = (String) tableModel.getValueAt(row, 0);
|
||||
externalNames.add(externalName);
|
||||
}
|
||||
return externalNames;
|
||||
|
@ -23,7 +23,6 @@ import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import docking.widgets.table.DefaultSortedTableModel;
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.services.GoToService;
|
||||
@ -214,10 +213,6 @@ public class GhidraTable extends GTable {
|
||||
if (model instanceof ProgramTableModel) {
|
||||
return (ProgramTableModel) model;
|
||||
}
|
||||
else if (model instanceof DefaultSortedTableModel) {
|
||||
DefaultSortedTableModel defaultSortedTableModel = (DefaultSortedTableModel) model;
|
||||
return getProgramTableModel(defaultSortedTableModel.getModel());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ import ghidra.program.util.ProgramSelection;
|
||||
|
||||
/**
|
||||
* This is a "program aware" version of GTableFilterPanel
|
||||
* @param <ROW_OBJECT> the row type
|
||||
*/
|
||||
public class GhidraTableFilterPanel<ROW_OBJECT> extends GTableFilterPanel<ROW_OBJECT> {
|
||||
|
||||
|
@ -26,14 +26,17 @@ import docking.ActionContext;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.dialogs.StringChoices;
|
||||
import docking.widgets.table.AbstractSortedTableModel;
|
||||
import ghidra.app.LocationCallback;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||
import ghidra.app.plugin.core.clear.ClearCmd;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.app.plugin.core.data.DataSettingsDialog.SettingsRowObject;
|
||||
import ghidra.app.plugin.core.navigation.NextPrevAddressPlugin;
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.docking.settings.FormatSettingsDefinition;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
@ -215,7 +218,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||
waitForSwing();
|
||||
|
||||
Runnable r = () -> {
|
||||
DataSettingsDialog.SettingsTableModel model = dlg.getSettingsTableModel();
|
||||
AbstractSortedTableModel<SettingsRowObject> model = dlg.getSettingsTableModel();
|
||||
int useDefaultCol = model.findColumn("Use Default");
|
||||
int rowCnt = model.getRowCount();
|
||||
|
||||
@ -242,27 +245,25 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||
|
||||
waitForSwing();
|
||||
|
||||
final DataSettingsDialog.SettingsTableModel model = dlg.getSettingsTableModel();
|
||||
final int settingsCol = model.findColumn("Settings");
|
||||
assertEquals(Settings.class, model.getColumnClass(settingsCol));
|
||||
AbstractSortedTableModel<SettingsRowObject> model = dlg.getSettingsTableModel();
|
||||
|
||||
error = null;
|
||||
|
||||
Runnable r = () -> {
|
||||
|
||||
int nameCol = model.findColumn("Name");
|
||||
int settingsCol1 = model.findColumn("Settings");
|
||||
int settingsCol = model.findColumn("Settings");
|
||||
int rowCnt = model.getRowCount();
|
||||
|
||||
for (int i = 0; i < rowCnt; i++) {
|
||||
String name = (String) model.getValueAt(i, nameCol);
|
||||
int index = findSettingIndex(settingNames, name);
|
||||
if (index != -1) {
|
||||
Object v = model.getValueAt(i, settingsCol1);
|
||||
Object v = model.getValueAt(i, settingsCol);
|
||||
if (v instanceof StringChoices) {
|
||||
StringChoices choices = (StringChoices) v;
|
||||
choices.setSelectedValue(newValues[index]);
|
||||
model.setValueAt(choices, i, settingsCol1);
|
||||
model.setValueAt(choices, i, settingsCol);
|
||||
}
|
||||
else {
|
||||
error = "Unsupported test setting: " + v.getClass();
|
||||
@ -770,7 +771,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra
|
||||
protected void manipulateMutabilitySettings(boolean testDefaultSetting, boolean insideStruct,
|
||||
boolean commonStruct, Data data1, Data data2) throws Exception {
|
||||
|
||||
assertTrue(data1.getDataType() == data2.getDataType());
|
||||
assertSame(data1.getDataType(), data2.getDataType());
|
||||
|
||||
boolean settingsAreShared =
|
||||
testDefaultSetting && (!insideStruct || (insideStruct && commonStruct));
|
||||
|
@ -26,14 +26,6 @@ import ghidra.program.model.data.DataType;
|
||||
@Category(NightlyCategory.class)
|
||||
public class DataAction1Test extends AbstractDataActionTest {
|
||||
|
||||
/**
|
||||
* Constructor for FallThroughActionTest.
|
||||
* @param arg0
|
||||
*/
|
||||
public DataAction1Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllStructDataSettings() throws Exception {
|
||||
|
||||
|
@ -26,14 +26,6 @@ import ghidra.program.model.data.DataType;
|
||||
@Category(NightlyCategory.class)
|
||||
public class DataAction2Test extends AbstractDataActionTest {
|
||||
|
||||
/**
|
||||
* Constructor for FallThroughActionTest.
|
||||
* @param arg0
|
||||
*/
|
||||
public DataAction2Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllDefaultStructDataSettings() throws Exception {
|
||||
|
||||
|
@ -26,20 +26,11 @@ import ghidra.program.model.data.DataType;
|
||||
@Category(NightlyCategory.class)
|
||||
public class DataAction3Test extends AbstractDataActionTest {
|
||||
|
||||
/**
|
||||
* Constructor for FallThroughActionTest.
|
||||
* @param arg0
|
||||
*/
|
||||
public DataAction3Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllDefaultDataSettings() throws Exception {
|
||||
|
||||
List<DataType> builtIns = getBuiltInDataTypesAsFavorites();
|
||||
for (DataType type : builtIns) {
|
||||
//if (!(type instanceof UnicodeDataType)) continue;
|
||||
String actionName = "Define " + type.getName();
|
||||
manipulateAllSettings(true, false, false, actionName);
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||
|
||||
doAction(CREATE_ARRAY, false);
|
||||
|
||||
final NumberInputDialog dlg1 = env.waitForDialogComponent(NumberInputDialog.class, 1000);
|
||||
final NumberInputDialog dlg1 = waitForDialogComponent(NumberInputDialog.class);
|
||||
assertNotNull("Expected element count input dialog", dlg1);
|
||||
|
||||
Runnable r = () -> dlg1.setInput(0x20);
|
||||
@ -500,8 +500,6 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||
|
||||
// Test action disablement on array element location
|
||||
|
||||
Data array = getContextData();
|
||||
Data d0 = array.getComponent(0);
|
||||
BytesFieldLocation loc =
|
||||
new BytesFieldLocation(program, addr(0x010069f2), addr(0x010069f2), new int[] { 0 }, 0);
|
||||
locationGenerated(loc);
|
||||
@ -515,7 +513,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||
|
||||
doAction(CREATE_ARRAY, false);
|
||||
|
||||
final NumberInputDialog dlg2 = env.waitForDialogComponent(NumberInputDialog.class, 1000);
|
||||
final NumberInputDialog dlg2 = waitForDialogComponent(NumberInputDialog.class);
|
||||
assertNotNull("Expected element count input dialog", dlg2);
|
||||
|
||||
r = () -> dlg2.setInput(0x10);
|
||||
@ -748,7 +746,7 @@ public class DataAction4Test extends AbstractDataActionTest {
|
||||
|
||||
doAction(CREATE_ARRAY, false);
|
||||
|
||||
final NumberInputDialog dlg1 = env.waitForDialogComponent(NumberInputDialog.class, 1000);
|
||||
final NumberInputDialog dlg1 = waitForDialogComponent(NumberInputDialog.class);
|
||||
assertNotNull("Expected element count input dialog", dlg1);
|
||||
|
||||
Runnable r = () -> dlg1.setInput(5);
|
||||
|
@ -16,18 +16,22 @@
|
||||
package docking.widgets.dialogs;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
import javax.swing.table.*;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.DockingWindowManager;<<<<<<<Upstream,based on origin/master
|
||||
import docking.widgets.checkbox.GCheckBox;
|
||||
import docking.widgets.combobox.GComboBox;
|
||||
import docking.widgets.table.DefaultSortedTableModel;
|
||||
import docking.widgets.table.DefaultSortedTableModel;=======
|
||||
import docking.widgets.table.AbstractSortedTableModel;>>>>>>>000543e GT-2763-Table Sorting-updated help;removed old DefaultSortedTableModel
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
@ -44,9 +48,6 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
private SettingsTableModel settingsTableModel;
|
||||
private GTable settingsTable;
|
||||
|
||||
/**
|
||||
* Construct instance settings dialog.
|
||||
*/
|
||||
public SettingsDialog(HelpLocation help) {
|
||||
super("Settings", true, false, true, false);
|
||||
if (help != null) {
|
||||
@ -58,9 +59,6 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
setHelpLocation(new HelpLocation("Tables/GhidraTableHeaders.html", "ColumnSettings"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show dialog for the specified set of settings definitions and settings storage.
|
||||
*/
|
||||
public void show(Component parent, String title, SettingsDefinition[] newSettingsDefs,
|
||||
Settings newSettings) {
|
||||
this.settingsDefs = newSettingsDefs;
|
||||
@ -82,18 +80,13 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
JPanel workPanel = new JPanel(new BorderLayout());
|
||||
workPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
settingsTableModel = new SettingsTableModel();
|
||||
|
||||
DefaultSortedTableModel sorter = new DefaultSortedTableModel(settingsTableModel);
|
||||
sorter.sortByColumn(SettingsTableModel.DEFAULT_SORT_COL);
|
||||
|
||||
settingsTable = new GTable(sorter);
|
||||
settingsTableModel = new SettingsTableModel(settingsDefs);
|
||||
settingsTable = new GTable(settingsTableModel);
|
||||
settingsTable.setAutoscrolls(true);
|
||||
settingsTable.setRowSelectionAllowed(false);
|
||||
settingsTable.setColumnSelectionAllowed(false);
|
||||
|
||||
// disable user sorting and column adding (we don't expect enough data to require sort
|
||||
// changes)
|
||||
// disable sorting and column adding (we don't expect enough data to require sort changes)
|
||||
settingsTable.getTableHeader().setReorderingAllowed(false);
|
||||
settingsTable.setColumnHeaderPopupEnabled(false);
|
||||
settingsTable.setUserSortingEnabled(false);
|
||||
@ -109,83 +102,97 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
return workPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.util.bean.GhidraDialog#cancelCallback()
|
||||
*/
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
class SettingsTableModel extends AbstractTableModel {
|
||||
//==================================================================================================
|
||||
// Private Methods
|
||||
//==================================================================================================
|
||||
|
||||
static final int DEFAULT_SORT_COL = 0;
|
||||
private class SettingsRowObject {
|
||||
|
||||
private SettingsDefinition definition;
|
||||
|
||||
SettingsRowObject(SettingsDefinition definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return definition.getName();
|
||||
}
|
||||
|
||||
Object getSettingsChoices() {
|
||||
if (definition instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition def = (EnumSettingsDefinition) definition;
|
||||
StringChoices choices = new StringChoices(def.getDisplayChoices(settings));
|
||||
choices.setSelectedValue(def.getChoice(settings));
|
||||
return choices;
|
||||
}
|
||||
else if (definition instanceof BooleanSettingsDefinition) {
|
||||
BooleanSettingsDefinition def = (BooleanSettingsDefinition) definition;
|
||||
return Boolean.valueOf(def.getValue(settings));
|
||||
}
|
||||
return "<Unsupported>";
|
||||
}
|
||||
|
||||
boolean setSettingsChoice(Object value) {
|
||||
if (definition instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition def = (EnumSettingsDefinition) definition;
|
||||
StringChoices choices = (StringChoices) value;
|
||||
def.setChoice(settings, choices.getSelectedValueIndex());
|
||||
return true;
|
||||
}
|
||||
else if (definition instanceof BooleanSettingsDefinition) {
|
||||
BooleanSettingsDefinition def = (BooleanSettingsDefinition) definition;
|
||||
def.setValue(settings, ((Boolean) value).booleanValue());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear(Settings s) {
|
||||
definition.clear(s);
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingsTableModel extends AbstractSortedTableModel<SettingsRowObject> {
|
||||
|
||||
private List<SettingsRowObject> rows = new ArrayList<>();
|
||||
|
||||
SettingsTableModel(SettingsDefinition[] settingsDefs) {
|
||||
for (SettingsDefinition sd : settingsDefs) {
|
||||
rows.add(new SettingsRowObject(sd));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SettingsRowObject> getModelData() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Settings Definition Model";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
return columnIndex == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int col) {
|
||||
return col != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return settingsDefs != null ? settingsDefs.length : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
switch (col) {
|
||||
case 0:
|
||||
return settingsDefs[row].getName();
|
||||
case 1:
|
||||
if (settingsDefs[row] instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition def = (EnumSettingsDefinition) settingsDefs[row];
|
||||
StringChoices choices = new StringChoices(def.getDisplayChoices(settings));
|
||||
choices.setSelectedValue(def.getChoice(settings));
|
||||
return choices;
|
||||
}
|
||||
else if (settingsDefs[row] instanceof BooleanSettingsDefinition) {
|
||||
BooleanSettingsDefinition def =
|
||||
(BooleanSettingsDefinition) settingsDefs[row];
|
||||
return new Boolean(def.getValue(settings));
|
||||
}
|
||||
return "<Unsupported>";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#setValueAt(Object, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void setValueAt(Object value, int row, int col) {
|
||||
switch (col) {
|
||||
case 1:
|
||||
if (settingsDefs[row] instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition def = (EnumSettingsDefinition) settingsDefs[row];
|
||||
StringChoices choices = (StringChoices) value;
|
||||
def.setChoice(settings, choices.getSelectedValueIndex());
|
||||
fireTableDataChanged();
|
||||
}
|
||||
else if (settingsDefs[row] instanceof BooleanSettingsDefinition) {
|
||||
BooleanSettingsDefinition def =
|
||||
(BooleanSettingsDefinition) settingsDefs[row];
|
||||
def.setValue(settings, ((Boolean) value).booleanValue());
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
settingsDefs[row].clear(settings);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#getColumnName(int)
|
||||
*/
|
||||
@Override
|
||||
public String getColumnName(int col) {
|
||||
switch (col) {
|
||||
@ -197,32 +204,34 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#getColumnClass(int)
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getColumnClass(int col) {
|
||||
switch (col) {
|
||||
public Object getColumnValueForRow(SettingsRowObject t, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return String.class;
|
||||
return t.getName();
|
||||
case 1:
|
||||
return Settings.class;
|
||||
return t.getSettingsChoices();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isColumnSortable(int col) {
|
||||
return col == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TableModel#isCellEditable(int, int)
|
||||
*/
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int col) {
|
||||
return col != 0;
|
||||
public void setValueAt(Object value, int row, int col) {
|
||||
SettingsRowObject rowObject = rows.get(row);
|
||||
switch (col) {
|
||||
case 1:
|
||||
if (rowObject.setSettingsChoice(value)) {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
rowObject.clear(settings);
|
||||
fireTableDataChanged();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class SettingsEditor extends AbstractCellEditor
|
||||
@ -235,28 +244,20 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
private GComboBox<String> comboBox = new GComboBox<>();
|
||||
private GCheckBox checkBox = new GCheckBox();
|
||||
|
||||
private final Runnable editStopped = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fireEditingStopped();
|
||||
}
|
||||
};
|
||||
private final Runnable editStopped = () -> fireEditingStopped();
|
||||
|
||||
SettingsEditor() {
|
||||
super();
|
||||
comboBox.addPopupMenuListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.CellEditor#getCellEditorValue()
|
||||
*/
|
||||
@Override
|
||||
public Object getCellEditorValue() {
|
||||
switch (mode) {
|
||||
case ENUM:
|
||||
return getComboBoxEnum();
|
||||
case BOOLEAN:
|
||||
return Boolean.valueOf(checkBox.isSelected());
|
||||
return checkBox.isSelected();
|
||||
}
|
||||
throw new AssertException();
|
||||
}
|
||||
@ -271,9 +272,6 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
return choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(javax.swing.JTable, java.lang.Object, boolean, int, int)
|
||||
*/
|
||||
@Override
|
||||
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
|
||||
int row, int column) {
|
||||
@ -304,26 +302,19 @@ public class SettingsDialog extends DialogComponentProvider {
|
||||
comboBox.setSelectedIndex(choices.getSelectedValueIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent)
|
||||
*/
|
||||
@Override
|
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent)
|
||||
*/
|
||||
@Override
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
|
||||
SwingUtilities.invokeLater(editStopped);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.event.PopupMenuListener#popupMenuCanceled(javax.swing.event.PopupMenuEvent)
|
||||
*/
|
||||
@Override
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
// stub
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,432 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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 docking.widgets.table;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
import ghidra.util.datastruct.WeakSet;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
|
||||
/**
|
||||
* A sorter for TableModels. The sorter has a model (conforming to TableModel)
|
||||
* and itself implements TableModel. TableSorter does not store or copy
|
||||
* the data in the TableModel, instead it maintains an array of
|
||||
* integers which it keeps the same size as the number of rows in its
|
||||
* model. When the model changes it notifies the sorter that something
|
||||
* has changed (e.g., "rowsAdded") so that its internal array of integers
|
||||
* can be reallocated. As requests are made of the sorter (like
|
||||
* getValueAt(row, col) it redirects them to its model via the mapping
|
||||
* array. That way the TableSorter appears to hold another copy of the table
|
||||
* with the rows in a different order. The sorting algorithm used is stable
|
||||
* which means that it does not move around rows when its comparison
|
||||
* function returns 0 to denote that they are equivalent.
|
||||
*
|
||||
* @deprecated You should instead be using {@link AbstractSortedTableModel}
|
||||
*/
|
||||
@Deprecated
|
||||
public class DefaultSortedTableModel extends AbstractTableModel implements SortedTableModel,
|
||||
TableModelListener {
|
||||
|
||||
// all callbacks to fire changes and add listeners are expected to be in the Swing thread
|
||||
private WeakSet<SortListener> listeners =
|
||||
WeakDataStructureFactory.createSingleThreadAccessWeakSet();
|
||||
|
||||
//========================================================================
|
||||
// conversion to multi sorting tables
|
||||
|
||||
private TableSortState createSortState(int column, boolean ascending) {
|
||||
ColumnSortState sortState =
|
||||
new ColumnSortState(column, ascending ? SortDirection.ASCENDING
|
||||
: SortDirection.DESCENDING, 1);
|
||||
return new TableSortState(sortState);
|
||||
}
|
||||
|
||||
public void setSort(int column, boolean ascending) {
|
||||
TableSortState sortState = createSortState(column, ascending);
|
||||
setTableSortState(sortState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrimarySortColumnIndex() {
|
||||
return tableSortState.iterator().next().getColumnModelIndex();
|
||||
}
|
||||
|
||||
public boolean isAscending() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// end conversion to multi sorting tables
|
||||
|
||||
private TableSortState tableSortState = new TableSortState();
|
||||
|
||||
private int[] indexes;
|
||||
|
||||
/**
|
||||
* A poorly named variable that is intended to indicate that the client is making bulk updates
|
||||
* and this table should not perform indexing while this bulk operation is happening.
|
||||
*/
|
||||
private boolean sortEnabled = true;
|
||||
|
||||
private Map<Integer, Comparator<?>> registeredComparatorMap =
|
||||
new HashMap<Integer, Comparator<?>>();
|
||||
|
||||
protected TableModel model;
|
||||
|
||||
/**
|
||||
* Construct a new TableSorter using the given model.
|
||||
*
|
||||
* @deprecated You should instead be using {@link AbstractSortedTableModel}
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultSortedTableModel(TableModel model) {
|
||||
if (model == null) {
|
||||
throw new NullPointerException("Model cannot be null!");
|
||||
}
|
||||
|
||||
if (model instanceof AbstractSortedTableModel<?>) {
|
||||
throw new AssertException("You cannot pass an AbstractSortedTableModel to " +
|
||||
getClass().getSimpleName() + "--it is already sorted!");
|
||||
}
|
||||
|
||||
setModel(model);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
TableSortState defaultSortState = createSortState(0, true);
|
||||
this.tableSortState = defaultSortState;
|
||||
}
|
||||
|
||||
public void setModel(TableModel model) {
|
||||
if (model == null) {
|
||||
throw new NullPointerException("Model cannot be null!");
|
||||
}
|
||||
this.model = model;
|
||||
model.addTableModelListener(this);
|
||||
reallocateIndexes();
|
||||
}
|
||||
|
||||
public TableModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the sorter according to the enable parameter. This method
|
||||
* should be called with enable set to <b>false</b> <i>before</i> the table
|
||||
* model is populated or else a sort will be done after each row is
|
||||
* inserted, and that would not be good.
|
||||
* @param enable true means to enable the sorting.
|
||||
*/
|
||||
public void enableSorter(boolean enable) {
|
||||
sortEnabled = enable;
|
||||
if (!sortEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
reallocateIndexes();
|
||||
sort();
|
||||
|
||||
SystemUtilities.runIfSwingOrPostSwingLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
notifySorted();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void notifySorted() {
|
||||
fireTableChangedEvent();
|
||||
|
||||
for (SortListener listener : listeners) {
|
||||
listener.modelSorted(tableSortState);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireTableChangedEvent() {
|
||||
fireTableChanged(new TableModelEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSortListener(SortListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
public void registerComparator(Comparator<?> comparator, int column) {
|
||||
registeredComparatorMap.put(column, comparator);
|
||||
}
|
||||
|
||||
public void deRegisterComparator(int column) {
|
||||
registeredComparatorMap.remove(column);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
// for the Comparator<?> usage
|
||||
private int compareRowsByColumn(int row1, int row2, int column) {
|
||||
TableModel data = model;
|
||||
Object o1 = data.getValueAt(row1, column);
|
||||
Object o2 = data.getValueAt(row2, column);
|
||||
|
||||
// If both values are null return 0
|
||||
if (o1 == null && o2 == null) {
|
||||
return 0;
|
||||
}
|
||||
else if (o1 == null) { // Define null less than everything.
|
||||
return -1;
|
||||
}
|
||||
else if (o2 == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if the user has registered a comparator, prefer that
|
||||
Comparator comparator = getComparator(column);
|
||||
Object value1 = data.getValueAt(row1, column);
|
||||
Object value2 = data.getValueAt(row2, column);
|
||||
return comparator.compare(value1, value2);
|
||||
}
|
||||
|
||||
private Comparator<?> getComparator(int column) {
|
||||
Comparator<?> comparator = registeredComparatorMap.get(column);
|
||||
if (comparator != null) {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
return DEFAULT_COMPARATOR;
|
||||
}
|
||||
|
||||
private int compare(int row1, int row2) {
|
||||
|
||||
for (ColumnSortState columnSortState : tableSortState) {
|
||||
int result = compareRowsByColumn(row1, row2, columnSortState.getColumnModelIndex());
|
||||
if (result != 0) {
|
||||
return columnSortState.isAscending() ? result : -result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void reallocateIndexes() {
|
||||
int rowCount = model.getRowCount();
|
||||
|
||||
// Set up a new array of indexes with the right number of elements
|
||||
// for the new data model.
|
||||
indexes = new int[rowCount];
|
||||
|
||||
// Initialize with the identity mapping.
|
||||
for (int row = 0; row < rowCount; row++) {
|
||||
indexes[row] = row;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
if (sortEnabled) {
|
||||
reallocateIndexes();
|
||||
sort();
|
||||
}
|
||||
fireTableChanged(e);
|
||||
}
|
||||
|
||||
private void checkModel() {
|
||||
if (indexes.length == model.getRowCount()) {
|
||||
return; // O.K.!
|
||||
}
|
||||
|
||||
if (!sortEnabled) {
|
||||
return; // don't report an issue if we are called while in the middle of updating
|
||||
}
|
||||
|
||||
Msg.error(this, "Sorter not informed of a change in model.");
|
||||
}
|
||||
|
||||
private void sort() {
|
||||
checkModel();
|
||||
|
||||
shuttlesort(indexes.clone(), indexes, 0, indexes.length);
|
||||
}
|
||||
|
||||
// This is a home-grown implementation which we have not had time
|
||||
// to research - it may perform poorly in some circumstances. It
|
||||
// requires twice the space of an in-place algorithm and makes
|
||||
// NlogN assignments shuttling the values between the two
|
||||
// arrays. The number of compares appears to vary between N-1 and
|
||||
// NlogN depending on the initial order but the main reason for
|
||||
// using it here is that, unlike qsort, it is stable.
|
||||
private void shuttlesort(int[] from, int[] to, int low, int high) {
|
||||
if (high - low < 2) {
|
||||
return;
|
||||
}
|
||||
int middle = (low + high) / 2;
|
||||
shuttlesort(to, from, low, middle);
|
||||
shuttlesort(to, from, middle, high);
|
||||
|
||||
int p = low;
|
||||
int q = middle;
|
||||
|
||||
/* This is an optional short-cut; at each recursive call,
|
||||
check to see if the elements in this subset are already
|
||||
ordered. If so, no further comparisons are needed; the
|
||||
sub-array can just be copied. The array must be copied rather
|
||||
than assigned otherwise sister calls in the recursion might
|
||||
get out of sinc. When the number of elements is three they
|
||||
are partitioned so that the first set, [low, mid), has one
|
||||
element and and the second, [mid, high), has two. We skip the
|
||||
optimization when the number of elements is three or less as
|
||||
the first compare in the normal merge will produce the same
|
||||
sequence of steps. This optimization seems to be worthwhile
|
||||
for partially ordered lists but some analysis is needed to
|
||||
find out how the performance drops to Nlog(N) as the initial
|
||||
order diminishes - it may drop very quickly. */
|
||||
|
||||
if (high - low >= 4 && compare(from[middle - 1], from[middle]) <= 0) {
|
||||
for (int i = low; i < high; i++) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// A normal merge.
|
||||
|
||||
for (int i = low; i < high; i++) {
|
||||
if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
|
||||
to[i] = from[p++];
|
||||
}
|
||||
else {
|
||||
to[i] = from[q++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableModel#getValueAt(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Object getValueAt(int aRow, int aColumn) {
|
||||
checkModel();
|
||||
return model.getValueAt(indexes[aRow], aColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a sorted index into an unsorted index.
|
||||
* This is good if you need to access the underlying table directly by
|
||||
* the unsorted index.
|
||||
*/
|
||||
public int getSortedIndex(int aRow) {
|
||||
checkModel();
|
||||
return indexes[aRow];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
|
||||
*/
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int aRow, int aColumn) {
|
||||
checkModel();
|
||||
model.setValueAt(aValue, indexes[aRow], aColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the model in ascending order by the specified columnIndex.
|
||||
* @param column the index of the column to sort
|
||||
*/
|
||||
public void sortByColumn(int column) {
|
||||
ColumnSortState sortState = new ColumnSortState(column, SortDirection.ASCENDING, 1);
|
||||
TableSortState newCollection = new TableSortState(sortState);
|
||||
setTableSortState(newCollection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void resort() {
|
||||
tableChanged(new TableModelEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableSortState getTableSortState() {
|
||||
return tableSortState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTableSortState(TableSortState sortStates) {
|
||||
this.tableSortState = sortStates;
|
||||
resort();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Delegate Methods - We are a wrapper
|
||||
//==================================================================================================
|
||||
|
||||
/**
|
||||
*
|
||||
* @see javax.swing.table.TableModel#getRowCount()
|
||||
*/
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
// Always rely on the indexed values as the count. This prevents getValueAt() from
|
||||
// being called when the indexes are out-of-date, while the client is manipulating the table
|
||||
return indexes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see javax.swing.table.TableModel#getColumnCount()
|
||||
*/
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return model.getColumnCount();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see javax.swing.table.TableModel#getColumnName(int)
|
||||
*/
|
||||
@Override
|
||||
public String getColumnName(int aColumn) {
|
||||
return model.getColumnName(aColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see javax.swing.table.TableModel#getColumnClass(int)
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getColumnClass(int aColumn) {
|
||||
return model.getColumnClass(aColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see javax.swing.table.TableModel#isCellEditable(int, int)
|
||||
*/
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
return model.isCellEditable(row, column);
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,6 @@ import java.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -40,17 +39,8 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||
* filtered, the contents change (and then change back when the filter is removed). It is nice
|
||||
* to be able to filter a table, select an item of interest, and then unfilter the table to see
|
||||
* that item in more context.
|
||||
* <p>
|
||||
* Notes on usage:
|
||||
* <ul>
|
||||
* <li>Some table models are sensitive to the order in which {@link TableModel#tableChanged()}
|
||||
* is called. These models should either not use this SelectionManger, or need to
|
||||
* change their code to be more robust. As an example, the {@link DefaultSortedTableModel}
|
||||
* updates its indexes in odd ways. Further, there is a chance that the state of its
|
||||
* indexing is incorrect when <tt>tableChanged</tt> is called. So, that model has to
|
||||
* account for the fact that it may get called by this class when it is in a bad state.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> the row type
|
||||
*/
|
||||
public class RowObjectSelectionManager<T> extends DefaultListSelectionModel
|
||||
implements SelectionManager {
|
||||
@ -109,14 +99,6 @@ public class RowObjectSelectionManager<T> extends DefaultListSelectionModel
|
||||
installListSelectionListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logger used by this class. Useful for debugging individual table issues.
|
||||
*/
|
||||
@Override
|
||||
public void setLogger(Logger logger) {
|
||||
this.log = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSelectionManagerListener(SelectionManagerListener listener) {
|
||||
listeners.add(listener);
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package docking.widgets.table;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.table.TableModel;
|
||||
@ -29,11 +30,7 @@ public interface RowObjectTableModel<T> extends TableModel {
|
||||
|
||||
public static TableModel unwrap(TableModel m) {
|
||||
|
||||
// TODO can we now get rid of the default sorted model usage?
|
||||
TableModel model = m;
|
||||
while (model instanceof DefaultSortedTableModel) {
|
||||
model = ((DefaultSortedTableModel) model).getModel();
|
||||
}
|
||||
while (model instanceof TableModelWrapper) {
|
||||
model = ((TableModelWrapper<?>) model).getWrappedModel();
|
||||
}
|
||||
@ -52,6 +49,7 @@ public interface RowObjectTableModel<T> extends TableModel {
|
||||
* non-filtering models the view and model rows will always be the same.
|
||||
*
|
||||
* @param viewRow the row for which to return a row object.
|
||||
* @return the row object
|
||||
*/
|
||||
public T getRowObject(int viewRow);
|
||||
|
||||
@ -77,7 +75,7 @@ public interface RowObjectTableModel<T> extends TableModel {
|
||||
* the underlying data and not a copy, as this method will potentially sort the given data.
|
||||
* <p>
|
||||
* For those subclasses using an array, you may use the <tt>Arrays</tt> class to create
|
||||
* a list backed by the array ({@link Arrays#asList(Object...)).
|
||||
* a list backed by the array ({@link Arrays#asList(Object...)}).
|
||||
* @return the model data.
|
||||
*/
|
||||
public List<T> getModelData();
|
||||
|
@ -17,9 +17,6 @@ package docking.widgets.table;
|
||||
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* A class to track and restore selections made in a table. We use this in the docking
|
||||
@ -27,17 +24,6 @@ import org.apache.logging.log4j.Logger;
|
||||
* filtered, the contents change (and then change back when the filter is removed). It is nice
|
||||
* to be able to filter a table, select an item of interest, and then unfilter the table to see
|
||||
* that item in more context.
|
||||
* <p>
|
||||
* Notes on usage:
|
||||
* <ul>
|
||||
* <li>Some table models are sensitive to the order in which {@link TableModel#tableChanged()}
|
||||
* is called. These models should either not use this SelectionManger, or need to
|
||||
* change their code to be more robust. As an example, the {@link DefaultSortedTableModel}
|
||||
* updates its indexes in odd ways. Further, there is a chance that the state of its
|
||||
* indexing is incorrect when <tt>tableChanged</tt> is called. So, that model has to
|
||||
* account for the fact that it may get called by this class when it is in a bad state.
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
public interface SelectionManager extends ListSelectionModel, TableModelListener {
|
||||
|
||||
@ -47,12 +33,5 @@ public interface SelectionManager extends ListSelectionModel, TableModelListener
|
||||
|
||||
public void clearSavedSelection();
|
||||
|
||||
/**
|
||||
* Allows clients to enable tracing by providing a logger with tracing enabled.
|
||||
* @param logger The logger to be used by this manager, which has tracing embedded in its
|
||||
* code.
|
||||
*/
|
||||
public void setLogger(Logger logger);
|
||||
|
||||
public void dispose();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user