diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java index 27ee48165b..fc03a5d0d1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,17 +15,9 @@ */ package ghidra.app.plugin.core.compositeeditor; -import java.awt.Component; - import docking.ActionContext; -import docking.DockingWindowManager; -import ghidra.program.model.data.Structure; import ghidra.util.exception.AssertException; -/** - * Action for use in the composite data type editor. - * This action has help associated with it. - */ public class AddBitFieldAction extends CompositeEditorTableAction { public final static String ACTION_NAME = "Add Bitfield"; @@ -45,33 +37,17 @@ public class AddBitFieldAction extends CompositeEditorTableAction { @Override public void actionPerformed(ActionContext context) { - - CompEditorModel editorModel = (CompEditorModel) model; - if (editorModel.getNumSelectedRows() != 1) { - return; - } - int rowIndex = model.getSelectedRows()[0]; - - BitFieldEditorDialog dlg = - new BitFieldEditorDialog(editorModel.viewComposite, provider.dtmService, - -(rowIndex + 1), model.showHexNumbers, - ordinal -> refreshTableAndSelection(editorModel, ordinal)); - Component c = provider.getComponent(); - DockingWindowManager.showDialog(c, dlg); - requestTableFocus(); - } - - private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) { - editorModel.notifyCompositeChanged(); + StructureEditorProvider structProvider = (StructureEditorProvider) provider; + structProvider.showAddBitFieldEditor(); } @Override public void adjustEnablement() { boolean enabled = true; CompEditorModel editorModel = (CompEditorModel) model; - // Union do not support non-packed placement of bitfields - if (!(editorModel.viewComposite instanceof Structure) || editorModel.isPackingEnabled() || - editorModel.getNumSelectedRows() != 1) { + // Unions do not support non-packed manipulation of bitfields + if (!(provider instanceof StructureEditorProvider structProvider) || + editorModel.isPackingEnabled() || editorModel.getNumSelectedRows() != 1) { enabled = false; } setEnabled(enabled); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java index 3d3ac48491..df224880e5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldPlacementComponent.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -171,6 +171,8 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable { if (!editUseEnabled && composite != null) { allocationByteSize = composite.getLength(); } + setBounds(0, 0, getPreferredWidth(), getPreferredHeight()); + invalidate(); init(null); } @@ -315,8 +317,8 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable { * (allocation unit size is determine by current {@link #allocationByteSize}). */ void refresh(int bitSize, int bitOffset) { - bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset); updatePreferredSize(); + bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset); repaint(); } @@ -333,8 +335,8 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable { void refresh(int byteSize, int byteOffset, int bitSize, int bitOffset) { this.allocationByteOffset = byteOffset; this.allocationByteSize = byteSize; - bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset); updatePreferredSize(); + bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset); repaint(); } @@ -1030,6 +1032,14 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable { rightChopBytes = rightChop; allocationBytes = allocationByteSize - leftChopBytes - rightChopBytes; + if (allocationBytes <= 0) { + int junk = 0; + // allocation shrunk - need to adjust window + + // TODO: Need to adjust view port sizing when allocationByteSize changes + + } + allocateBits(); layoutBits(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index a264661484..ef4a3f553a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -281,6 +281,7 @@ public abstract class CompositeEditorPanel extends JPanel if (cellEditor != null) { cellEditor.cancelCellEditing(); } + provider.closeDependentEditors(); } protected void stopCellEditing() { @@ -545,7 +546,7 @@ public abstract class CompositeEditorPanel extends JPanel } } - public void dataTypeManagerRestored() { + protected void dataTypeManagerRestored() { DataTypeManager originalDTM = model.getOriginalDataTypeManager(); if (originalDTM == null) { // editor unloaded diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java index 78e185ed6e..64fac24e0a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,6 +21,7 @@ import javax.swing.*; import docking.*; import docking.widgets.OptionDialog; +import docking.widgets.table.GTable; import generic.theme.GIcon; import ghidra.app.context.ProgramActionContext; import ghidra.app.services.DataTypeManagerService; @@ -338,4 +339,23 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter help.registerHelp(object, new HelpLocation(getHelpTopic(), getHelpName() + "_" + anchor)); } + protected void requestTableFocus() { + + JTable table = editorPanel.getTable(); + if (!table.isEditing()) { + table.requestFocus(); + return; + } + + if (table instanceof GTable gTable) { + gTable.requestTableEditorFocus(); + } + else { + table.getEditorComponent().requestFocus(); + } + } + + protected void closeDependentEditors() { + // do nothing by default + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java index 884d85304c..5be06d1ba6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,6 @@ import java.awt.event.ActionListener; import javax.swing.*; import docking.action.*; -import docking.widgets.table.GTable; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; @@ -88,21 +87,8 @@ abstract public class CompositeEditorTableAction extends DockingAction implement } protected void requestTableFocus() { - if (provider == null) { - return; // must have been disposed - } - - JTable table = ((CompositeEditorPanel) provider.getComponent()).getTable(); - if (!table.isEditing()) { - table.requestFocus(); - return; - } - - if (table instanceof GTable gTable) { - gTable.requestTableEditorFocus(); - } - else { - table.getEditorComponent().requestFocus(); + if (provider != null) { + provider.requestTableFocus(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java index a4971ca35e..d56f4d43e1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,14 +15,7 @@ */ package ghidra.app.plugin.core.compositeeditor; -import java.awt.Component; - -import javax.swing.JTable; - import docking.ActionContext; -import docking.DockingWindowManager; -import ghidra.program.model.data.DataTypeComponent; -import ghidra.program.model.data.Structure; import ghidra.util.exception.AssertException; public class EditBitFieldAction extends CompositeEditorTableAction { @@ -41,50 +34,18 @@ public class EditBitFieldAction extends CompositeEditorTableAction { adjustEnablement(); } - private DataTypeComponent getUnalignedBitFieldComponent() { - CompEditorModel editorModel = (CompEditorModel) model; - if ((editorModel.viewComposite instanceof Structure) && - !editorModel.viewComposite.isPackingEnabled() && - editorModel.getNumSelectedRows() == 1) { - int rowIndex = model.getSelectedRows()[0]; - if (rowIndex < model.getNumComponents()) { - DataTypeComponent dtComponent = model.getComponent(rowIndex); - if (dtComponent.isBitFieldComponent()) { - return dtComponent; - } - } - } - return null; - } - @Override public void actionPerformed(ActionContext context) { - - CompEditorModel editorModel = (CompEditorModel) model; - - DataTypeComponent dtComponent = getUnalignedBitFieldComponent(); - if (dtComponent == null) { - return; - } - - BitFieldEditorDialog dlg = new BitFieldEditorDialog(editorModel.viewComposite, - provider.dtmService, dtComponent.getOrdinal(), model.showHexNumbers, - ordinal -> refreshTableAndSelection(editorModel, ordinal)); - Component c = provider.getComponent(); - DockingWindowManager.showDialog(c, dlg); - requestTableFocus(); - } - - private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) { - editorModel.fireTableDataChanged(); - editorModel.compositeInfoChanged(); - JTable editorTable = provider.getTable(); - editorTable.getSelectionModel().setSelectionInterval(ordinal, ordinal); + StructureEditorProvider structProvider = (StructureEditorProvider) provider; + structProvider.showBitFieldEditor(); } @Override public void adjustEnablement() { - setEnabled(getUnalignedBitFieldComponent() != null); + // Unions do not support non-packed manipulation of bitfields + boolean enabled = (provider instanceof StructureEditorProvider structProvider) && + structProvider.getSelectedNonPackedBitFieldComponent() != null; + setEnabled(enabled); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java index 488dc5c516..84a44951cd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,15 +17,20 @@ package ghidra.app.plugin.core.compositeeditor; import javax.swing.Icon; +import docking.DockingWindowManager; import generic.theme.GIcon; import ghidra.framework.plugintool.Plugin; +import ghidra.program.model.data.DataTypeComponent; import ghidra.program.model.data.Structure; +import ghidra.util.Msg; /** * Editor for a Structure Data Type. */ public class StructureEditorProvider extends CompositeEditorProvider { + private BitFieldEditorDialog bitFieldEditor; + protected static final Icon STRUCTURE_EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider.structure"); @@ -95,4 +100,69 @@ public class StructureEditorProvider extends CompositeEditorProvider { editorPanel.selectField(fieldName); } } + + @Override + protected void closeDependentEditors() { + if (bitFieldEditor != null && bitFieldEditor.isVisible()) { + bitFieldEditor.close(); + } + } + + private void refreshTableAndSelection(int ordinal) { + editorModel.notifyCompositeChanged(); + editorModel.setSelection(new int[] { ordinal, ordinal }); + } + + void showAddBitFieldEditor() { + + int[] selectedRows = editorModel.getSelectedRows(); + +// TODO: Add w/ GP-4740 merge +// if (editorPanel.hasInvalidEntry() || editorPanel.hasUncomittedEntry() || +// selectedRows.length != 1 || editorModel.viewComposite.isPackingEnabled()) { +// Msg.error(this, "Unsupported add bitfield editor use"); +// return; +// } + + bitFieldEditor = + new BitFieldEditorDialog(editorModel.viewComposite, dtmService, -(selectedRows[0] + 1), + editorModel.showHexNumbers, ordinal -> refreshTableAndSelection(ordinal)); + + DockingWindowManager.showDialog(editorPanel, bitFieldEditor); + requestTableFocus(); + } + + void showBitFieldEditor() { + + DataTypeComponent dtComponent = getSelectedNonPackedBitFieldComponent(); + if (dtComponent == null) { + Msg.error(this, "Unsupported bitfield editor use"); + return; + } + + bitFieldEditor = new BitFieldEditorDialog(editorModel.viewComposite, dtmService, + dtComponent.getOrdinal(), editorModel.showHexNumbers, + ordinal -> refreshTableAndSelection(ordinal)); + DockingWindowManager.showDialog(editorPanel, bitFieldEditor); + requestTableFocus(); + } + + /** + * Get the selected bitfield component if contained within a non-packed structure + * @return selected bitfield component or null + */ + DataTypeComponent getSelectedNonPackedBitFieldComponent() { + if (!editorModel.viewComposite.isPackingEnabled() && + editorModel.getNumSelectedRows() == 1) { + int rowIndex = editorModel.getSelectedRows()[0]; + if (rowIndex < editorModel.getNumComponents()) { + DataTypeComponent dtComponent = editorModel.getComponent(rowIndex); + if (dtComponent.isBitFieldComponent()) { + return dtComponent; + } + } + } + return null; + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java index ca45b6fa2e..7647bb72ba 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -274,7 +274,7 @@ public class StackEditorPanel extends CompositeEditorPanel { } @Override - public void dataTypeManagerRestored() { + protected void dataTypeManagerRestored() { boolean reload = true; String objectType = "program"; DataTypeManager dtm = ((StackEditorModel) model).getOriginalDataTypeManager();