mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch 'origin/GP-5830_ghidra1_ProjectDataTableUpdates--SQUASHED'
This commit is contained in:
commit
1a1cdefc14
8 changed files with 362 additions and 27 deletions
|
@ -71,6 +71,7 @@ class ProjectDataPanel extends JSplitPane implements ProjectViewListener {
|
|||
readOnlyViews = new HashMap<>(TYPICAL_NUM_VIEWS);
|
||||
|
||||
projectTab = new JTabbedPane(SwingConstants.BOTTOM);
|
||||
projectTab.setName("PROJECT_TABBED_PANE");
|
||||
projectTab.setBorder(BorderFactory.createTitledBorder(BORDER_PREFIX));
|
||||
projectTab.addChangeListener(e -> frontEndPlugin.getTool().contextChanged(null));
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ import ghidra.framework.model.DomainFile;
|
|||
public class DomainFileInfo {
|
||||
|
||||
private DomainFile domainFile;
|
||||
private ProjectDataTableModel model;
|
||||
private int modCount;
|
||||
private String name;
|
||||
private String path;
|
||||
private Map<String, String> metadata;
|
||||
|
@ -36,9 +38,9 @@ public class DomainFileInfo {
|
|||
private Boolean isBrokenLink;
|
||||
private String toolTipText;
|
||||
|
||||
public DomainFileInfo(DomainFile domainFile) {
|
||||
DomainFileInfo(DomainFile domainFile, ProjectDataTableModel model) {
|
||||
this.domainFile = domainFile;
|
||||
this.path = domainFile.getParent().getPathname();
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
private String computeName() {
|
||||
|
@ -74,6 +76,7 @@ public class DomainFileInfo {
|
|||
}
|
||||
|
||||
public synchronized String getDisplayName() {
|
||||
checkModelModCount();
|
||||
if (name == null) {
|
||||
name = computeName();
|
||||
}
|
||||
|
@ -81,6 +84,7 @@ public class DomainFileInfo {
|
|||
}
|
||||
|
||||
public synchronized String getPath() {
|
||||
checkModelModCount();
|
||||
if (path == null) {
|
||||
path = domainFile.getParent().getPathname();
|
||||
}
|
||||
|
@ -88,6 +92,7 @@ public class DomainFileInfo {
|
|||
}
|
||||
|
||||
public synchronized DomainFileType getDomainFileType() {
|
||||
checkModelModCount();
|
||||
if (domainFileType == null) {
|
||||
checkStatus();
|
||||
String contentType = domainFile.getContentType();
|
||||
|
@ -102,7 +107,7 @@ public class DomainFileInfo {
|
|||
}
|
||||
|
||||
public synchronized Date getModificationDate() {
|
||||
|
||||
checkModelModCount();
|
||||
if (modificationDate == null) {
|
||||
modificationDate = getLastModifiedTime();
|
||||
}
|
||||
|
@ -118,6 +123,7 @@ public class DomainFileInfo {
|
|||
}
|
||||
|
||||
private synchronized Map<String, String> getMetadata() {
|
||||
checkModelModCount();
|
||||
if (metadata == null) {
|
||||
metadata = domainFile.getMetadata();
|
||||
if (metadata == null) {
|
||||
|
@ -154,7 +160,16 @@ public class DomainFileInfo {
|
|||
return domainFile.getName();
|
||||
}
|
||||
|
||||
private void checkStatus() {
|
||||
private void checkModelModCount() {
|
||||
int modelModCount = model.getModCount();
|
||||
if (modelModCount != modCount) {
|
||||
refresh();
|
||||
modCount = modelModCount;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void checkStatus() {
|
||||
checkModelModCount();
|
||||
if (isBrokenLink == null) {
|
||||
isBrokenLink = false;
|
||||
List<String> linkErrors = null;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -40,10 +39,6 @@ public class DomainFileType implements Comparable<DomainFileType>, DisplayString
|
|||
return result;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -34,6 +34,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, ProjectData> {
|
||||
|
||||
private ProjectData projectData;
|
||||
private volatile int modCount;
|
||||
private boolean editingOn;
|
||||
|
||||
private boolean loadWasCancelled;
|
||||
|
@ -50,6 +51,7 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
protected void doLoad(Accumulator<DomainFileInfo> accumulator, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
loadWasCancelled = false;
|
||||
++modCount;
|
||||
if (projectData != null) {
|
||||
loadWasCancelled = true;
|
||||
DomainFolder rootFolder = projectData.getRootFolder();
|
||||
|
@ -63,7 +65,7 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
DomainFile[] files = folder.getFiles();
|
||||
for (DomainFile domainFile : files) {
|
||||
monitor.checkCancelled();
|
||||
accumulator.add(new DomainFileInfo(domainFile));
|
||||
accumulator.add(new DomainFileInfo(domainFile, this));
|
||||
}
|
||||
DomainFolder[] folders = folder.getFolders();
|
||||
for (DomainFolder domainFolder : folders) {
|
||||
|
@ -113,13 +115,16 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
|
||||
@Override
|
||||
public void refresh() {
|
||||
List<DomainFileInfo> modelData = getModelData();
|
||||
for (DomainFileInfo domainFileInfo : modelData) {
|
||||
domainFileInfo.refresh();
|
||||
}
|
||||
// The modCount allows DomainFileInfo to determine if its cached data is stale relative
|
||||
// to this model
|
||||
++modCount;
|
||||
super.refresh();
|
||||
}
|
||||
|
||||
int getModCount() {
|
||||
return modCount;
|
||||
}
|
||||
|
||||
public void setProjectData(ProjectData projectData) {
|
||||
this.projectData = projectData;
|
||||
reload();
|
||||
|
@ -162,7 +167,7 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
//==================================================================================================
|
||||
|
||||
private class DomainFileTypeColumn
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, DomainFileType, ProjectData> {
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, DomainFileType, ProjectData> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
|
@ -182,7 +187,7 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
}
|
||||
|
||||
private class DomainFileNameColumn
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, String, ProjectData> {
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, String, ProjectData> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
|
@ -203,7 +208,7 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
}
|
||||
|
||||
private class ModificationDateColumn
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, Date, ProjectData> {
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, Date, ProjectData> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
|
@ -224,7 +229,7 @@ public class ProjectDataTableModel extends ThreadedTableModel<DomainFileInfo, Pr
|
|||
}
|
||||
|
||||
private class DomainFilePathColumn
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, String, ProjectData> {
|
||||
extends AbstractDynamicTableColumn<DomainFileInfo, String, ProjectData> {
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
|
|
|
@ -373,7 +373,8 @@ public class ProjectDataTablePanel extends JPanel {
|
|||
}
|
||||
checkCapacity();
|
||||
if (!capacityExceeded) {
|
||||
model.addObject(new DomainFileInfo(file));
|
||||
model.addObject(new DomainFileInfo(file, model));
|
||||
model.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,7 +383,7 @@ public class ProjectDataTablePanel extends JPanel {
|
|||
if (ignoreChanges()) {
|
||||
return;
|
||||
}
|
||||
model.refresh();
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -399,6 +400,7 @@ public class ProjectDataTablePanel extends JPanel {
|
|||
break;
|
||||
}
|
||||
}
|
||||
model.refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/* ###
|
||||
* 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.main.datatree;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.framework.data.FolderLinkContentHandler;
|
||||
import ghidra.framework.data.LinkHandler.LinkStatus;
|
||||
import ghidra.framework.main.datatable.DomainFileInfo;
|
||||
import ghidra.framework.main.datatable.DomainFileType;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.program.database.ProgramLinkContentHandler;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class ProjectLinkFileStatusTableTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private FrontEndTestEnv env;
|
||||
private FrontEndDataTableHelper tableHelper;
|
||||
|
||||
private DomainFolder rootFolder;
|
||||
private DomainFolder abcFolder;
|
||||
private DomainFolder xyzFolder;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
env = new FrontEndTestEnv();
|
||||
|
||||
/**
|
||||
/abc/ (folder)
|
||||
abc -> /xyz/abc (circular)
|
||||
bar (program file)
|
||||
/xyz/ (folder)
|
||||
abc -> /abc (folder link)
|
||||
abc -> (circular)
|
||||
bar (program within linked-folder should not appear in table)
|
||||
**/
|
||||
|
||||
rootFolder = env.getRootFolder();
|
||||
|
||||
abcFolder = rootFolder.createFolder("abc");
|
||||
xyzFolder = rootFolder.createFolder("xyz");
|
||||
DomainFile abcLinkFile = abcFolder.copyToAsLink(xyzFolder, false);
|
||||
abcLinkFile.copyToAsLink(abcFolder, false);
|
||||
|
||||
Program p = ToyProgramBuilder.buildSimpleProgram("bar", this);
|
||||
abcFolder.createFile("bar", p, TaskMonitor.DUMMY);
|
||||
p.release(this);
|
||||
|
||||
tableHelper = new FrontEndDataTableHelper(env.getFrontEndTool());
|
||||
tableHelper.showTablePanel();
|
||||
tableHelper.waitForTable();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileWithinLinkedFolder() throws Exception {
|
||||
|
||||
//
|
||||
// Check program file
|
||||
//
|
||||
|
||||
DomainFileInfo fileInfo = tableHelper.getDomainFileInfoByPath("/abc/bar");
|
||||
assertNotNull(fileInfo);
|
||||
|
||||
DomainFile df = fileInfo.getDomainFile();
|
||||
LinkFileInfo linkInfo = df.getLinkInfo();
|
||||
assertNull(linkInfo);
|
||||
|
||||
DomainFileType domainFileType = fileInfo.getDomainFileType();
|
||||
assertEquals("Program", domainFileType.getDisplayString());
|
||||
assertTrue("Unexpected tooltip: " + fileInfo.getToolTip(),
|
||||
fileInfo.getToolTip().startsWith("Last Modified"));
|
||||
|
||||
//
|
||||
// Verify program file reflected within linked-folder is not shown in table
|
||||
//
|
||||
|
||||
fileInfo = tableHelper.getDomainFileInfoByPath("/xyz/bar");
|
||||
assertNull(fileInfo);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileLink() throws Exception {
|
||||
|
||||
//
|
||||
// Create program link without referenced program in place
|
||||
//
|
||||
|
||||
xyzFolder.createLinkFile(rootFolder.getProjectData(), "/foo", false, "foo",
|
||||
ProgramLinkContentHandler.INSTANCE);
|
||||
|
||||
tableHelper.waitForTable();
|
||||
|
||||
//
|
||||
// Check initial state of broken program link
|
||||
//
|
||||
|
||||
DomainFileInfo fileInfo = tableHelper.getDomainFileInfoByPath("/xyz/foo");
|
||||
assertNotNull(fileInfo);
|
||||
|
||||
DomainFile df = fileInfo.getDomainFile();
|
||||
LinkFileInfo linkInfo = df.getLinkInfo();
|
||||
assertNotNull(linkInfo);
|
||||
|
||||
LinkStatus linkStatus = linkInfo.getLinkStatus(null);
|
||||
assertEquals(LinkStatus.BROKEN, linkStatus);
|
||||
|
||||
DomainFileType domainFileType = fileInfo.getDomainFileType();
|
||||
assertEquals("ProgramLink", domainFileType.getDisplayString());
|
||||
assertTrue("Unexpected tooltip: " + fileInfo.getToolTip(),
|
||||
fileInfo.getToolTip().startsWith("Broken ProgramLink - file not found"));
|
||||
|
||||
//
|
||||
// Add program file which should repair broken program link
|
||||
//
|
||||
|
||||
Program p = ToyProgramBuilder.buildSimpleProgram("foo", this);
|
||||
DomainFile programFile = rootFolder.createFile("foo", p, TaskMonitor.DUMMY);
|
||||
p.release(this);
|
||||
|
||||
tableHelper.waitForTable();
|
||||
|
||||
//
|
||||
// Check for new program file
|
||||
//
|
||||
|
||||
fileInfo = tableHelper.getDomainFileInfoByPath("/foo");
|
||||
assertNotNull(fileInfo);
|
||||
|
||||
df = fileInfo.getDomainFile();
|
||||
linkInfo = df.getLinkInfo();
|
||||
assertNull(linkInfo);
|
||||
|
||||
domainFileType = fileInfo.getDomainFileType();
|
||||
assertEquals("Program", domainFileType.getDisplayString());
|
||||
assertTrue("Unexpected tooltip: " + fileInfo.getToolTip(),
|
||||
fileInfo.getToolTip().startsWith("Last Modified")); // no error
|
||||
|
||||
//
|
||||
// Check for repaired program link
|
||||
//
|
||||
|
||||
fileInfo = tableHelper.getDomainFileInfoByPath("/xyz/foo");
|
||||
assertNotNull(fileInfo);
|
||||
|
||||
df = fileInfo.getDomainFile();
|
||||
linkInfo = df.getLinkInfo();
|
||||
assertNotNull(linkInfo);
|
||||
|
||||
linkStatus = linkInfo.getLinkStatus(null);
|
||||
assertEquals(LinkStatus.INTERNAL, linkStatus);
|
||||
|
||||
domainFileType = fileInfo.getDomainFileType();
|
||||
assertEquals("ProgramLink", domainFileType.getDisplayString());
|
||||
assertTrue("Unexpected tooltip: " + fileInfo.getToolTip(),
|
||||
fileInfo.getToolTip().startsWith("Last Modified")); // no error
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFolderLink() throws Exception {
|
||||
|
||||
// Create folder link without referenced folder in place
|
||||
xyzFolder.createLinkFile(rootFolder.getProjectData(), "/aaa", false, "aaa",
|
||||
FolderLinkContentHandler.INSTANCE);
|
||||
|
||||
tableHelper.waitForTable();
|
||||
|
||||
//
|
||||
// Check initial state of broken folder link
|
||||
//
|
||||
|
||||
DomainFileInfo fileInfo = tableHelper.getDomainFileInfoByPath("/xyz/aaa");
|
||||
assertNotNull(fileInfo);
|
||||
|
||||
DomainFile df = fileInfo.getDomainFile();
|
||||
LinkFileInfo linkInfo = df.getLinkInfo();
|
||||
assertNotNull(linkInfo);
|
||||
|
||||
LinkStatus linkStatus = linkInfo.getLinkStatus(null);
|
||||
assertEquals(LinkStatus.BROKEN, linkStatus);
|
||||
|
||||
DomainFileType domainFileType = fileInfo.getDomainFileType();
|
||||
assertEquals("FolderLink", domainFileType.getDisplayString());
|
||||
assertTrue("Unexpected tooltip: " + fileInfo.getToolTip(),
|
||||
fileInfo.getToolTip().startsWith("Broken FolderLink - folder not found"));
|
||||
|
||||
//
|
||||
// Add folder file which should repair broken folder link
|
||||
//
|
||||
|
||||
rootFolder.createFolder("aaa");
|
||||
|
||||
tableHelper.waitForTable();
|
||||
|
||||
//
|
||||
// Check for repaired folder link
|
||||
//
|
||||
|
||||
fileInfo = tableHelper.getDomainFileInfoByPath("/xyz/aaa");
|
||||
assertNotNull(fileInfo);
|
||||
|
||||
df = fileInfo.getDomainFile();
|
||||
linkInfo = df.getLinkInfo();
|
||||
assertNotNull(linkInfo);
|
||||
|
||||
linkStatus = linkInfo.getLinkStatus(null);
|
||||
assertEquals(LinkStatus.INTERNAL, linkStatus);
|
||||
|
||||
domainFileType = fileInfo.getDomainFileType();
|
||||
assertEquals("FolderLink", domainFileType.getDisplayString());
|
||||
assertTrue("Unexpected tooltip: " + fileInfo.getToolTip(),
|
||||
fileInfo.getToolTip().startsWith("Last Modified")); // no error
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -77,9 +77,7 @@ public class ProjectLinkFileStatusTest extends AbstractGhidraHeadedIntegrationTe
|
|||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (env != null) {
|
||||
env.dispose();
|
||||
}
|
||||
env.dispose();
|
||||
ClientUtil.clearRepositoryAdapter("localhost", ServerTestUtil.GHIDRA_TEST_SERVER_PORT);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* ###
|
||||
* 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.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.swing.JTabbedPane;
|
||||
|
||||
import docking.test.AbstractDockingTest;
|
||||
import docking.widgets.table.GTable;
|
||||
import generic.test.AbstractGuiTest;
|
||||
import ghidra.framework.main.FrontEndTool;
|
||||
import ghidra.framework.main.datatable.DomainFileInfo;
|
||||
import ghidra.framework.main.datatable.ProjectDataTableModel;
|
||||
import ghidra.framework.main.datatree.DataTree;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
/**
|
||||
* This class provides some convenience methods for interacting with a {@link DataTree}.
|
||||
*/
|
||||
public class FrontEndDataTableHelper {
|
||||
|
||||
private FrontEndTool frontEndTool;
|
||||
private GTable table;
|
||||
private ProjectDataTableModel model;
|
||||
|
||||
public FrontEndDataTableHelper(FrontEndTool frontEndTool) {
|
||||
this.frontEndTool = frontEndTool;
|
||||
table = AbstractGuiTest.findComponent(frontEndTool.getToolFrame(), GTable.class);
|
||||
model = (ProjectDataTableModel) table.getModel();
|
||||
}
|
||||
|
||||
public void showTablePanel() {
|
||||
|
||||
JTabbedPane projectTabbedPane = (JTabbedPane) AbstractGuiTest
|
||||
.findComponentByName(frontEndTool.getToolFrame(), "PROJECT_TABBED_PANE");
|
||||
assertNotNull("Project Data tabbed pane not found", projectTabbedPane);
|
||||
|
||||
Swing.runNow(() -> {
|
||||
for (int i = 0; i < projectTabbedPane.getTabCount(); i++) {
|
||||
if (projectTabbedPane.getTitleAt(i).equals("Table View")) {
|
||||
projectTabbedPane.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void waitForTable() {
|
||||
AbstractDockingTest.waitForTableModel(model);
|
||||
}
|
||||
|
||||
public GTable getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
public DomainFileInfo getDomainFileInfoByPath(String path) {
|
||||
int rowCount = model.getRowCount();
|
||||
for (int row = 0; row < rowCount; ++row) {
|
||||
DomainFileInfo fileInfo = model.getRowObject(row);
|
||||
if (path.equals(fileInfo.getDomainFile().getPathname())) {
|
||||
return fileInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue