mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 23:46:35 +08:00
GP-1200 - Fixed UI live lock when connecting to remote project
This commit is contained in:
+11
-23
@@ -79,22 +79,22 @@ class ProgramSaveManager {
|
|||||||
List<Program> saveList = new ArrayList<>();
|
List<Program> saveList = new ArrayList<>();
|
||||||
List<Program> lockList = new ArrayList<>();
|
List<Program> lockList = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < programs.length; i++) {
|
for (Program program : programs) {
|
||||||
// if (programs[i].isTemporary()) {
|
// if (programs[i].isTemporary()) {
|
||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
if (isOnlyToolConsumer(programs[i])) {
|
if (isOnlyToolConsumer(program)) {
|
||||||
if (!acquireSaveLock(programs[i], "Close")) {
|
if (!acquireSaveLock(program, "Close")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lockList.add(programs[i]);
|
lockList.add(program);
|
||||||
saveList.add(programs[i]);
|
saveList.add(program);
|
||||||
}
|
}
|
||||||
else if (isAnalysisTool(programs[i])) {
|
else if (isAnalysisTool(program)) {
|
||||||
if (!acquireSaveLock(programs[i], "Close")) {
|
if (!acquireSaveLock(program, "Close")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lockList.add(programs[i]);
|
lockList.add(program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ class ProgramSaveManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOnlyToolConsumer(Program program) {
|
private boolean isOnlyToolConsumer(Program program) {
|
||||||
ArrayList<?> consumers = program.getDomainFile().getConsumers();
|
List<?> consumers = program.getDomainFile().getConsumers();
|
||||||
for (Object consumer : consumers) {
|
for (Object consumer : consumers) {
|
||||||
if ((consumer instanceof PluginTool) && consumer != tool) {
|
if ((consumer instanceof PluginTool) && consumer != tool) {
|
||||||
return false;
|
return false;
|
||||||
@@ -474,25 +474,15 @@ class ProgramSaveManager {
|
|||||||
return dataTreeSaveDialog;
|
return dataTreeSaveDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class SaveFileTask extends Task {
|
class SaveFileTask extends Task {
|
||||||
|
|
||||||
private DomainFile domainFile;
|
private DomainFile domainFile;
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct new SaveFileTask.
|
|
||||||
* @param df domain file to save
|
|
||||||
*/
|
|
||||||
SaveFileTask(DomainFile df) {
|
SaveFileTask(DomainFile df) {
|
||||||
super("Save Program", true, true, true);
|
super("Save Program", true, true, true);
|
||||||
this.domainFile = df;
|
this.domainFile = df;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.util.task.Task#run(TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TaskMonitor monitor) {
|
public void run(TaskMonitor monitor) {
|
||||||
monitor.setMessage("Saving Program...");
|
monitor.setMessage("Saving Program...");
|
||||||
@@ -500,6 +490,7 @@ class ProgramSaveManager {
|
|||||||
domainFile.save(monitor);
|
domainFile.save(monitor);
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
catch (NotConnectedException e) {
|
catch (NotConnectedException e) {
|
||||||
ClientUtil.promptForReconnect(tool.getProject().getRepository(),
|
ClientUtil.promptForReconnect(tool.getProject().getRepository(),
|
||||||
@@ -525,7 +516,7 @@ class ProgramSaveManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct new SaveFileTask to do a "Save As"
|
* Construct new SaveFileTask to do a "Save As"
|
||||||
* @param obj
|
* @param obj the object to save
|
||||||
* @param folder new parent folder
|
* @param folder new parent folder
|
||||||
* @param newName name for domain object
|
* @param newName name for domain object
|
||||||
* @param doOverwrite true means the given name already exists and the user
|
* @param doOverwrite true means the given name already exists and the user
|
||||||
@@ -541,9 +532,6 @@ class ProgramSaveManager {
|
|||||||
this.doOverwrite = doOverwrite;
|
this.doOverwrite = doOverwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.util.task.Task#run(TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TaskMonitor monitor) {
|
public void run(TaskMonitor monitor) {
|
||||||
monitor.setMessage("Saving Program...");
|
monitor.setMessage("Saving Program...");
|
||||||
|
|||||||
+10
-8
@@ -65,11 +65,12 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
|
|||||||
undoCheckOut();
|
undoCheckOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one of the provided domain files is checked out from the repository.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.isCheckedOut()) {
|
if (domainFile.isCheckedOut()) {
|
||||||
@@ -91,8 +92,8 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
|
|||||||
closeEditorsForUndoCheckOut();
|
closeEditorsForUndoCheckOut();
|
||||||
|
|
||||||
List<Archive> archiveList = archiveProvider.getArchives();
|
List<Archive> archiveList = archiveProvider.getArchives();
|
||||||
List<DomainFileArchive> unmodifiedCheckOutsList = new ArrayList<DomainFileArchive>();
|
List<DomainFileArchive> unmodifiedCheckOutsList = new ArrayList<>();
|
||||||
List<DomainFileArchive> modifiedCheckOutsList = new ArrayList<DomainFileArchive>();
|
List<DomainFileArchive> modifiedCheckOutsList = new ArrayList<>();
|
||||||
for (Archive archive2 : archiveList) {
|
for (Archive archive2 : archiveList) {
|
||||||
ProjectArchive archive = (ProjectArchive) archive2;
|
ProjectArchive archive = (ProjectArchive) archive2;
|
||||||
DomainFile domainFile = archive.getDomainFile();
|
DomainFile domainFile = archive.getDomainFile();
|
||||||
@@ -134,7 +135,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
|
|||||||
* will be undone.
|
* will be undone.
|
||||||
* @param unmodifiedArchivesList the list of unmodified archives
|
* @param unmodifiedArchivesList the list of unmodified archives
|
||||||
* @param modifiedArchivesList the list of archives that have been modified
|
* @param modifiedArchivesList the list of archives that have been modified
|
||||||
* @throws CancelledException
|
* @throws CancelledException if canclled
|
||||||
*/
|
*/
|
||||||
protected void undoCheckOuts(List<DomainFileArchive> unmodifiedArchivesList,
|
protected void undoCheckOuts(List<DomainFileArchive> unmodifiedArchivesList,
|
||||||
List<DomainFileArchive> modifiedArchivesList) throws CancelledException {
|
List<DomainFileArchive> modifiedArchivesList) throws CancelledException {
|
||||||
@@ -169,7 +170,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
|
|||||||
private List<DomainFileArchive> getMatchingArchives(List<DomainFileArchive> archivesList,
|
private List<DomainFileArchive> getMatchingArchives(List<DomainFileArchive> archivesList,
|
||||||
DomainFile[] selectedFiles) {
|
DomainFile[] selectedFiles) {
|
||||||
List<DomainFileArchive> archiveList =
|
List<DomainFileArchive> archiveList =
|
||||||
new ArrayList<DomainFileArchive>(selectedFiles.length);
|
new ArrayList<>(selectedFiles.length);
|
||||||
for (DomainFile domainFile : selectedFiles) {
|
for (DomainFile domainFile : selectedFiles) {
|
||||||
DomainFileArchive archive = getArchiveForDomainFile(archivesList, domainFile);
|
DomainFileArchive archive = getArchiveForDomainFile(archivesList, domainFile);
|
||||||
if (archive != null) {
|
if (archive != null) {
|
||||||
@@ -195,7 +196,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<DomainFile> getDomainFileList(List<DomainFileArchive> modifiedArchivesList) {
|
private List<DomainFile> getDomainFileList(List<DomainFileArchive> modifiedArchivesList) {
|
||||||
List<DomainFile> dfList = new ArrayList<DomainFile>(modifiedArchivesList.size());
|
List<DomainFile> dfList = new ArrayList<>(modifiedArchivesList.size());
|
||||||
for (DomainFileArchive dfArchive : modifiedArchivesList) {
|
for (DomainFileArchive dfArchive : modifiedArchivesList) {
|
||||||
dfList.add(dfArchive.getDomainFile());
|
dfList.add(dfArchive.getDomainFile());
|
||||||
}
|
}
|
||||||
@@ -205,6 +206,7 @@ public class VersionControlDataTypeArchiveUndoCheckoutAction extends VersionCont
|
|||||||
/**
|
/**
|
||||||
* Saves all checked out changes.
|
* Saves all checked out changes.
|
||||||
* @param changedList the list of changes
|
* @param changedList the list of changes
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
protected void saveCheckOutChanges(List<DomainFile> changedList) throws CancelledException {
|
protected void saveCheckOutChanges(List<DomainFile> changedList) throws CancelledException {
|
||||||
if (changedList.size() > 0) {
|
if (changedList.size() > 0) {
|
||||||
|
|||||||
+3
-42
@@ -55,7 +55,7 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a listener to this list.
|
* Add a listener to this list.
|
||||||
* @param listener
|
* @param listener the listener
|
||||||
*/
|
*/
|
||||||
public synchronized void add(FileSystemListener listener) {
|
public synchronized void add(FileSystemListener listener) {
|
||||||
listenerList.add(listener);
|
listenerList.add(listener);
|
||||||
@@ -68,7 +68,7 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a listener from this list.
|
* Remove a listener from this list.
|
||||||
* @param listener
|
* @param listener the listener
|
||||||
*/
|
*/
|
||||||
public void remove(FileSystemListener listener) {
|
public void remove(FileSystemListener listener) {
|
||||||
listenerList.remove(listener);
|
listenerList.remove(listener);
|
||||||
@@ -81,10 +81,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
listenerList.clear();
|
listenerList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards itemMoved callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#itemMoved(String, String, String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void itemMoved(String parentPath, String name, String newParentPath, String newName) {
|
public void itemMoved(String parentPath, String name, String newParentPath, String newName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -97,10 +93,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards itemRenamed callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#itemRenamed(String, String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void itemRenamed(String parentPath, String itemName, String newName) {
|
public void itemRenamed(String parentPath, String itemName, String newName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -113,10 +105,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards itemDeleted callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#itemDeleted(String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void itemDeleted(String parentPath, String itemName) {
|
public void itemDeleted(String parentPath, String itemName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -129,10 +117,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards folderRenamed callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#folderRenamed(String, String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void folderRenamed(String parentPath, String folderName, String newFolderName) {
|
public void folderRenamed(String parentPath, String folderName, String newFolderName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -145,10 +129,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards folderMoved callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#folderMoved(String, String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void folderMoved(String parentPath, String folderName, String newParentPath) {
|
public void folderMoved(String parentPath, String folderName, String newParentPath) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -161,10 +141,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards folderDeleted callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#folderDeleted(String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void folderDeleted(String parentPath, String folderName) {
|
public void folderDeleted(String parentPath, String folderName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -177,10 +153,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards itemCreated callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#itemCreated(String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void itemCreated(String parentPath, String itemName) {
|
public void itemCreated(String parentPath, String itemName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -193,10 +165,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards folderCreated callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#folderCreated(String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void folderCreated(String parentPath, String folderName) {
|
public void folderCreated(String parentPath, String folderName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -209,10 +177,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards itemChanged callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#itemChanged(String, String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void itemChanged(String parentPath, String itemName) {
|
public void itemChanged(String parentPath, String itemName) {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -225,10 +189,6 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forwards syncronize callback to all listeners within this list.
|
|
||||||
* @see ghidra.framework.store.FileSystemListener#syncronize()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void syncronize() {
|
public void syncronize() {
|
||||||
if (enableAsynchronousDispatching) {
|
if (enableAsynchronousDispatching) {
|
||||||
@@ -303,6 +263,7 @@ public class FileSystemListenerList implements FileSystemListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
|
// not sure why we are ignoring this
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
isEventProcessingThreadWaiting = false;
|
isEventProcessingThreadWaiting = false;
|
||||||
|
|||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.framework.store;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is essentially a global flag used to track the long running file system synchronizing
|
||||||
|
* operation. This class is a workaround to avoid rewriting the complicated file system locking.
|
||||||
|
*/
|
||||||
|
public class FileSystemSynchronizer {
|
||||||
|
|
||||||
|
private static AtomicBoolean isSynchronizing = new AtomicBoolean();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the synchronizing operation is running.
|
||||||
|
* @param b true if synchronizing
|
||||||
|
*/
|
||||||
|
public static void setSynchronizing(boolean b) {
|
||||||
|
isSynchronizing.set(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true the underlying file system is going through a long-running synchronization
|
||||||
|
* operation while holding the {@code filesystem} lock. Calling this method allows clients
|
||||||
|
* in the Swing thread to avoid calling methods that require a file system lock, which would
|
||||||
|
* cause the UI to lock during the synchronizing operation.
|
||||||
|
*
|
||||||
|
* @return true if synchronizing
|
||||||
|
*/
|
||||||
|
public static boolean isSynchronizing() {
|
||||||
|
return isSynchronizing.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-16
@@ -19,7 +19,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.Swing;
|
||||||
|
|
||||||
class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFolderAdded(folder);
|
listener.domainFolderAdded(folder);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileAdded(file);
|
listener.domainFileAdded(file);
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFolderRemoved(parent, name);
|
listener.domainFolderRemoved(parent, name);
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileRemoved(parent, name, fileID);
|
listener.domainFileRemoved(parent, name, fileID);
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFolderRenamed(folder, oldName);
|
listener.domainFolderRenamed(folder, oldName);
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileRenamed(file, oldName);
|
listener.domainFileRenamed(file, oldName);
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFolderMoved(folder, oldParent);
|
listener.domainFolderMoved(folder, oldParent);
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileMoved(file, oldParent, oldName);
|
listener.domainFileMoved(file, oldParent, oldName);
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFolderSetActive(folder);
|
listener.domainFolderSetActive(folder);
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileStatusChanged(file, fileIDset);
|
listener.domainFileStatusChanged(file, fileIDset);
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileObjectOpenedForUpdate(file, object);
|
listener.domainFileObjectOpenedForUpdate(file, object);
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SystemUtilities.runSwingLater(() -> {
|
Swing.runLater(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileObjectClosed(file, object);
|
listener.domainFileObjectClosed(file, object);
|
||||||
}
|
}
|
||||||
@@ -205,12 +205,11 @@ class DomainFolderChangeListenerList implements DomainFolderChangeListener {
|
|||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Runnable r = () -> {
|
Swing.runNow(() -> {
|
||||||
for (DomainFolderChangeListener listener : list) {
|
for (DomainFolderChangeListener listener : list) {
|
||||||
listener.domainFileObjectReplaced(file, oldObject);
|
listener.domainFileObjectReplaced(file, oldObject);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
SystemUtilities.runSwingNow(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAll() {
|
public void clearAll() {
|
||||||
|
|||||||
@@ -512,7 +512,7 @@ public class GhidraFile implements DomainFile {
|
|||||||
public ArrayList<?> getConsumers() {
|
public ArrayList<?> getConsumers() {
|
||||||
DomainObjectAdapter dobj = fileManager.getOpenedDomainObject(getPathname());
|
DomainObjectAdapter dobj = fileManager.getOpenedDomainObject(getPathname());
|
||||||
if (dobj == null) {
|
if (dobj == null) {
|
||||||
return new ArrayList<Object>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
return dobj.getConsumerList();
|
return dobj.getConsumerList();
|
||||||
}
|
}
|
||||||
@@ -554,7 +554,7 @@ public class GhidraFile implements DomainFile {
|
|||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
fileError(e);
|
fileError(e);
|
||||||
}
|
}
|
||||||
return new HashMap<String, String>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileChanged() {
|
void fileChanged() {
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ public class GhidraFolder implements DomainFolder {
|
|||||||
|
|
||||||
GhidraFolderData getFolderPathData(String folderPath) throws FileNotFoundException {
|
GhidraFolderData getFolderPathData(String folderPath) throws FileNotFoundException {
|
||||||
GhidraFolderData parentData = (folderPath.startsWith(FileSystem.SEPARATOR))
|
GhidraFolderData parentData = (folderPath.startsWith(FileSystem.SEPARATOR))
|
||||||
? fileManager.getRootFolderData() : getFolderData();
|
? fileManager.getRootFolderData()
|
||||||
|
: getFolderData();
|
||||||
GhidraFolderData folderData = parentData.getFolderPathData(folderPath, false);
|
GhidraFolderData folderData = parentData.getFolderPathData(folderPath, false);
|
||||||
if (folderData == null) {
|
if (folderData == null) {
|
||||||
String path = (folderPath.startsWith(FileSystem.SEPARATOR)) ? folderPath
|
String path = (folderPath.startsWith(FileSystem.SEPARATOR)) ? folderPath
|
||||||
|
|||||||
+44
-94
@@ -24,16 +24,14 @@ import ghidra.framework.client.*;
|
|||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
import ghidra.framework.protocol.ghidra.GhidraURL;
|
import ghidra.framework.protocol.ghidra.GhidraURL;
|
||||||
import ghidra.framework.remote.User;
|
import ghidra.framework.remote.User;
|
||||||
|
import ghidra.framework.store.*;
|
||||||
import ghidra.framework.store.FileSystem;
|
import ghidra.framework.store.FileSystem;
|
||||||
import ghidra.framework.store.FileSystemListener;
|
|
||||||
import ghidra.framework.store.FolderItem;
|
|
||||||
import ghidra.framework.store.local.LocalFileSystem;
|
import ghidra.framework.store.local.LocalFileSystem;
|
||||||
import ghidra.framework.store.remote.RemoteFileSystem;
|
import ghidra.framework.store.remote.RemoteFileSystem;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.DuplicateFileException;
|
import ghidra.util.exception.DuplicateFileException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.*;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,9 +141,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used for testing
|
|
||||||
*/
|
|
||||||
ProjectFileManager(LocalFileSystem fileSystem, FileSystem versionedFileSystem) {
|
ProjectFileManager(LocalFileSystem fileSystem, FileSystem versionedFileSystem) {
|
||||||
this.localStorageLocator = new ProjectLocator(null, "Test");
|
this.localStorageLocator = new ProjectLocator(null, "Test");
|
||||||
owner = SystemUtilities.getUserName();
|
owner = SystemUtilities.getUserName();
|
||||||
@@ -208,9 +203,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
fileSystem.testValidName(name, isPath);
|
fileSystem.testValidName(name, isPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getUser()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public User getUser() {
|
public User getUser() {
|
||||||
if (repository != null) {
|
if (repository != null) {
|
||||||
@@ -386,17 +378,11 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getRootFolder()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public GhidraFolder getRootFolder() {
|
public GhidraFolder getRootFolder() {
|
||||||
return rootFolderData.getDomainFolder();
|
return rootFolderData.getDomainFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getFolder(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public DomainFolder getFolder(String path) {
|
public DomainFolder getFolder(String path) {
|
||||||
int len = path.length();
|
int len = path.length();
|
||||||
@@ -429,9 +415,8 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we can't distinguish between files represented
|
// NOTE: we can't distinguish between files represented in both file counts so we will
|
||||||
// in both file counts so we will return the larger of
|
// return the larger of the two counts obtained.
|
||||||
// the two counts obtained.
|
|
||||||
|
|
||||||
int privateFileCnt = -1;
|
int privateFileCnt = -1;
|
||||||
try {
|
try {
|
||||||
@@ -452,9 +437,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
return Math.max(sharedFileCnt, privateFileCnt);
|
return Math.max(sharedFileCnt, privateFileCnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getFile(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public DomainFile getFile(String path) {
|
public DomainFile getFile(String path) {
|
||||||
int len = path.length();
|
int len = path.length();
|
||||||
@@ -480,17 +462,11 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getFileByID(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public DomainFile getFileByID(String fileID) {
|
public DomainFile getFileByID(String fileID) {
|
||||||
return fileIndex.getFileByID(fileID);
|
return fileIndex.getFileByID(fileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getSharedFileURL(java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public URL getSharedFileURL(String path) {
|
public URL getSharedFileURL(String path) {
|
||||||
if (repository != null) {
|
if (repository != null) {
|
||||||
@@ -504,10 +480,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Releases all domain files for the specified consumer.
|
|
||||||
* @param consumer the domain object consumer
|
|
||||||
*/
|
|
||||||
public void releaseDomainFiles(Object consumer) {
|
public void releaseDomainFiles(Object consumer) {
|
||||||
for (DomainObjectAdapter domainObj : openDomainObjects.values()) {
|
for (DomainObjectAdapter domainObj : openDomainObjects.values()) {
|
||||||
try {
|
try {
|
||||||
@@ -522,8 +494,7 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all changed domain files and appends
|
* Finds all changed domain files and appends them to the specified list.
|
||||||
* them to the specified list.
|
|
||||||
* @param list the list to receive the changed domain files
|
* @param list the list to receive the changed domain files
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@@ -533,52 +504,30 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#getProjectLocator()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ProjectLocator getProjectLocator() {
|
public ProjectLocator getProjectLocator() {
|
||||||
return localStorageLocator;
|
return localStorageLocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#addDomainFolderChangeListener(
|
|
||||||
* ghidra.framework.model.DomainFolderChangeListener)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void addDomainFolderChangeListener(DomainFolderChangeListener l) {
|
public void addDomainFolderChangeListener(DomainFolderChangeListener l) {
|
||||||
listenerList.addListener(l);
|
listenerList.addListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#removeDomainFolderChangeListener(
|
|
||||||
* ghidra.framework.model.DomainFolderChangeListener)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void removeDomainFolderChangeListener(DomainFolderChangeListener l) {
|
public void removeDomainFolderChangeListener(DomainFolderChangeListener l) {
|
||||||
listenerList.removeListener(l);
|
listenerList.removeListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the private files system associated with this project file manager.
|
|
||||||
* @return the private files system associated with this project file manager
|
|
||||||
*/
|
|
||||||
public FileSystem getPrivateFileSystem() {
|
public FileSystem getPrivateFileSystem() {
|
||||||
return fileSystem;
|
return fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the repository associated with this project file manager.
|
|
||||||
* @return the repository associated with this project file manager
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public RepositoryAdapter getRepository() {
|
public RepositoryAdapter getRepository() {
|
||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.framework.model.ProjectData#refresh(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh(boolean force) throws IOException {
|
public void refresh(boolean force) throws IOException {
|
||||||
try {
|
try {
|
||||||
@@ -589,12 +538,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see ghidra.framework.model.ProjectData#convertProjectToShared(
|
|
||||||
* ghidra.framework.client.RepositoryAdapter,
|
|
||||||
* ghidra.util.task.TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void convertProjectToShared(RepositoryAdapter newRepository, TaskMonitor monitor)
|
public void convertProjectToShared(RepositoryAdapter newRepository, TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
@@ -607,7 +550,7 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
throw new IllegalStateException("Only private project may be converted to shared");
|
throw new IllegalStateException("Only private project may be converted to shared");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1) Convert versioned files (inclulding checked-out files) to private files
|
// 1) Convert versioned files (including checked-out files) to private files
|
||||||
convertFilesToPrivate(getRootFolder(), monitor);
|
convertFilesToPrivate(getRootFolder(), monitor);
|
||||||
|
|
||||||
// 2) Update the properties with server info
|
// 2) Update the properties with server info
|
||||||
@@ -621,12 +564,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
FileUtilities.deleteDir(versionedFileSystemDir);
|
FileUtilities.deleteDir(versionedFileSystemDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see ghidra.framework.model.ProjectData#updateRepositoryInfo(
|
|
||||||
* ghidra.framework.client.RepositoryAdapter,
|
|
||||||
* ghidra.util.task.TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void updateRepositoryInfo(RepositoryAdapter newRepository, TaskMonitor monitor)
|
public void updateRepositoryInfo(RepositoryAdapter newRepository, TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
@@ -641,20 +578,20 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
|
||||||
DomainFile[] files = folder.getFiles();
|
DomainFile[] files = folder.getFiles();
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (DomainFile file : files) {
|
||||||
if (monitor.isCancelled()) {
|
if (monitor.isCancelled()) {
|
||||||
throw new CancelledException();
|
throw new CancelledException();
|
||||||
}
|
}
|
||||||
if (files[i].isCheckedOut()) {
|
if (file.isCheckedOut()) {
|
||||||
throw new IOException("File " + files[i].getPathname() + " is checked out.");
|
throw new IOException("File " + file.getPathname() + " is checked out.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DomainFolder[] folders = folder.getFolders();
|
DomainFolder[] folders = folder.getFolders();
|
||||||
for (int i = 0; i < folders.length; i++) {
|
for (DomainFolder folder2 : folders) {
|
||||||
if (monitor.isCancelled()) {
|
if (monitor.isCancelled()) {
|
||||||
throw new CancelledException();
|
throw new CancelledException();
|
||||||
}
|
}
|
||||||
findCheckedOutFiles(folders[i], monitor);
|
findCheckedOutFiles(folder2, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,12 +599,12 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
|
||||||
DomainFile[] files = folder.getFiles();
|
DomainFile[] files = folder.getFiles();
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (DomainFile file : files) {
|
||||||
((GhidraFile) files[i]).convertToPrivateFile(monitor);
|
((GhidraFile) file).convertToPrivateFile(monitor);
|
||||||
}
|
}
|
||||||
DomainFolder[] folders = folder.getFolders();
|
DomainFolder[] folders = folder.getFolders();
|
||||||
for (int i = 0; i < folders.length; i++) {
|
for (DomainFolder folder2 : folders) {
|
||||||
convertFilesToPrivate(folders[i], monitor);
|
convertFilesToPrivate(folder2, monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,12 +839,32 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncronize() {
|
public void syncronize() {
|
||||||
|
|
||||||
|
if (SystemUtilities.isInHeadlessMode()) {
|
||||||
|
doSynchronize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
FileSystemSynchronizer.setSynchronizing(true);
|
||||||
|
|
||||||
|
// This operation can hold a lock for a long period. Block with a modal dialog to
|
||||||
|
// prevent UI live lock situations.
|
||||||
|
TaskLauncher.launchModal("Synchronizing Filesystem", this::doSynchronize);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
FileSystemSynchronizer.setSynchronizing(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSynchronize() {
|
||||||
try {
|
try {
|
||||||
rootFolderData.refresh(true, true, projectDisposalMonitor);
|
rootFolderData.refresh(true, true, projectDisposalMonitor);
|
||||||
scheduleUserDataReconcilation();
|
scheduleUserDataReconcilation();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// ignore
|
Msg.trace(this, "Exception synchronizing filesystem", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -929,9 +886,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
return buf.length() == 0 ? "unknown" : buf.toString();
|
return buf.length() == 0 ? "unknown" : buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the project directory.
|
|
||||||
*/
|
|
||||||
public File getProjectDir() {
|
public File getProjectDir() {
|
||||||
return projectDir;
|
return projectDir;
|
||||||
}
|
}
|
||||||
@@ -941,9 +895,6 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes this project file manager.
|
|
||||||
*/
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -978,12 +929,11 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the open domain object (opened for update) associated with a file.
|
* Set the open domain object (opened for update) associated with a file.
|
||||||
* NOTE: Caller is responsible for setting domain file on domain object after
|
* NOTE: Caller is responsible for setting domain file on domain object after invoking this
|
||||||
* invoking this method.
|
* method. If a domain object saveAs was done, the previous file association
|
||||||
* If a domain object saveAs was done, the previous file association
|
|
||||||
* will be removed.
|
* will be removed.
|
||||||
* @param pathname
|
* @param pathname the path name
|
||||||
* @param doa
|
* @param doa the domain object
|
||||||
*/
|
*/
|
||||||
synchronized void setDomainObject(String pathname, DomainObjectAdapter doa) {
|
synchronized void setDomainObject(String pathname, DomainObjectAdapter doa) {
|
||||||
if (openDomainObjects.containsKey(pathname)) {
|
if (openDomainObjects.containsKey(pathname)) {
|
||||||
@@ -998,7 +948,8 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the open domain object (opened for update) for the specified path.
|
* Returns the open domain object (opened for update) for the specified path.
|
||||||
* @param pathname
|
* @param pathname the path name
|
||||||
|
* @return the domain object
|
||||||
*/
|
*/
|
||||||
synchronized DomainObjectAdapter getOpenedDomainObject(String pathname) {
|
synchronized DomainObjectAdapter getOpenedDomainObject(String pathname) {
|
||||||
return openDomainObjects.get(pathname);
|
return openDomainObjects.get(pathname);
|
||||||
@@ -1006,7 +957,7 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the previously open domain object which has been closed.
|
* Clears the previously open domain object which has been closed.
|
||||||
* @param pathname
|
* @param pathname the path name
|
||||||
* @return true if previously open domain file was cleared, else false
|
* @return true if previously open domain file was cleared, else false
|
||||||
*/
|
*/
|
||||||
synchronized boolean clearDomainObject(String pathname) {
|
synchronized boolean clearDomainObject(String pathname) {
|
||||||
@@ -1028,7 +979,7 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove specified fileID from index.
|
* Remove specified fileID from index.
|
||||||
* @param fileID
|
* @param fileID the file ID
|
||||||
*/
|
*/
|
||||||
public void removeFromIndex(String fileID) {
|
public void removeFromIndex(String fileID) {
|
||||||
fileIndex.removeFileEntry(fileID);
|
fileIndex.removeFileEntry(fileID);
|
||||||
@@ -1041,5 +992,4 @@ public class ProjectFileManager implements ProjectData {
|
|||||||
public TaskMonitor getProjectDisposalMonitor() {
|
public TaskMonitor getProjectDisposalMonitor() {
|
||||||
return projectDisposalMonitor;
|
return projectDisposalMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -22,8 +22,10 @@ import docking.widgets.OptionDialog;
|
|||||||
import ghidra.framework.client.*;
|
import ghidra.framework.client.*;
|
||||||
import ghidra.framework.main.datatable.DomainFileContext;
|
import ghidra.framework.main.datatable.DomainFileContext;
|
||||||
import ghidra.framework.main.datatable.DomainFileProviderContextAction;
|
import ghidra.framework.main.datatable.DomainFileProviderContextAction;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.DomainFile;
|
||||||
|
import ghidra.framework.model.Project;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.framework.store.FileSystemSynchronizer;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,6 +82,14 @@ public abstract class VersionControlAction extends DomainFileProviderContextActi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the file system is locked by another thread for a long running operation
|
||||||
|
* @return true if locked
|
||||||
|
*/
|
||||||
|
protected boolean isFileSystemBusy() {
|
||||||
|
return FileSystemSynchronizer.isSynchronizing();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: do not call this from a non-Swing thread.
|
* NOTE: do not call this from a non-Swing thread.
|
||||||
* @return true if the repository is null or is connected.
|
* @return true if the repository is null or is connected.
|
||||||
|
|||||||
+4
-8
@@ -57,11 +57,12 @@ public class VersionControlAddAction extends VersionControlAction {
|
|||||||
addToVersionControl(context.getSelectedFiles());
|
addToVersionControl(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one of the provided domain files can be added to the repository.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.canAddToRepository()) {
|
if (domainFile.canAddToRepository()) {
|
||||||
@@ -71,11 +72,6 @@ public class VersionControlAddAction extends VersionControlAction {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds all the non-version controlled domain files to the repository from the
|
|
||||||
* list of files from the DomainFileProvider.
|
|
||||||
* @param domainFiles
|
|
||||||
*/
|
|
||||||
private void addToVersionControl(List<DomainFile> domainFiles) {
|
private void addToVersionControl(List<DomainFile> domainFiles) {
|
||||||
|
|
||||||
if (!checkRepositoryConnected()) {
|
if (!checkRepositoryConnected()) {
|
||||||
|
|||||||
+7
-7
@@ -61,12 +61,12 @@ public class VersionControlCheckInAction extends VersionControlAction {
|
|||||||
doCheckIn(context.getSelectedFiles());
|
doCheckIn(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one of the provided domain files can have its changes
|
|
||||||
* checked into the repository.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.isCheckedOut() && domainFile.modifiedSinceCheckout()) {
|
if (domainFile.isCheckedOut() && domainFile.modifiedSinceCheckout()) {
|
||||||
@@ -83,7 +83,7 @@ public class VersionControlCheckInAction extends VersionControlAction {
|
|||||||
if (!checkRepositoryConnected()) {
|
if (!checkRepositoryConnected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<DomainFile> checkedOut = new ArrayList<DomainFile>();
|
List<DomainFile> checkedOut = new ArrayList<>();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.isCheckedOut() && domainFile.modifiedSinceCheckout()) {
|
if (domainFile.isCheckedOut() && domainFile.modifiedSinceCheckout()) {
|
||||||
checkedOut.add(domainFile);
|
checkedOut.add(domainFile);
|
||||||
@@ -112,8 +112,8 @@ public class VersionControlCheckInAction extends VersionControlAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<DomainFile> changedList = new ArrayList<DomainFile>();
|
ArrayList<DomainFile> changedList = new ArrayList<>();
|
||||||
ArrayList<DomainFile> list = new ArrayList<DomainFile>();
|
ArrayList<DomainFile> list = new ArrayList<>();
|
||||||
for (int i = 0; i < fileList.size(); i++) {
|
for (int i = 0; i < fileList.size(); i++) {
|
||||||
DomainFile df = fileList.get(i);
|
DomainFile df = fileList.get(i);
|
||||||
if (df != null && df.canCheckin()) {
|
if (df != null && df.canCheckin()) {
|
||||||
|
|||||||
+4
-4
@@ -64,12 +64,12 @@ public class VersionControlCheckOutAction extends VersionControlAction {
|
|||||||
checkOut(context.getSelectedFiles());
|
checkOut(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one of the provided domain files can can be
|
|
||||||
* checked out of the repository.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> providedList = context.getSelectedFiles();
|
List<DomainFile> providedList = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : providedList) {
|
for (DomainFile domainFile : providedList) {
|
||||||
if (domainFile.canCheckout()) {
|
if (domainFile.canCheckout()) {
|
||||||
|
|||||||
+4
-3
@@ -48,15 +48,16 @@ public class VersionControlShowHistoryAction extends VersionControlAction {
|
|||||||
showHistory(context.getSelectedFiles());
|
showHistory(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a single version controlled domain file is being provided.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
if (domainFiles.size() != 1) {
|
if (domainFiles.size() != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
DomainFile domainFile = domainFiles.get(0);
|
DomainFile domainFile = domainFiles.get(0);
|
||||||
return domainFile.isVersioned();
|
return domainFile.isVersioned();
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-11
@@ -61,11 +61,12 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction {
|
|||||||
undoCheckOut(context.getSelectedFiles());
|
undoCheckOut(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one of the provided domain files is checked out from the repository.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.isCheckedOut()) {
|
if (domainFile.isCheckedOut()) {
|
||||||
@@ -83,8 +84,8 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction {
|
|||||||
if (!checkRepositoryConnected()) {
|
if (!checkRepositoryConnected()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<DomainFile> unmodifiedCheckOutsList = new ArrayList<DomainFile>();
|
List<DomainFile> unmodifiedCheckOutsList = new ArrayList<>();
|
||||||
List<DomainFile> modifiedCheckOutsList = new ArrayList<DomainFile>();
|
List<DomainFile> modifiedCheckOutsList = new ArrayList<>();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.isCheckedOut()) {
|
if (domainFile.isCheckedOut()) {
|
||||||
if (domainFile.modifiedSinceCheckout()) {
|
if (domainFile.modifiedSinceCheckout()) {
|
||||||
@@ -145,10 +146,9 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction {
|
|||||||
/**
|
/**
|
||||||
* Creates a task for undoing checkouts of domain files.
|
* Creates a task for undoing checkouts of domain files.
|
||||||
* @param unmodifiedCheckOutsList the list of unmodified checked out files
|
* @param unmodifiedCheckOutsList the list of unmodified checked out files
|
||||||
* @param modifiedCheckOutsList the list of checked out files that have been modified
|
* @param modifiedCheckedOutFiles the list of checked out files that have been modified
|
||||||
* @param saveCopy true indicates that copies of the modified files should be made
|
* @param saveCopy true indicates that copies of the modified files should be made
|
||||||
* before undo of the checkout.
|
* before undo of the checkout
|
||||||
* @param listener the task listener to call when the task completes or is cancelled.
|
|
||||||
*/
|
*/
|
||||||
UndoCheckOutTask(List<DomainFile> unmodifiedCheckOutsList,
|
UndoCheckOutTask(List<DomainFile> unmodifiedCheckOutsList,
|
||||||
DomainFile[] modifiedCheckedOutFiles, boolean saveCopy) {
|
DomainFile[] modifiedCheckedOutFiles, boolean saveCopy) {
|
||||||
@@ -158,9 +158,6 @@ public class VersionControlUndoCheckOutAction extends VersionControlAction {
|
|||||||
this.saveCopy = saveCopy;
|
this.saveCopy = saveCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see ghidra.util.task.Task#run(ghidra.util.task.TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TaskMonitor monitor) {
|
public void run(TaskMonitor monitor) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+6
-9
@@ -55,11 +55,12 @@ public class VersionControlUndoHijackAction extends VersionControlAction {
|
|||||||
undoHijackedFiles(context.getSelectedFiles());
|
undoHijackedFiles(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one of the provided domain files is hijacked.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile.isHijacked()) {
|
if (domainFile.isHijacked()) {
|
||||||
@@ -77,7 +78,7 @@ public class VersionControlUndoHijackAction extends VersionControlAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DomainFile> hijackList = new ArrayList<DomainFile>();
|
List<DomainFile> hijackList = new ArrayList<>();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile != null && domainFile.isHijacked()) {
|
if (domainFile != null && domainFile.isHijacked()) {
|
||||||
hijackList.add(domainFile);
|
hijackList.add(domainFile);
|
||||||
@@ -143,8 +144,7 @@ public class VersionControlUndoHijackAction extends VersionControlAction {
|
|||||||
* Creates a task for undoing hijacks of domain files.
|
* Creates a task for undoing hijacks of domain files.
|
||||||
* @param hijackFiles the list of hijacked files
|
* @param hijackFiles the list of hijacked files
|
||||||
* @param saveCopy true indicates that copies of the modified files should be made
|
* @param saveCopy true indicates that copies of the modified files should be made
|
||||||
* before undo of the checkout.
|
* before undo of the checkout
|
||||||
* @param listener the task listener to call when the task completes or is cancelled.
|
|
||||||
*/
|
*/
|
||||||
UndoHijackTask(DomainFile[] hijackFiles, boolean saveCopy) {
|
UndoHijackTask(DomainFile[] hijackFiles, boolean saveCopy) {
|
||||||
super("Undo Hijack", true, true, true);
|
super("Undo Hijack", true, true, true);
|
||||||
@@ -152,9 +152,6 @@ public class VersionControlUndoHijackAction extends VersionControlAction {
|
|||||||
this.saveCopy = saveCopy;
|
this.saveCopy = saveCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see ghidra.util.task.Task#run(ghidra.util.task.TaskMonitor)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void run(TaskMonitor monitor) {
|
public void run(TaskMonitor monitor) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+5
-4
@@ -59,11 +59,12 @@ public class VersionControlUpdateAction extends VersionControlAction {
|
|||||||
update(context.getSelectedFiles());
|
update(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if at least one checked out file has a newer version in the repository.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
List<DomainFile> providedList = context.getSelectedFiles();
|
List<DomainFile> providedList = context.getSelectedFiles();
|
||||||
for (DomainFile domainFile : providedList) {
|
for (DomainFile domainFile : providedList) {
|
||||||
if (domainFile.isVersioned() &&
|
if (domainFile.isVersioned() &&
|
||||||
@@ -83,7 +84,7 @@ public class VersionControlUpdateAction extends VersionControlAction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DomainFile> updateList = new ArrayList<DomainFile>();
|
List<DomainFile> updateList = new ArrayList<>();
|
||||||
for (DomainFile domainFile : domainFiles) {
|
for (DomainFile domainFile : domainFiles) {
|
||||||
if (domainFile != null && domainFile.canMerge()) {
|
if (domainFile != null && domainFile.canMerge()) {
|
||||||
if (!canCloseDomainFile(domainFile)) {
|
if (!canCloseDomainFile(domainFile)) {
|
||||||
|
|||||||
+4
-3
@@ -50,15 +50,16 @@ public class VersionControlViewCheckOutAction extends VersionControlAction {
|
|||||||
viewCheckouts(context.getSelectedFiles());
|
viewCheckouts(context.getSelectedFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a single version controlled domain file is being provided.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEnabledForContext(DomainFileContext context) {
|
public boolean isEnabledForContext(DomainFileContext context) {
|
||||||
List<DomainFile> domainFiles = context.getSelectedFiles();
|
List<DomainFile> domainFiles = context.getSelectedFiles();
|
||||||
if (domainFiles.size() != 1) {
|
if (domainFiles.size() != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isFileSystemBusy()) {
|
||||||
|
return false; // don't block; we should get called again later
|
||||||
|
}
|
||||||
|
|
||||||
DomainFile domainFile = domainFiles.get(0);
|
DomainFile domainFile = domainFiles.get(0);
|
||||||
return domainFile.isVersioned();
|
return domainFile.isVersioned();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
package ghidra.framework.model;
|
package ghidra.framework.model;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
@@ -28,10 +28,10 @@ import ghidra.util.exception.*;
|
|||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>DomainFile</code> provides a storage interface for project
|
* <code>DomainFile</code> provides a storage interface for project files. A
|
||||||
* files. A <code>DomainFile</code> is an immutable reference to
|
* <code>DomainFile</code> is an immutable reference to file contained within a project. The state
|
||||||
* a file contained within a project. The state of a <code>DomainFile</code>
|
* of a <code>DomainFile</code> object does not track name/parent changes made to the referenced
|
||||||
* object does not track name/parent changes made to the referenced project file.
|
* project file.
|
||||||
*/
|
*/
|
||||||
public interface DomainFile extends Comparable<DomainFile> {
|
public interface DomainFile extends Comparable<DomainFile> {
|
||||||
|
|
||||||
@@ -48,8 +48,8 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
public final static String READ_ONLY_PROPERTY = "READ_ONLY";
|
public final static String READ_ONLY_PROPERTY = "READ_ONLY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of the StoredObj that is associated with
|
* Get the name of the StoredObj that is associated with the data.
|
||||||
* the data.
|
* @return the name
|
||||||
*/
|
*/
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a unique file-ID
|
* Returns a unique file-ID
|
||||||
* @return
|
* @return the ID
|
||||||
*/
|
*/
|
||||||
public String getFileID();
|
public String getFileID();
|
||||||
|
|
||||||
@@ -79,27 +79,31 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path name to the domain object.
|
* Returns the path name to the domain object.
|
||||||
|
* @return the path name
|
||||||
*/
|
*/
|
||||||
public String getPathname();
|
public String getPathname();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local storage location for the project that this DomainFile belongs to.
|
* Returns the local storage location for the project that this DomainFile belongs to.
|
||||||
|
* @return the location
|
||||||
*/
|
*/
|
||||||
public ProjectLocator getProjectLocator();
|
public ProjectLocator getProjectLocator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns content-type string
|
* Returns content-type string
|
||||||
|
* @return the content type
|
||||||
*/
|
*/
|
||||||
public String getContentType();
|
public String getContentType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the underlying Class for the domain object in this
|
* Returns the underlying Class for the domain object in this domain file.
|
||||||
* domain file.
|
* @return the class
|
||||||
*/
|
*/
|
||||||
public Class<? extends DomainObject> getDomainObjectClass();
|
public Class<? extends DomainObject> getDomainObjectClass();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the parent domain folder for this domain file.
|
* Get the parent domain folder for this domain file.
|
||||||
|
* @return the parent
|
||||||
*/
|
*/
|
||||||
public DomainFolder getParent();
|
public DomainFolder getParent();
|
||||||
|
|
||||||
@@ -210,21 +214,23 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
public boolean canRecover();
|
public boolean canRecover();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the file has an updateable domain object with unsaved changes, generate a
|
* If the file has an updatable domain object with unsaved changes, generate a recovery
|
||||||
* recovery snapshot.
|
* snapshot.
|
||||||
* @return true if snapshot successful or not needed, false if file is busy
|
* @return true if snapshot successful or not needed, false if file is busy which prevents
|
||||||
* which prevents snapshot, or snapshot was cancelled.
|
* snapshot, or snapshot was cancelled.
|
||||||
* @throws IOException
|
* @throws IOException if there is an exception saving the snapshot
|
||||||
*/
|
*/
|
||||||
public boolean takeRecoverySnapshot() throws IOException;
|
public boolean takeRecoverySnapshot() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file is in a writable project.
|
* Returns true if this file is in a writable project.
|
||||||
|
* @return true if writable
|
||||||
*/
|
*/
|
||||||
public boolean isInWritableProject();
|
public boolean isInWritableProject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a long value representing the time when the data was last modified.
|
* Get a long value representing the time when the data was last modified.
|
||||||
|
* @return the time
|
||||||
*/
|
*/
|
||||||
public long getLastModifiedTime();
|
public long getLastModifiedTime();
|
||||||
|
|
||||||
@@ -238,39 +244,44 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this is a checked-out file.
|
* Returns true if this is a checked-out file.
|
||||||
|
* @return true if checked-out
|
||||||
*/
|
*/
|
||||||
public boolean isCheckedOut();
|
public boolean isCheckedOut();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this a checked-out file with exclusive access.
|
* Returns true if this a checked-out file with exclusive access.
|
||||||
|
* @return true if checked-out exclusively
|
||||||
*/
|
*/
|
||||||
public boolean isCheckedOutExclusive();
|
public boolean isCheckedOutExclusive();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this is a checked-out file which has been modified
|
* Returns true if this is a checked-out file which has been modified since it was checked-out.
|
||||||
* since it was checked-out.
|
* @return true if modified since check-out
|
||||||
*/
|
*/
|
||||||
public boolean modifiedSinceCheckout();
|
public boolean modifiedSinceCheckout();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file may be checked-out from the associated repository.
|
* Returns true if this file may be checked-out from the associated repository.
|
||||||
* User's with read-only repository access will not have checkout ability.
|
* User's with read-only repository access will not have checkout ability.
|
||||||
|
* @return true if can checkout
|
||||||
*/
|
*/
|
||||||
public boolean canCheckout();
|
public boolean canCheckout();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file may be checked-in to the associated repository.
|
* Returns true if this file may be checked-in to the associated repository.
|
||||||
|
* @return true if can check-in
|
||||||
*/
|
*/
|
||||||
public boolean canCheckin();
|
public boolean canCheckin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file can be merged with the current versioned file.
|
* Returns true if this file can be merged with the current versioned file.
|
||||||
|
* @return true if can merge
|
||||||
*/
|
*/
|
||||||
public boolean canMerge();
|
public boolean canMerge();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this private file may be added to the
|
* Returns true if this private file may be added to the associated repository.
|
||||||
* associated repository.
|
* @return true if can add to the repository
|
||||||
*/
|
*/
|
||||||
public boolean canAddToRepository();
|
public boolean canAddToRepository();
|
||||||
|
|
||||||
@@ -284,47 +295,53 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
public void setReadOnly(boolean state) throws IOException;
|
public void setReadOnly(boolean state) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the object is read-only. From a
|
* Returns whether the object is read-only. From a framework point of view a read-only object
|
||||||
* framework point of view a read-only object can never be
|
* can never be changed.
|
||||||
* changed.
|
* @return true if read-only
|
||||||
*/
|
*/
|
||||||
public boolean isReadOnly();
|
public boolean isReadOnly();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the versioned filesystem can be used to store
|
* Returns true if the versioned filesystem can be used to store this files content type.
|
||||||
* this files content type.
|
* @return true if supports version control
|
||||||
*/
|
*/
|
||||||
public boolean isVersionControlSupported();
|
public boolean isVersionControlSupported();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if this is a versioned database, else false
|
* Return true if this is a versioned database, else false
|
||||||
|
* @return true if versioned
|
||||||
*/
|
*/
|
||||||
public boolean isVersioned();
|
public boolean isVersioned();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the file is versioned but a private copy also exists.
|
* Returns true if the file is versioned but a private copy also exists.
|
||||||
|
* @return true if hijacked
|
||||||
*/
|
*/
|
||||||
public boolean isHijacked();
|
public boolean isHijacked();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the latest version
|
* Return the latest version
|
||||||
|
* @return the version
|
||||||
*/
|
*/
|
||||||
public int getLatestVersion();
|
public int getLatestVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file represents the latest version of the
|
* Returns true if this file represents the latest version of the associated domain object.
|
||||||
* associated domain object.
|
* @return true if the latest version
|
||||||
*/
|
*/
|
||||||
public boolean isLatestVersion();
|
public boolean isLatestVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return either the latest version if the file is not checked-out or the version that
|
* Return either the latest version if the file is not checked-out or the version that
|
||||||
* was checked-out or a specific version that was requested.
|
* was checked-out or a specific version that was requested.
|
||||||
|
* @return the version
|
||||||
*/
|
*/
|
||||||
public int getVersion();
|
public int getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns list of all available versions.
|
* Returns list of all available versions.
|
||||||
|
* @return the versions
|
||||||
|
* @throws IOException if there is an exception getting the history
|
||||||
*/
|
*/
|
||||||
public Version[] getVersionHistory() throws IOException;
|
public Version[] getVersionHistory() throws IOException;
|
||||||
|
|
||||||
@@ -334,8 +351,8 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
* @param keepCheckedOut if true, the file will be initially checked-out
|
* @param keepCheckedOut if true, the file will be initially checked-out
|
||||||
* @param monitor progress monitor
|
* @param monitor progress monitor
|
||||||
* @throws FileInUseException if this file is in-use.
|
* @throws FileInUseException if this file is in-use.
|
||||||
* @throws IOException thrown if an IO or access error occurs. Also
|
* @throws IOException thrown if an IO or access error occurs. Also thrown if file is not
|
||||||
* thrown if file is not private.
|
* private.
|
||||||
* @throws CancelledException if the monitor cancelled the operation
|
* @throws CancelledException if the monitor cancelled the operation
|
||||||
*/
|
*/
|
||||||
public void addToVersionControl(String comment, boolean keepCheckedOut, TaskMonitor monitor)
|
public void addToVersionControl(String comment, boolean keepCheckedOut, TaskMonitor monitor)
|
||||||
@@ -393,7 +410,7 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Forcefully terminate a checkout for the associated versioned file.
|
* Forcefully terminate a checkout for the associated versioned file.
|
||||||
* The user must be the owner of the checkout or have admin privilege
|
* The user must be the owner of the checkout or have administrator privilege
|
||||||
* on the versioned filesystem (i.e., repository).
|
* on the versioned filesystem (i.e., repository).
|
||||||
* @param checkoutId checkout ID
|
* @param checkoutId checkout ID
|
||||||
* @throws IOException if an IO or access error occurs
|
* @throws IOException if an IO or access error occurs
|
||||||
@@ -456,7 +473,7 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
* @throws IOException thrown if an IO or access error occurs.
|
* @throws IOException thrown if an IO or access error occurs.
|
||||||
* @throws CancelledException if task monitor cancelled operation.
|
* @throws CancelledException if task monitor cancelled operation.
|
||||||
*/
|
*/
|
||||||
DomainFile copyTo(DomainFolder newParent, TaskMonitor monitor)
|
public DomainFile copyTo(DomainFolder newParent, TaskMonitor monitor)
|
||||||
throws IOException, CancelledException;
|
throws IOException, CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -464,47 +481,53 @@ public interface DomainFile extends Comparable<DomainFile> {
|
|||||||
* @param version version to copy
|
* @param version version to copy
|
||||||
* @param destFolder destination parent folder
|
* @param destFolder destination parent folder
|
||||||
* @param monitor task monitor
|
* @param monitor task monitor
|
||||||
|
* @return the copied file
|
||||||
* @throws IOException thrown if an IO or access error occurs.
|
* @throws IOException thrown if an IO or access error occurs.
|
||||||
* @throws CancelledException if task monitor cancelled operation.
|
* @throws CancelledException if task monitor cancelled operation.
|
||||||
*/
|
*/
|
||||||
DomainFile copyVersionTo(int version, DomainFolder destFolder, TaskMonitor monitor)
|
public DomainFile copyVersionTo(int version, DomainFolder destFolder, TaskMonitor monitor)
|
||||||
throws IOException, CancelledException;
|
throws IOException, CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of consumers (Objects) for this domain file.
|
* Get the list of consumers (Objects) for this domain file.
|
||||||
* @return empty array list if there are no consumers
|
* @return empty array list if there are no consumers
|
||||||
*/
|
*/
|
||||||
ArrayList<?> getConsumers();
|
public List<?> getConsumers();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether the domain object in this domain file has changed.
|
* Return whether the domain object in this domain file has changed.
|
||||||
|
* @return true if changed
|
||||||
*/
|
*/
|
||||||
boolean isChanged();
|
public boolean isChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is an open domainObject for this file.
|
* Returns true if there is an open domainObject for this file.
|
||||||
|
* @return true if open
|
||||||
*/
|
*/
|
||||||
boolean isOpen();
|
public boolean isOpen();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the domain object in this domain file exists and has an open transaction.
|
* Returns true if the domain object in this domain file exists and has an open transaction.
|
||||||
|
* @return true if busy
|
||||||
*/
|
*/
|
||||||
boolean isBusy();
|
public boolean isBusy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pack domain file into specified file.
|
* Pack domain file into specified file.
|
||||||
* Specified file will be overwritten if it already exists.
|
* Specified file will be overwritten if it already exists.
|
||||||
* @param file destination file
|
* @param file destination file
|
||||||
* @param monitor
|
* @param monitor the task monitor
|
||||||
* @throws IOException
|
* @throws IOException if there is an exception packing the file
|
||||||
* @throws CancelledException if monitor cancels operation
|
* @throws CancelledException if monitor cancels operation
|
||||||
*/
|
*/
|
||||||
public void packFile(File file, TaskMonitor monitor) throws IOException, CancelledException;
|
public void packFile(File file, TaskMonitor monitor) throws IOException, CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an ordered map containting the metadata that has been associated with the corresponding domain object.
|
* Returns an ordered map containing the metadata that has been associated with the
|
||||||
* The map contains key,value pairs and are ordered by their insertion order.
|
* corresponding domain object. The map contains key,value pairs and are ordered by their
|
||||||
* @return a map containting the metadata that has been associated with the corresponding domain object.
|
* insertion order.
|
||||||
|
* @return a map containing the metadata that has been associated with the corresponding domain
|
||||||
|
* object.
|
||||||
*/
|
*/
|
||||||
public Map<String, String> getMetadata();
|
public Map<String, String> getMetadata();
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ import ghidra.util.exception.*;
|
|||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>DomainFolder</code> provides a storage interface for project
|
* <code>DomainFolder</code> provides a storage interface for project folders. A
|
||||||
* folders. A <code>DomainFolder</code> is an immutable reference to
|
* <code>DomainFolder</code> is an immutable reference to a folder contained within a project. The
|
||||||
* a folder contained within a project. The state of a <code>DomainFolder</code>
|
* state of a <code>DomainFolder</code> object does not track name/parent changes made to the
|
||||||
* object does not track name/parent changes made to the referenced project folder.
|
* referenced project folder.
|
||||||
*/
|
*/
|
||||||
public interface DomainFolder extends Comparable<DomainFolder> {
|
public interface DomainFolder extends Comparable<DomainFolder> {
|
||||||
/**
|
/**
|
||||||
@@ -42,41 +42,51 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this folder's name.
|
* Return this folder's name.
|
||||||
|
* @return the name
|
||||||
*/
|
*/
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name on this domain folder.
|
* Set the name on this domain folder.
|
||||||
* @param newName domain folder name
|
* @param newName domain folder name
|
||||||
* @return renamed domain file (the original DomainFolder object becomes invalid since it is immutable)
|
* @return renamed domain file (the original DomainFolder object becomes invalid since it is
|
||||||
|
* immutable)
|
||||||
* @throws InvalidNameException if newName contains illegal characters
|
* @throws InvalidNameException if newName contains illegal characters
|
||||||
* @throws DuplicateFileException if a folder named newName
|
* @throws DuplicateFileException if a folder named newName
|
||||||
* already exists in this files domain folder.
|
* already exists in this files domain folder.
|
||||||
* @throws FileInUseException if any file within this folder or its
|
* @throws FileInUseException if any file within this folder or its descendants is
|
||||||
* decendents is in-use / checked-out.
|
* in-use / checked-out.
|
||||||
* @throws IOException thrown if an IO or access error occurs.
|
* @throws IOException thrown if an IO or access error occurs.
|
||||||
*/
|
*/
|
||||||
public DomainFolder setName(String newName) throws InvalidNameException, IOException;
|
public DomainFolder setName(String newName) throws InvalidNameException, IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the local storage location for the project that this DomainFolder belongs to.
|
* Returns the local storage location for the project that this DomainFolder belongs to.
|
||||||
|
* @return the locator
|
||||||
*/
|
*/
|
||||||
public ProjectLocator getProjectLocator();
|
public ProjectLocator getProjectLocator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the project data
|
||||||
|
* @return the project data
|
||||||
|
*/
|
||||||
public ProjectData getProjectData();
|
public ProjectData getProjectData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path name to the domain object.
|
* Returns the path name to the domain object.
|
||||||
|
* @return the path name
|
||||||
*/
|
*/
|
||||||
public String getPathname();
|
public String getPathname();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this file is in a writable project.
|
* Returns true if this file is in a writable project.
|
||||||
|
* @return true if writable
|
||||||
*/
|
*/
|
||||||
public boolean isInWritableProject();
|
public boolean isInWritableProject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return parent folder or null if this DomainFolder is the root folder.
|
* Return parent folder or null if this DomainFolder is the root folder.
|
||||||
|
* @return the parent
|
||||||
*/
|
*/
|
||||||
public DomainFolder getParent();
|
public DomainFolder getParent();
|
||||||
|
|
||||||
@@ -149,10 +159,11 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
|||||||
/**
|
/**
|
||||||
* Create a subfolder of this folder.
|
* Create a subfolder of this folder.
|
||||||
* @param folderName sub-folder name
|
* @param folderName sub-folder name
|
||||||
|
* @return the folder
|
||||||
* @throws DuplicateFileException if a folder by
|
* @throws DuplicateFileException if a folder by
|
||||||
* this name already exists
|
* this name already exists
|
||||||
* @throws InvalidNameException if name is an empty string
|
* @throws InvalidNameException if name is an empty string of if it contains characters other
|
||||||
* of if it contains characters other than alphanumerics.
|
* than alphanumerics.
|
||||||
* @throws IOException if IO or access error occurs
|
* @throws IOException if IO or access error occurs
|
||||||
*/
|
*/
|
||||||
public DomainFolder createFolder(String folderName) throws InvalidNameException, IOException;
|
public DomainFolder createFolder(String folderName) throws InvalidNameException, IOException;
|
||||||
@@ -169,10 +180,11 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
|||||||
* this affects both private and repository folders and files. If not
|
* this affects both private and repository folders and files. If not
|
||||||
* connected, only private folders and files are affected.
|
* connected, only private folders and files are affected.
|
||||||
* @param newParent new parent folder within the same project
|
* @param newParent new parent folder within the same project
|
||||||
* @return the newly relocated folder (the original DomainFolder object becomes invalid since it is immutable)
|
* @return the newly relocated folder (the original DomainFolder object becomes invalid since
|
||||||
|
* it is immutable)
|
||||||
* @throws DuplicateFileException if a folder with the same name
|
* @throws DuplicateFileException if a folder with the same name
|
||||||
* already exists in newParent folder.
|
* already exists in newParent folder.
|
||||||
* @throws FileInUseException if this folder or one of its decendents
|
* @throws FileInUseException if this folder or one of its descendants
|
||||||
* contains a file which is in-use / checked-out.
|
* contains a file which is in-use / checked-out.
|
||||||
* @throws IOException thrown if an IO or access error occurs.
|
* @throws IOException thrown if an IO or access error occurs.
|
||||||
*/
|
*/
|
||||||
@@ -182,6 +194,7 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
|||||||
* Copy this folder into the newParent folder.
|
* Copy this folder into the newParent folder.
|
||||||
* @param newParent new parent folder
|
* @param newParent new parent folder
|
||||||
* @param monitor the task monitor
|
* @param monitor the task monitor
|
||||||
|
* @return the copied folder
|
||||||
* @throws DuplicateFileException if a folder or file by
|
* @throws DuplicateFileException if a folder or file by
|
||||||
* this name already exists in the newParent folder
|
* this name already exists in the newParent folder
|
||||||
* @throws IOException thrown if an IO or access error occurs.
|
* @throws IOException thrown if an IO or access error occurs.
|
||||||
@@ -191,9 +204,7 @@ public interface DomainFolder extends Comparable<DomainFolder> {
|
|||||||
CancelledException;
|
CancelledException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the framework to react to a request to make this folder the
|
* Allows the framework to react to a request to make this folder the "active" one.
|
||||||
* "active" one.
|
|
||||||
*/
|
*/
|
||||||
public void setActive();
|
public void setActive();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -115,5 +115,4 @@ public interface DomainFolderChangeListener {
|
|||||||
* @param object domain object which was open for update
|
* @param object domain object which was open for update
|
||||||
*/
|
*/
|
||||||
public void domainFileObjectClosed(DomainFile file, DomainObject object);
|
public void domainFileObjectClosed(DomainFile file, DomainObject object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user