Skip to content

Commit

Permalink
Partial Fix For Slow jFileChooser
Browse files Browse the repository at this point in the history
Start of fixing #272

This is a Swing / JDK bug - Using a different JDK is the recommended fix, but this work around helps cut the time waited by a lot.
  • Loading branch information
Konloch committed Sep 30, 2024
1 parent d78ab84 commit 133526c
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import java.io.IOException;
import java.util.List;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static javax.swing.JOptionPane.QUESTION_MESSAGE;
import static the.bytecode.club.bytecodeviewer.Constants.*;
Expand Down Expand Up @@ -263,7 +265,8 @@ public static void boot(boolean cli)
TASK_MANAGER.start();

//setup the viewer
viewer.calledAfterLoad();
if(!cli)
viewer.calledAfterLoad();

//setup the recent files
Settings.resetRecentFilesMenu();
Expand Down
37 changes: 22 additions & 15 deletions src/main/java/the/bytecode/club/bytecodeviewer/GlobalHotKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,26 +103,33 @@ else if ((e.getKeyCode() == KeyEvent.VK_S) && ((e.getModifiersEx() & KeyEvent.CT
if (!BytecodeViewer.autoCompileSuccessful())
return;

JFileChooser fc = new FileChooser(Configuration.getLastSaveDirectory(), "Select Zip Export", "Zip Archives", "zip");
try
{
JFileChooser fc = FileChooser.create(Configuration.getLastSaveDirectory(), "Select Zip Export", "Zip Archives", "zip");

int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);

if (returnVal == JFileChooser.APPROVE_OPTION)
{
Configuration.setLastSaveDirectory(fc.getSelectedFile());
if (returnVal == JFileChooser.APPROVE_OPTION)
{
Configuration.setLastSaveDirectory(fc.getSelectedFile());

File file = MiscUtils.autoAppendFileExtension(".zip", fc.getSelectedFile());
File file = MiscUtils.autoAppendFileExtension(".zip", fc.getSelectedFile());

if (!DialogUtils.canOverwriteFile(file))
return;
if (!DialogUtils.canOverwriteFile(file))
return;

BytecodeViewer.updateBusyStatus(true);
Thread jarExport = new Thread(() ->
{
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
BytecodeViewer.updateBusyStatus(false);
}, "Jar Export");
jarExport.start();
BytecodeViewer.updateBusyStatus(true);
Thread jarExport = new Thread(() ->
{
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), file.getAbsolutePath());
BytecodeViewer.updateBusyStatus(false);
}, "Jar Export");
jarExport.start();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}, "Resource Export");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.ExecutionException;

import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
import static the.bytecode.club.bytecodeviewer.Constants.NL;
Expand Down Expand Up @@ -145,9 +146,9 @@ else if (result == 2)
}
}

