diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java index 3d1c21d610..36e69dc548 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPlugin.java @@ -205,9 +205,9 @@ public class DataTypeManagerPlugin extends ProgramPlugin } /** - * Add project pathname to recently opened list. - * @param projectName - * @param pathname + * Add project archive name to recently opened list + * @param projectName the project name + * @param pathname the pathname */ public void addRecentlyOpenedProjectArchive(String projectName, String pathname) { String projectPathname = DataTypeManagerHandler.getProjectPathname(projectName, pathname); @@ -239,8 +239,8 @@ public class DataTypeManagerPlugin extends ProgramPlugin /** * Get a project archive file by project name and pathname - * @param projectName - * @param pathname + * @param projectName the project name + * @param pathname the project pathname * @return project archive domain file or null if it does not exist * or can not be found (e.g., projectName is not the active project) */ @@ -272,10 +272,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin dataTypeManagerHandler.dispose(); } - /** - * Tells the Plugin to read its data-independant (preferences) - * properties from the input stream. - */ @Override public void readConfigState(SaveState saveState) { dataTypeManagerHandler.restore(saveState); @@ -311,10 +307,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin dataTypePropertyManager.programClosed(program); } - /** - * Program was opened. - * @param program - */ @Override protected void programActivated(Program program) { program.addListener(this); @@ -574,7 +566,6 @@ public class DataTypeManagerPlugin extends ProgramPlugin openDialog.addOkActionListener(listener); } tool.showDialog(openDialog); -// updateActions(); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java index 32588ff96d..902a19b7e6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesProvider.java @@ -83,7 +83,8 @@ public class DataTypesProvider extends ComponentProviderAdapter { private HelpLocation helpLocation; private DataTypeManagerPlugin plugin; - private HistoryList navigationHistory = new HistoryList<>(15, dt -> { + private HistoryList navigationHistory = new HistoryList<>(15, url -> { + DataType dt = url.getDataType(plugin); setDataTypeSelected(dt); }); private MultiActionDockingAction nextAction; @@ -465,35 +466,12 @@ public class DataTypesProvider extends ComponentProviderAdapter { try { url = new DataTypeIdUrl(href); } - catch (NumberFormatException e) { - Msg.debug(this, "Could not parse Data Type ID URL '" + href + "'"); + catch (IllegalArgumentException e) { + Msg.debug(this, "Could not parse Data Type ID URL '" + href + "'", e); return null; } - DataTypeManager manager = getManager(url); - if (manager == null) { - // this shouldn't be possible, unless the url is old and the manager has been closed - Msg.debug(this, "Could not find data type for " + event.getDescription()); - return null; - } - - DataType dt = manager.findDataTypeForID(url.getDataTypeId()); - return dt; - } - - private DataTypeManager getManager(DataTypeIdUrl url) { - UniversalID id = url.getDataTypeManagerId(); - return getManager(id); - } - - private DataTypeManager getManager(UniversalID id) { - DataTypeManager[] mgs = plugin.getDataTypeManagers(); - for (DataTypeManager dtm : mgs) { - if (dtm.getUniversalID().equals(id)) { - return dtm; - } - } - return null; + return url.getDataType(plugin); } private void updatePreviewPane() { @@ -550,6 +528,7 @@ public class DataTypesProvider extends ComponentProviderAdapter { void dispose() { previewUpdateManager.dispose(); archiveGTree.dispose(); + navigationHistory.clear(); } @Override @@ -861,6 +840,10 @@ public class DataTypesProvider extends ComponentProviderAdapter { return conflictMode.getHandler(); } + DataTypeManagerPlugin getPlugin() { + return plugin; + } + private DataType getDataTypeFrom(TreePath path) { if (path == null) { return null; @@ -876,7 +859,7 @@ public class DataTypesProvider extends ComponentProviderAdapter { return dt; } - HistoryList getNavigationHistory() { + HistoryList getNavigationHistory() { return navigationHistory; } @@ -898,7 +881,11 @@ public class DataTypesProvider extends ComponentProviderAdapter { return; // Ignore events from the GTree's housekeeping } - navigationHistory.add(dt); + if (dt == null) { + return; + } + + navigationHistory.add(new DataTypeIdUrl(dt)); contextChanged(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/NextPreviousDataTypeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/NextPreviousDataTypeAction.java index 0a5670d34f..890549d45c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/NextPreviousDataTypeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/NextPreviousDataTypeAction.java @@ -23,6 +23,7 @@ import javax.swing.Icon; import docking.ActionContext; import docking.action.*; import docking.menu.MultiActionDockingAction; +import ghidra.app.util.datatype.DataTypeIdUrl; import ghidra.base.actions.HorizontalRuleAction; import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataTypeManager; @@ -38,7 +39,7 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction { private boolean isNext; private String owner; private DataTypesProvider provider; - private HistoryList history; + private HistoryList history; public NextPreviousDataTypeAction(DataTypesProvider provider, String owner, boolean isNext) { super(isNext ? "Next Data Type in History" : "Previous Data Type in History", owner); @@ -92,19 +93,19 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction { DataTypeManager lastDtm = null; List results = new ArrayList<>(); - List types = + List types = isNext ? history.getNextHistoryItems() : history.getPreviousHistoryItems(); - for (DataType dt : types) { + for (DataTypeIdUrl url : types) { + DataType dt = url.getDataType(provider.getPlugin()); DataTypeManager dtm = dt.getDataTypeManager(); - if (dtm != lastDtm && !results.isEmpty()) { // add a separator to show the user they are navigating across managers results.add(createHorizontalRule(lastDtm, dtm)); } - results.add(new NavigationAction(dt)); + results.add(new NavigationAction(dt.getDisplayName())); lastDtm = dtm; } @@ -122,10 +123,10 @@ class NextPreviousDataTypeAction extends MultiActionDockingAction { private class NavigationAction extends DockingAction { - private NavigationAction(DataType dt) { + private NavigationAction(String dtDisplayName) { super("DataTypeNavigationAction_" + ++navigationActionIdCount, owner); - setMenuBarData(new MenuData(new String[] { dt.getDisplayName() })); + setMenuBarData(new MenuData(new String[] { dtDisplayName })); setEnabled(true); setHelpLocation(new HelpLocation("DataTypeManagerPlugin", "Navigation_Actions")); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java index edd10c26b6..61c41683db 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/ArchiveNode.java @@ -223,7 +223,7 @@ public class ArchiveNode extends CategoryNode { return null; } - CategoryNode node = findCategoryNode(parentCategory); + CategoryNode node = findCategoryNode(parentCategory, loadChildren); if (node == null) { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeIdUrl.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeIdUrl.java index 2b5e67bdb0..c6d83d0547 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeIdUrl.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeIdUrl.java @@ -15,40 +15,52 @@ */ package ghidra.app.util.datatype; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.DataTypeManager; -import ghidra.util.Msg; +import ghidra.app.services.DataTypeManagerService; +import ghidra.program.model.data.*; import ghidra.util.UniversalID; /** * A class to produce and parse URLs of the form: *
- * 	datatype:/12345678/12345678
+ * 	datatype:/12345678?uid=12345678&name=Bob
  * 
