mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-01-10 06:27:59 -05:00
Test fixes
This commit is contained in:
@@ -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.
|
||||
@@ -55,14 +55,13 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
private CParserPlugin plugin;
|
||||
|
||||
private DockingActionIf cparserAction;
|
||||
|
||||
|
||||
private DataTypeManagerPlugin dtmPlugin;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
program = getNotepad();
|
||||
|
||||
|
||||
env = new TestEnv();
|
||||
}
|
||||
|
||||
@@ -80,7 +79,8 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
private void initTool(Program prog) throws Exception {
|
||||
if (prog != null) {
|
||||
tool = env.showTool(prog);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
tool = env.showTool();
|
||||
}
|
||||
|
||||
@@ -99,48 +99,48 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
initTool(null);
|
||||
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("No Open Program"), "OK", false);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportToProgramNoArch() throws Exception {
|
||||
program = getNotepad();
|
||||
|
||||
|
||||
initTool(program);
|
||||
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "MacOSX_10.5.prf");
|
||||
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
String langText = parseDialog.getLanguageText().getText();
|
||||
assertEquals("64/32 (primarily for backward compatibility)", langText);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Cancel", false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportToProgramConfirm() throws Exception {
|
||||
program = getNotepad();
|
||||
|
||||
|
||||
initTool(program);
|
||||
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Cancel", false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportToProgram() throws Exception {
|
||||
|
||||
@@ -149,45 +149,46 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
// write out a dummy header file to read
|
||||
File dummyHeader = this.createTempFile("dummy.h");
|
||||
|
||||
|
||||
FileUtilities.deleteDir(dummyHeader);
|
||||
|
||||
String files[] = {dummyHeader.getPath()};
|
||||
|
||||
|
||||
String files[] = { dummyHeader.getPath() };
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
|
||||
|
||||
|
||||
// dummy file empty, error
|
||||
pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Failed"), "OK", false);
|
||||
|
||||
// dummy file full, OK
|
||||
FileUtilities.writeStringToFile(dummyHeader,
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
"};\n");
|
||||
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
"};\n");
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
|
||||
|
||||
|
||||
waitForBusyTool(tool);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
|
||||
|
||||
DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Completed"), "OK", false);
|
||||
|
||||
DataType dataType = program.getDataTypeManager()
|
||||
.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
|
||||
|
||||
assertNotNull("mystruct parsed into program", dataType);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportToProgramWithIncludePaths() throws Exception {
|
||||
|
||||
@@ -196,67 +197,69 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
// write out a dummy header file to read
|
||||
File dummyHeader = this.createTempFile("dummy.h");
|
||||
|
||||
|
||||
FileUtilities.deleteDir(dummyHeader);
|
||||
|
||||
String files[] = {dummyHeader.getName()};
|
||||
|
||||
|
||||
String files[] = { dummyHeader.getName() };
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
String includePath[] = {dummyHeader.getParent()};
|
||||
|
||||
|
||||
String includePath[] = { dummyHeader.getParent() };
|
||||
|
||||
this.setIncludePaths(parseDialog, includePath);
|
||||
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
|
||||
|
||||
|
||||
// dummy file empty, error
|
||||
pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Failed"), "OK", false);
|
||||
|
||||
// dummy file full, OK
|
||||
FileUtilities.writeStringToFile(dummyHeader,
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
"};\n");
|
||||
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
"};\n");
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
|
||||
|
||||
|
||||
waitForBusyTool(tool);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
|
||||
|
||||
DataType dataType = program.getDataTypeManager().getDataType("/"+dummyHeader.getName()+ "/" + "mystruct");
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Completed"), "OK", false);
|
||||
|
||||
DataType dataType = program.getDataTypeManager()
|
||||
.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
|
||||
|
||||
assertNotNull("mystruct parsed into program", dataType);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testImportToProgramOpenArchives() throws Exception {
|
||||
initTool(program);
|
||||
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
|
||||
// open an archive
|
||||
dtmPlugin.openDataTypeArchive("windows_vs12_64");
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to Program", false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Confirm"), "Continue", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Don't Use Open Archives", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Don't Use Open Archives",
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
// switch between two
|
||||
// change, test ask save if change
|
||||
@Test
|
||||
@@ -267,92 +270,91 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
|
||||
//
|
||||
// test switch to new profile after changes, NO to save changes
|
||||
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
setLanguage(parseDialog, "8051:BE:16:default", "default");
|
||||
|
||||
|
||||
runSwing(() -> {
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
|
||||
}, false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "No", false);
|
||||
|
||||
|
||||
assertEquals("VisualStudio12_64.prf",parseDialog.getCurrentItem().getName());
|
||||
|
||||
|
||||
assertEquals("VisualStudio12_64.prf", parseDialog.getCurrentItem().getName());
|
||||
|
||||
//
|
||||
// test forced save as new profile, doesn't exist
|
||||
setLanguage(parseDialog, "8051:BE:16:default", "default");
|
||||
|
||||
|
||||
runSwing(() -> {
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
}, false);
|
||||
|
||||
|
||||
// make sure profile is gone
|
||||
ResourceFile userProfileParent = parseDialog.getUserProfileParent();
|
||||
File f = new File(userProfileParent.getAbsolutePath(),"MyTestProfile.prf");
|
||||
File f = new File(userProfileParent.getAbsolutePath(), "MyTestProfile.prf");
|
||||
f.delete();
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
|
||||
|
||||
|
||||
InputDialog dialog = waitForDialogComponent(InputDialog.class);
|
||||
|
||||
dialog.setValue("MyTestProfile");
|
||||
pressButtonByText(dialog, "OK");
|
||||
waitForSwing();
|
||||
|
||||
assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
|
||||
|
||||
|
||||
assertEquals("MyTestProfile.prf", parseDialog.getCurrentItem().getName());
|
||||
|
||||
// test save as forced to an existing profile
|
||||
|
||||
|
||||
runSwing(() -> {
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_64.prf");
|
||||
}, false);
|
||||
|
||||
|
||||
setLanguage(parseDialog, "x86:LE:64:default", "gcc");
|
||||
|
||||
|
||||
runSwing(() -> {
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
}, false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Save Changes to Another Profile?"), "Yes", false);
|
||||
|
||||
|
||||
dialog = waitForDialogComponent(InputDialog.class);
|
||||
|
||||
dialog.setValue("MyTestProfile");
|
||||
pressButtonByText(dialog, "OK");
|
||||
waitForSwing();
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
|
||||
|
||||
|
||||
waitForSwing();
|
||||
|
||||
assertEquals("MyTestProfile.prf",parseDialog.getCurrentItem().getName());
|
||||
|
||||
assertEquals("MyTestProfile.prf", parseDialog.getCurrentItem().getName());
|
||||
|
||||
// test save the current USER profile when switching
|
||||
|
||||
|
||||
runSwing(() -> {
|
||||
this.setSelectedParseProfile(parseDialog, "MyTestProfile.prf");
|
||||
}, false);
|
||||
|
||||
|
||||
setLanguage(parseDialog, "8051:BE:16:default", "default");
|
||||
|
||||
|
||||
runSwing(() -> {
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
}, false);
|
||||
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Save Changes to Profile?"), "Yes", false);
|
||||
|
||||
assertEquals("VisualStudio12_32.prf",parseDialog.getCurrentItem().getName());
|
||||
|
||||
|
||||
assertEquals("VisualStudio12_32.prf", parseDialog.getCurrentItem().getName());
|
||||
|
||||
}
|
||||
|
||||
private void setLanguage(ParseDialog parseDialog, String langID, String compID) {
|
||||
runSwing(() -> {
|
||||
pressButton(parseDialog.getLanguageButton());
|
||||
}, false);
|
||||
|
||||
|
||||
SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
|
||||
assertNotNull(dlg);
|
||||
NewLanguagePanel languagePanel =
|
||||
@@ -372,7 +374,7 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
|
||||
pressButtonByText(dlg, "OK");
|
||||
}
|
||||
|
||||
|
||||
// test parse to file, choose file
|
||||
@Test
|
||||
public void testImportToFile() throws Exception {
|
||||
@@ -380,70 +382,71 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
initTool(program);
|
||||
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
setLanguage(parseDialog, "8051:BE:16:default", "default");
|
||||
|
||||
|
||||
final File tmpDir = createTempDirectory("GDT");
|
||||
FileUtilities.checkedMkdir(tmpDir);
|
||||
|
||||
|
||||
// open an archive
|
||||
// write out a dummy header file to read
|
||||
File dummyHeader = this.createTempFile("dummy.h");
|
||||
|
||||
|
||||
FileUtilities.deleteDir(dummyHeader);
|
||||
|
||||
String files[] = {dummyHeader.getName()};
|
||||
|
||||
|
||||
String files[] = { dummyHeader.getName() };
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
String includePath[] = {dummyHeader.getParent()};
|
||||
|
||||
|
||||
String includePath[] = { dummyHeader.getParent() };
|
||||
|
||||
this.setIncludePaths(parseDialog, includePath);
|
||||
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to File...", false);
|
||||
|
||||
|
||||
final GhidraFileChooser fileChooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
|
||||
|
||||
runSwing(() -> fileChooser.setSelectedFile(new File(tmpDir, "dummy")));
|
||||
|
||||
|
||||
waitForUpdateOnChooser(fileChooser);
|
||||
|
||||
pressButtonByName(fileChooser.getComponent(), "OK");
|
||||
|
||||
|
||||
// dummy file empty, error
|
||||
pressButtonByText(waitForDialogComponent("Parse Errors"), "OK", false);
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Failed"), "OK", false);
|
||||
|
||||
// dummy file full, OK
|
||||
FileUtilities.writeStringToFile(dummyHeader,
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
"};\n");
|
||||
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
"};\n");
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to File...", false);
|
||||
|
||||
|
||||
final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
|
||||
|
||||
final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
|
||||
|
||||
|
||||
runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
|
||||
|
||||
|
||||
waitForUpdateOnChooser(existsChooser);
|
||||
|
||||
pressButtonByName(existsChooser.getComponent(), "OK");
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Overwrite Existing File?"), "Yes", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Completed"), "OK", false);
|
||||
|
||||
waitForBusyTool(tool);
|
||||
|
||||
// open the file archive
|
||||
FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
|
||||
FileDataTypeManager fileArchive =
|
||||
FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
|
||||
try {
|
||||
DataType dataType =
|
||||
fileArchive.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
|
||||
@@ -461,59 +464,60 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
initTool(program);
|
||||
|
||||
ParseDialog parseDialog = showParseDialog();
|
||||
|
||||
|
||||
// open an archive
|
||||
dtmPlugin.openDataTypeArchive("windows_vs12_64");
|
||||
|
||||
|
||||
this.setSelectedParseProfile(parseDialog, "VisualStudio12_32.prf");
|
||||
|
||||
|
||||
setLanguage(parseDialog, "8051:BE:16:default", "default");
|
||||
|
||||
|
||||
final File tmpDir = createTempDirectory("GDT");
|
||||
FileUtilities.checkedMkdir(tmpDir);
|
||||
|
||||
|
||||
// open an archive
|
||||
// write out a dummy header file to read
|
||||
File dummyHeader = this.createTempFile("dummy.h");
|
||||
|
||||
|
||||
FileUtilities.deleteDir(dummyHeader);
|
||||
|
||||
String files[] = {dummyHeader.getName()};
|
||||
|
||||
String includePath[] = {dummyHeader.getParent()};
|
||||
|
||||
|
||||
String files[] = { dummyHeader.getName() };
|
||||
|
||||
String includePath[] = { dummyHeader.getParent() };
|
||||
|
||||
this.setIncludePaths(parseDialog, includePath);
|
||||
|
||||
// dummy file full, OK
|
||||
FileUtilities.writeStringToFile(dummyHeader,
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
" wint_t defined_from_windows;\n" +
|
||||
"};\n");
|
||||
|
||||
"typedef int wchar_t;\n" +
|
||||
"struct mystruct {\n" +
|
||||
" wchar_t defined_wchar_t;\n" +
|
||||
" wint_t defined_from_windows;\n" +
|
||||
"};\n");
|
||||
|
||||
this.setFiles(parseDialog, files);
|
||||
|
||||
pressButtonByText(parseDialog, "Parse to File...", false);
|
||||
|
||||
|
||||
final GhidraFileChooser existsChooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
|
||||
|
||||
final File GDTarchiveFile = new File(tmpDir, "dummy.gdt");
|
||||
|
||||
|
||||
runSwing(() -> existsChooser.setSelectedFile(GDTarchiveFile), true);
|
||||
|
||||
|
||||
waitForUpdateOnChooser(existsChooser);
|
||||
|
||||
pressButtonByName(existsChooser.getComponent(), "OK");
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Use Open Archives", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("Use Open Archives?"), "Use Open Archives", false);
|
||||
|
||||
waitForBusyTool(tool);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse of Header Files Complete"), "OK", false);
|
||||
|
||||
pressButtonByText(waitForDialogComponent("C-Parse Completed"), "OK", false);
|
||||
|
||||
// open the file archive
|
||||
FileDataTypeManager fileArchive = FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
|
||||
FileDataTypeManager fileArchive =
|
||||
FileDataTypeManager.openFileArchive(GDTarchiveFile, false);
|
||||
try {
|
||||
DataType dataType =
|
||||
fileArchive.getDataType("/" + dummyHeader.getName() + "/" + "mystruct");
|
||||
@@ -530,8 +534,8 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void startSetLanguage(LanguageID languageID, CompilerSpecID compilerSpecID) throws Exception {
|
||||
private void startSetLanguage(LanguageID languageID, CompilerSpecID compilerSpecID)
|
||||
throws Exception {
|
||||
if (languageID == null) {
|
||||
throw new RuntimeException("languageID == null not allowed");
|
||||
}
|
||||
@@ -580,14 +584,14 @@ public class ParseDialogParsingAndPromptsTest extends AbstractGhidraHeadedIntegr
|
||||
parseOptionsTextField.setText(options);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void setIncludePaths(ParseDialog dialog, String paths[]) {
|
||||
runSwing(() -> {
|
||||
PathnameTablePanel incPaths = dialog.getIncludePaths();
|
||||
incPaths.setPaths(paths);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void setFiles(ParseDialog dialog, String files[]) {
|
||||
runSwing(() -> {
|
||||
PathnameTablePanel sourceFiles = dialog.getSourceFiles();
|
||||
|
||||
Reference in New Issue
Block a user