public static File promptFileSave(String description, String extension) throws IOException
public static File promptFileSave(String description, String extension) throws IOException, ExecutionException, InterruptedException
{
JFileChooser fc = new FileChooser(new File("./").getCanonicalFile(), "Select Save File", description, extension);
JFileChooser fc = FileChooser.create(new File("./").getCanonicalFile(), "Select Save File", description, extension);

int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
File file = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static the.bytecode.club.bytecodeviewer.Configuration.useNewSettingsDialog;
import static the.bytecode.club.bytecodeviewer.Constants.VERSION;
Expand Down Expand Up @@ -835,6 +837,10 @@ public void defaultSettings()
public void calledAfterLoad()
{
deleteForeignOutdatedLibs.setSelected(Configuration.deleteForeignLibraries);

//preload the jFileChooser to fix https://stackoverflow.com/a/59165208
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(FileChooser.SINGLETON);
}

public int getFontSize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,48 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
* @author Konloch
* @since 6/25/2021
*/
public class FileChooser extends JFileChooser
public class FileChooser
{
public static final FutureTask<JFileChooser> SINGLETON = new FutureTask<>(JFileChooser::new);
public static final String EVERYTHING = "everything";

public FileChooser(File file, String title, String description, String... extensions)
public static JFileChooser create(File file, String title, String description, String... extensions) throws ExecutionException, InterruptedException
{
this(false, file, title, description, extensions);
return create(false, file, title, description, extensions);
}

public FileChooser(boolean skipFileFilter, File file, String title, String description, String... extensions)
public static JFileChooser create(boolean skipFileFilter, File file, String title, String description, String... extensions) throws ExecutionException, InterruptedException
{
JFileChooser chooser = SINGLETON.get();

Set<String> extensionSet = new HashSet<>(Arrays.asList(extensions));

setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

try
{
setSelectedFile(file);
chooser.setSelectedFile(file);
}
catch (Exception ignored)
{
}

setDialogTitle(title);
setFileHidingEnabled(false);
setAcceptAllFileFilterUsed(false);
chooser.setDialogTitle(title);
chooser.setFileHidingEnabled(false);
chooser.setAcceptAllFileFilterUsed(false);

chooser.resetChoosableFileFilters();

if (!skipFileFilter)
{
addChoosableFileFilter(new FileFilter()
chooser.addChoosableFileFilter(new FileFilter()
{
@Override
public boolean accept(File f)
Expand All @@ -80,5 +88,7 @@ public String getDescription()
}
});
}

return chooser;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,30 +235,37 @@ public void save()

if (savePath == null)
{
final String ext = FileNameUtils.getExtension(pluginName);
JFileChooser fc = new FileChooser(Configuration.getLastPluginDirectory(), "Save Plugin", "BCV Plugin", ext);

int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
if (returnVal == JFileChooser.APPROVE_OPTION)
try
{
Configuration.setLastPluginDirectory(fc.getSelectedFile());
final String ext = FileNameUtils.getExtension(pluginName);
JFileChooser fc = FileChooser.create(Configuration.getLastPluginDirectory(), "Save Plugin", "BCV Plugin", ext);

File file = fc.getSelectedFile();
String path = file.getAbsolutePath();
int returnVal = fc.showSaveDialog(BytecodeViewer.viewer);
if (returnVal == JFileChooser.APPROVE_OPTION)
{
Configuration.setLastPluginDirectory(fc.getSelectedFile());

//auto append extension
if (!path.endsWith("." + ext))
path += "." + ext;
File file = fc.getSelectedFile();
String path = file.getAbsolutePath();

if (!DialogUtils.canOverwriteFile(path))
return;
//auto append extension
if (!path.endsWith("." + ext))
path += "." + ext;

//swap from save-as to having a defined path each save
setSourceFile(new File(path));
if (!DialogUtils.canOverwriteFile(path))
return;

//swap from save-as to having a defined path each save
setSourceFile(new File(path));
}
else
{
return;
}
}
else
catch (Exception e)
{
return;
e.printStackTrace();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,42 +63,42 @@ public static void decompileSaveAll()

MiscUtils.createNewThread("Decompile Save-All Thread", () ->
{
//signal to the user that BCV is performing an action in the background
BytecodeViewer.updateBusyStatus(true);
try
{
//signal to the user that BCV is performing an action in the background
BytecodeViewer.updateBusyStatus(true);

//auto compile before decompilation
if (!BytecodeViewer.autoCompileSuccessful())
return;
//auto compile before decompilation
if (!BytecodeViewer.autoCompileSuccessful())
return;

final JFileChooser fc = new FileChooser(Configuration.getLastSaveDirectory(),
"Select Zip Export", "Zip Archives", "zip");
final JFileChooser fc = FileChooser.create(Configuration.getLastSaveDirectory(),
"Select Zip Export", "Zip Archives", "zip");

//if the user doesn't select a file then we should stop while we're ahead
if (fc.showSaveDialog(BytecodeViewer.viewer) != JFileChooser.APPROVE_OPTION)
return;
//if the user doesn't select a file then we should stop while we're ahead
if (fc.showSaveDialog(BytecodeViewer.viewer) != JFileChooser.APPROVE_OPTION)
return;

//set the last touched save directory for BCV
Configuration.setLastSaveDirectory(fc.getSelectedFile());
//set the last touched save directory for BCV
Configuration.setLastSaveDirectory(fc.getSelectedFile());

//get the save file and auto append zip extension
final File outputZip = MiscUtils.autoAppendFileExtension(".zip", fc.getSelectedFile());
//get the save file and auto append zip extension
final File outputZip = MiscUtils.autoAppendFileExtension(".zip", fc.getSelectedFile());

//prompt the user for a dialogue override-this-file option if the file already exists
if (!DialogUtils.canOverwriteFile(outputZip))
return;
//prompt the user for a dialogue override-this-file option if the file already exists
if (!DialogUtils.canOverwriteFile(outputZip))
return;

//this temporary jar file will be used to store the classes while BCV performs decompilation
File temporaryTargetJar = MiscUtils.deleteExistingFile(new File(TEMP_DIRECTORY + FS
+ "temp_" + MiscUtils.getRandomizedName() + ".jar"));
//this temporary jar file will be used to store the classes while BCV performs decompilation
File temporaryTargetJar = MiscUtils.deleteExistingFile(new File(TEMP_DIRECTORY + FS
+ "temp_" + MiscUtils.getRandomizedName() + ".jar"));

//extract all the loaded classes imported into BCV to the temporary target jar
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), temporaryTargetJar.getAbsolutePath());
//extract all the loaded classes imported into BCV to the temporary target jar
JarUtils.saveAsJarClassesOnly(BytecodeViewer.getLoadedClasses(), temporaryTargetJar.getAbsolutePath());

//signal to the user that BCV is finished performing that action
BytecodeViewer.updateBusyStatus(false);
//signal to the user that BCV is finished performing that action
BytecodeViewer.updateBusyStatus(false);

try
{
//handle the result of the user selection
switch (promptDecompilerUserSelect() + DECOMPILE_SAVE_ALL)
{
Expand Down Expand Up @@ -159,34 +159,35 @@ public static void decompileSaveOpenedResource()

MiscUtils.createNewThread("Decompile Save Opened Resource", () ->
{
//signal to the user that BCV is performing an action in the background
BytecodeViewer.updateBusyStatus(true);
try
{
//signal to the user that BCV is performing an action in the background
BytecodeViewer.updateBusyStatus(true);

//auto compile before decompilation
if (!BytecodeViewer.autoCompileSuccessful())
return;
//auto compile before decompilation
if (!BytecodeViewer.autoCompileSuccessful())
return;

JFileChooser fc = new FileChooser(Configuration.getLastSaveDirectory(), "Select Java Files", "Java Source Files", "java");
JFileChooser fc = FileChooser.create(Configuration.getLastSaveDirectory(),
"Select Java Files", "Java Source Files", "java");

//if the user doesn't select a file then we should stop while we're ahead
if (fc.showSaveDialog(BytecodeViewer.viewer) != JFileChooser.APPROVE_OPTION)
return;
//if the user doesn't select a file then we should stop while we're ahead
if (fc.showSaveDialog(BytecodeViewer.viewer) != JFileChooser.APPROVE_OPTION)
return;

//set the last touched save directory for BCV
Configuration.setLastSaveDirectory(fc.getSelectedFile());
//set the last touched save directory for BCV
Configuration.setLastSaveDirectory(fc.getSelectedFile());

//get the save file and auto append java extension
File file = MiscUtils.autoAppendFileExtension(".java", fc.getSelectedFile());
//get the save file and auto append java extension
File file = MiscUtils.autoAppendFileExtension(".java", fc.getSelectedFile());

//prompt the user for a dialogue override-this-file option if the file already exists
if (!DialogUtils.canOverwriteFile(file))
return;
//prompt the user for a dialogue override-this-file option if the file already exists
if (!DialogUtils.canOverwriteFile(file))
return;

//signal to the user that BCV is finished performing that action
BytecodeViewer.updateBusyStatus(false);
//signal to the user that BCV is finished performing that action
BytecodeViewer.updateBusyStatus(false);

try
{
//handle the result of the user selection
switch (promptDecompilerUserSelect() + DECOMPILE_OPENED_ONLY_ALL)
{
Expand Down
Loading

0 comments on commit 133526c

Please sign in to comment.