* where the first number is the ID of the {@link DataTypeManager} and the second number is * the {@link DataType} ID. */ public class DataTypeIdUrl { + // see javadoc for format private static String PROTOCOL = "datatype"; - private static Pattern URL_PATTERN = Pattern.compile(PROTOCOL + ":/(\\d+)/(\\d+)"); + private static Pattern URL_PATTERN = + Pattern.compile(PROTOCOL + ":/(\\d+)\\?uid=(\\d*)&name=(\\w+)"); private UniversalID dataTypeManagerId; private UniversalID dataTypeId; + private String dataTypeName; + /** + * Constructs a url from the given data type + * @param dt the data type; cannot be null + */ public DataTypeIdUrl(DataType dt) { DataTypeManager dtm = dt.getDataTypeManager(); - if (dtm == null) { - Msg.debug(this, ""); - } - dataTypeManagerId = dtm.getUniversalID(); + dataTypeManagerId = Objects.requireNonNull(dtm.getUniversalID()); dataTypeId = dt.getUniversalID(); + dataTypeName = Objects.requireNonNull(dt.getName()); } - public DataTypeIdUrl(String url) { + /** + * Constructs a url from the given url string + * + * @param url the url + * @throws IllegalArgumentException if the url does not match the expected {@link #URL_PATTERN} + * or if there is an issue parsing the id within the given url + */ + public DataTypeIdUrl(String url) throws IllegalArgumentException { Matcher matcher = URL_PATTERN.matcher(url); if (!matcher.matches()) { @@ -57,8 +69,21 @@ public class DataTypeIdUrl { String dtmId = matcher.group(1); String dtId = matcher.group(2); - dataTypeManagerId = new UniversalID(Long.parseLong(dtmId)); - dataTypeId = new UniversalID(Long.parseLong(dtId)); + + try { + dataTypeManagerId = new UniversalID(Long.parseLong(dtmId)); + } + catch (NumberFormatException e) { + throw new IllegalArgumentException("Exception parsing Data Type Manager ID: ", e); + } + + try { + dataTypeId = new UniversalID(Long.parseLong(dtId)); + } + catch (NumberFormatException e) { + throw new IllegalArgumentException("Exception parsing Data Type ID: ", e); + } + dataTypeName = matcher.group(3); } public UniversalID getDataTypeManagerId() { @@ -69,8 +94,86 @@ public class DataTypeIdUrl { return dataTypeId; } + /** + * Uses the given service and its {@link DataTypeManager}s to find the data type + * represented by this url + * + * @param service the service + * @return the data type; null if there was an error restoring the type, such as if the + * parent {@link DataTypeManager} has been closed + */ + public DataType getDataType(DataTypeManagerService service) { + + DataTypeManager manager = findManager(service); + if (manager == null) { + return null; + } + + if (dataTypeId == null) { + // The ID will be null for built-in types. In that case, the name will not be + // null. Further, built-in types live at the root, so we can just ask for the + // type by name. + return manager.getDataType(new DataTypePath(CategoryPath.ROOT, dataTypeName)); + } + + DataType dt = manager.findDataTypeForID(dataTypeId); + return dt; + } + + private DataTypeManager findManager(DataTypeManagerService service) { + return getManagerById(service); + } + + private DataTypeManager getManagerById(DataTypeManagerService service) { + DataTypeManager[] mgs = service.getDataTypeManagers(); + for (DataTypeManager dtm : mgs) { + if (dtm.getUniversalID().equals(dataTypeManagerId)) { + return dtm; + } + } + return null; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((dataTypeId == null) ? 0 : dataTypeId.hashCode()); + result = prime * result + ((dataTypeManagerId == null) ? 0 : dataTypeManagerId.hashCode()); + result = prime * result + ((dataTypeName == null) ? 0 : dataTypeName.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; + } + + DataTypeIdUrl other = (DataTypeIdUrl) obj; + if (!Objects.equals(dataTypeId, other.dataTypeId)) { + return false; + } + + if (!Objects.equals(dataTypeManagerId, other.dataTypeManagerId)) { + return false; + } + + if (!Objects.equals(dataTypeName, other.dataTypeName)) { + return false; + } + return true; + } + @Override public String toString() { - return PROTOCOL + ":/" + dataTypeManagerId.toString() + '/' + dataTypeId.toString(); + return PROTOCOL + ":/" + dataTypeManagerId.toString() + "?uid=" + + Objects.toString(dataTypeId, "") + "&name=" + dataTypeName; } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java index a4f2965880..ea68acb6de 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.datamgr; -import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import java.awt.Container; @@ -24,7 +24,8 @@ import java.awt.event.KeyEvent; import java.io.File; import java.io.FileNotFoundException; import java.net.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -39,10 +40,6 @@ import docking.action.DockingActionIf; import docking.action.ToggleDockingActionIf; import docking.actions.KeyBindingUtils; import docking.widgets.OptionDialog; -import docking.widgets.combobox.GhidraComboBox; -import docking.widgets.dialogs.InputWithChoicesDialog; -import docking.widgets.fieldpanel.support.Highlight; -import docking.widgets.table.threaded.ThreadedTableModel; import docking.widgets.tree.GTreeNode; import ghidra.app.context.ProgramActionContext; import ghidra.app.plugin.core.datamgr.actions.CreateTypeDefDialog; @@ -50,23 +47,15 @@ import ghidra.app.plugin.core.datamgr.archive.Archive; import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler; import ghidra.app.plugin.core.datamgr.tree.*; import ghidra.app.plugin.core.function.EditFunctionSignatureDialog; -import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesPlugin; -import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesProvider; import ghidra.app.plugin.core.programtree.ProgramTreePlugin; -import ghidra.app.services.CodeViewerService; import ghidra.app.services.ProgramManager; -import ghidra.app.util.HighlightProvider; import ghidra.app.util.datatype.DataTypeSelectionEditor; -import ghidra.app.util.viewer.field.*; -import ghidra.app.util.viewer.format.FormatManager; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; import ghidra.program.database.data.ProgramDataTypeManager; -import ghidra.program.model.address.*; import ghidra.program.model.data.*; -import ghidra.program.model.listing.*; import ghidra.test.*; import ghidra.util.Msg; import ghidra.util.classfinder.ClassFilter; @@ -856,85 +845,6 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe return builtinNode; } - private void findReferencesToField(String choice) { - DockingActionIf searchAction = getAction(plugin, "Find Uses of Field"); - assertTrue(searchAction.isEnabledForContext(treeContext)); - DataTypeTestUtils.performAction(searchAction, tree, false); - - InputWithChoicesDialog d = waitForDialogComponent(InputWithChoicesDialog.class); - @SuppressWarnings("unchecked") - GhidraComboBox combo = (GhidraComboBox) getInstanceField("combo", d); - setComboBoxSelection(combo, choice); - pressButtonByText(d, "OK"); - - waitForSearchResults(); - } - - @SuppressWarnings("unchecked") - private LocationReferencesProvider getLocationReferencesProvider() { - LocationReferencesPlugin locationRefsPlugin = - getPlugin(tool, LocationReferencesPlugin.class); - - List providerList = - (List) getInstanceField("providerList", locationRefsPlugin); - if (providerList.size() == 0) { - return null; - } - return providerList.get(0); - } - - private ThreadedTableModel getTableModel() { - - waitForCondition(() -> getLocationReferencesProvider() != null); - - LocationReferencesProvider refsProvider = getLocationReferencesProvider(); - Object referencesPanel = getInstanceField("referencesPanel", refsProvider); - return (ThreadedTableModel) getInstanceField("tableModel", referencesPanel); - } - - private void waitForSearchResults() { - ThreadedTableModel model = getTableModel(); - waitForTableModel(model); - } - - private HighlightProvider getHighlightProvider() { - CodeViewerService service = tool.getService(CodeViewerService.class); - FormatManager fm = (FormatManager) getInstanceField("formatMgr", service); - return (HighlightProvider) getInstanceField("highlightProvider", fm); - } - - private void assertOperandHighlight(String rep, Address addr) { - assertHighlight(OperandFieldFactory.class, rep, addr); - } - - private void assertFieldNameHighlight(String rep, Address addr) { - assertHighlight(FieldNameFieldFactory.class, rep, addr); - } - - private void assertHighlight(Class clazz, String rep, Address addr) { - Listing listing = program.getListing(); - CodeUnit cu = listing.getCodeUnitContaining(addr); - if (cu instanceof Data) { - Data data = (Data) cu; - Address minAddress = data.getMinAddress(); - long offset = addr.subtract(minAddress); - if (offset != 0) { - Data subData = data.getComponentAt((int) offset); - cu = subData; - } - } - HighlightProvider highlighter = getHighlightProvider(); - Highlight[] highlights = highlighter.getHighlights(rep, cu, clazz, -1); - assertNotNull(highlights); - assertTrue(highlights.length != 0); - } - - private Address addr(long offset) { - AddressFactory addrMap = program.getAddressFactory(); - AddressSpace space = addrMap.getDefaultAddressSpace(); - return space.getAddress(offset); - } - private void assertSingleFilterMatch(String[] path) { GTreeNode rootNode = tree.getRootNode(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeTestUtils.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeTestUtils.java index 4ee38b921c..76636a4558 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeTestUtils.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeTestUtils.java @@ -31,6 +31,7 @@ import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree; import ghidra.program.model.data.*; import ghidra.program.model.listing.Program; import ghidra.util.Msg; +import ghidra.util.Swing; import ghidra.util.task.TaskMonitor; import utilities.util.FileUtilities; @@ -146,20 +147,18 @@ public class DataTypeTestUtils { static void closeArchive(final ArchiveNode archiveNode, final boolean deleteFile) throws Exception { - final Exception[] container = new Exception[1]; - - SwingUtilities.invokeAndWait(() -> { + Exception exception = Swing.runNow(() -> { try { doCloseArchive(archiveNode, deleteFile); + return null; } catch (Exception e) { - container[0] = e; + return e; } }); - if (container[0] != null) { - throw new RuntimeException("Exception closing archive on Swing thread!: ", - container[0]); + if (exception != null) { + throw new RuntimeException("Exception closing archive on Swing thread!: ", exception); } } diff --git a/Ghidra/Framework/Generic/src/main/java/util/HistoryList.java b/Ghidra/Framework/Generic/src/main/java/util/HistoryList.java index cec5435567..e8488e8627 100644 --- a/Ghidra/Framework/Generic/src/main/java/util/HistoryList.java +++ b/Ghidra/Framework/Generic/src/main/java/util/HistoryList.java @@ -82,6 +82,10 @@ public class HistoryList { * True signals that this list will allow duplicate entries. False signals to not only not * allow duplicates, but to also move the position of an item if it is re-added to the * list. + * + *

For correct behavior when not allowing duplicates, ensure you have defined an + * equals method to work as you expect. If two different items are considered + * equal, then this class will only remove the duplicate if the equals method returns true. * *

The default is false * @@ -162,7 +166,6 @@ public class HistoryList { *

No action is taken if the current pointer is already at the beginning of the list. */ public void goBack() { - if (historyIndex == 0) { return; } @@ -217,7 +220,7 @@ public class HistoryList { /** * Get all items in the history that come after the current history item. They are - * returned in navigation order, as traversed if {@link #goForward() is called. + * returned in navigation order, as traversed if {@link #goForward()} is called. * * @return the items */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java index 099cf18969..95944ac173 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java @@ -31,8 +31,8 @@ import ghidra.util.task.TaskMonitorAdapter; * DataTypeManager for a file. Can import categories from a file, or export * categories to a packed database. */ -public class FileDataTypeManager extends StandAloneDataTypeManager implements - FileArchiveBasedDataTypeManager { +public class FileDataTypeManager extends StandAloneDataTypeManager + implements FileArchiveBasedDataTypeManager { public final static String EXTENSION = "gdt"; // Ghidra Data Types /** @@ -108,16 +108,15 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements * @param outputFilename filename for output * @param databaseId new databaseId */ - public void saveAs(File saveFile, UniversalID newUniversalId) throws DuplicateFileException, - IOException { + public void saveAs(File saveFile, UniversalID newUniversalId) + throws DuplicateFileException, IOException { ResourceFile resourceSaveFile = new ResourceFile(saveFile); // TODO: this should really be a package method and not public! validateFilename(resourceSaveFile); try { universalID = newUniversalId; - packedDB = - ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(), - saveFile.getName(), newUniversalId.getValue(), TaskMonitorAdapter.DUMMY_MONITOR); + packedDB = ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(), + saveFile.getName(), newUniversalId.getValue(), TaskMonitorAdapter.DUMMY_MONITOR); file = resourceSaveFile; updateRootCategoryName(resourceSaveFile, getRootCategory()); } @@ -134,9 +133,8 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements ResourceFile resourceSaveFile = new ResourceFile(saveFile); validateFilename(resourceSaveFile); try { - packedDB = - ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(), - saveFile.getName(), TaskMonitorAdapter.DUMMY_MONITOR); + packedDB = ((PackedDBHandle) dbHandle).saveAs("DTArchive", saveFile.getParentFile(), + saveFile.getName(), TaskMonitorAdapter.DUMMY_MONITOR); file = resourceSaveFile; updateRootCategoryName(resourceSaveFile, getRootCategory()); } @@ -268,4 +266,8 @@ public class FileDataTypeManager extends StandAloneDataTypeManager implements return ArchiveType.FILE; } + @Override + public String toString() { + return getClass().getSimpleName() + " - " + getName(); + } }