better zip info support
This commit is contained in:
parent
2114d2d453
commit
0b23d2424a
@ -1714,9 +1714,11 @@ public class FilePanelTab extends JPanel {
|
||||
|
||||
public void showArchiveFile(File archive, String entryName) {
|
||||
rememberArchiveReturnState(archive);
|
||||
Path temp = extractArchiveToTemp(archive);
|
||||
if (temp != null) {
|
||||
// Delete any previous temp dir if different
|
||||
final String finalEntryName = entryName;
|
||||
|
||||
// Extract archive asynchronously
|
||||
extractArchiveToTempAsync(archive,
|
||||
temp -> {
|
||||
try {
|
||||
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
||||
deleteTempDirRecursively(currentArchiveTempDir);
|
||||
@ -1725,12 +1727,12 @@ public class FilePanelTab extends JPanel {
|
||||
currentArchiveTempDir = temp;
|
||||
currentArchiveSourceFile = archive;
|
||||
|
||||
if (entryName == null || entryName.isBlank()) {
|
||||
if (finalEntryName == null || finalEntryName.isBlank()) {
|
||||
loadDirectory(temp.toFile(), true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
File targetFile = new File(temp.toFile(), entryName);
|
||||
File targetFile = new File(temp.toFile(), finalEntryName);
|
||||
File targetDir = targetFile.isDirectory() ? targetFile : targetFile.getParentFile();
|
||||
|
||||
if (targetDir != null && targetDir.exists()) {
|
||||
@ -1742,92 +1744,12 @@ public class FilePanelTab extends JPanel {
|
||||
} else {
|
||||
loadDirectory(temp.toFile(), true, true);
|
||||
}
|
||||
} else {
|
||||
},
|
||||
error -> {
|
||||
clearArchiveReturnState();
|
||||
JOptionPane.showMessageDialog(FilePanelTab.this, error, "Archive Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private Path extractArchiveToTemp(File archive) {
|
||||
if (archive == null || !archive.isFile()) return null;
|
||||
try {
|
||||
Path tempDir = Files.createTempDirectory("kfmanager-archive-");
|
||||
final String[] usedPassword = new String[1];
|
||||
FileOperations.extractArchive(archive, tempDir.toFile(), new FileOperations.ProgressCallback() {
|
||||
@Override
|
||||
public void onProgress(long current, long total, String currentFile) {}
|
||||
|
||||
@Override
|
||||
public String requestPassword(String archiveName) {
|
||||
final String[] result = new String[1];
|
||||
try {
|
||||
Runnable showPasswordDialog = () -> {
|
||||
JPasswordField pf = new JPasswordField() {
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
requestFocusInWindow();
|
||||
}
|
||||
};
|
||||
|
||||
Object[] message = {
|
||||
"Enter password for " + archiveName,
|
||||
pf
|
||||
};
|
||||
|
||||
JOptionPane pane = new JOptionPane(message, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
|
||||
JDialog dialog = pane.createDialog(FilePanelTab.this, "Password Required");
|
||||
|
||||
dialog.addWindowFocusListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowGainedFocus(java.awt.event.WindowEvent e) {
|
||||
pf.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setVisible(true);
|
||||
Object selectedValue = pane.getValue();
|
||||
if (selectedValue != null && (Integer) selectedValue == JOptionPane.OK_OPTION) {
|
||||
result[0] = new String(pf.getPassword());
|
||||
usedPassword[0] = result[0];
|
||||
}
|
||||
};
|
||||
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
showPasswordDialog.run();
|
||||
} else {
|
||||
SwingUtilities.invokeAndWait(showPasswordDialog);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result[0] = null;
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileProgress(long current, long total) {}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() { return false; }
|
||||
|
||||
@Override
|
||||
public FileOperations.OverwriteResponse confirmOverwrite(File source, File target) { return FileOperations.OverwriteResponse.YES; }
|
||||
|
||||
@Override
|
||||
public FileOperations.ErrorResponse onError(File file, Exception e) { return FileOperations.ErrorResponse.ABORT; }
|
||||
|
||||
@Override
|
||||
public FileOperations.SymlinkResponse confirmSymlink(File file) { return FileOperations.SymlinkResponse.FOLLOW; }
|
||||
});
|
||||
currentArchivePassword = usedPassword[0];
|
||||
return tempDir;
|
||||
} catch (Exception ex) {
|
||||
// extraction failed; attempt best-effort cleanup
|
||||
try {
|
||||
if (currentArchiveTempDir != null) deleteTempDirRecursively(currentArchiveTempDir);
|
||||
} catch (Exception ignore) {}
|
||||
currentArchivePassword = null;
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void deleteTempDirRecursively(Path dir) {
|
||||
@ -1881,20 +1803,25 @@ public class FilePanelTab extends JPanel {
|
||||
navigateUp();
|
||||
} else if (FileOperations.isArchiveFile(item.getFile())) {
|
||||
rememberArchiveReturnState(item.getFile());
|
||||
Path temp = extractArchiveToTemp(item.getFile());
|
||||
if (temp != null) {
|
||||
// Delete any previous temp dir if different
|
||||
final File archiveFile = item.getFile();
|
||||
|
||||
// Extract archive asynchronously
|
||||
extractArchiveToTempAsync(archiveFile,
|
||||
temp -> {
|
||||
try {
|
||||
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
||||
deleteTempDirRecursively(currentArchiveTempDir);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
currentArchiveTempDir = temp;
|
||||
currentArchiveSourceFile = item.getFile();
|
||||
currentArchiveSourceFile = archiveFile;
|
||||
loadDirectory(temp.toFile());
|
||||
} else {
|
||||
},
|
||||
error -> {
|
||||
clearArchiveReturnState();
|
||||
JOptionPane.showMessageDialog(FilePanelTab.this, error, "Archive Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
);
|
||||
} else if (item.isDirectory()) {
|
||||
loadDirectory(item.getFile());
|
||||
} else if (item.getFile().isFile()) {
|
||||
@ -2400,19 +2327,25 @@ public class FilePanelTab extends JPanel {
|
||||
navigateUp();
|
||||
} else if (FileOperations.isArchiveFile(item.getFile())) {
|
||||
rememberArchiveReturnState(item.getFile());
|
||||
Path temp = extractArchiveToTemp(item.getFile());
|
||||
if (temp != null) {
|
||||
final File archiveFile = item.getFile();
|
||||
|
||||
// Extract archive asynchronously
|
||||
extractArchiveToTempAsync(archiveFile,
|
||||
temp -> {
|
||||
try {
|
||||
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
||||
deleteTempDirRecursively(currentArchiveTempDir);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
currentArchiveTempDir = temp;
|
||||
currentArchiveSourceFile = item.getFile();
|
||||
currentArchiveSourceFile = archiveFile;
|
||||
loadDirectory(temp.toFile(), true, true);
|
||||
} else {
|
||||
},
|
||||
error -> {
|
||||
clearArchiveReturnState();
|
||||
JOptionPane.showMessageDialog(FilePanelTab.this, error, "Archive Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
);
|
||||
} else if (item.isDirectory()) {
|
||||
loadDirectory(item.getFile());
|
||||
} else if (item.getFile().isFile()) {
|
||||
@ -4437,4 +4370,139 @@ public class FilePanelTab extends JPanel {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract archive asynchronously in background thread with progress dialog
|
||||
*/
|
||||
private void extractArchiveToTempAsync(File archive, java.util.function.Consumer<Path> onSuccess, java.util.function.Consumer<String> onError) {
|
||||
if (archive == null || !archive.isFile()) {
|
||||
onError.accept("Archive file not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Frame owner - traverse up to find JFrame
|
||||
Frame frameOwner = null;
|
||||
Component comp = this;
|
||||
while (comp != null) {
|
||||
if (comp instanceof Frame) {
|
||||
frameOwner = (Frame) comp;
|
||||
break;
|
||||
}
|
||||
comp = comp.getParent();
|
||||
}
|
||||
|
||||
if (frameOwner == null) {
|
||||
onError.accept("Cannot determine parent window for progress dialog");
|
||||
return;
|
||||
}
|
||||
|
||||
ProgressDialog progressDialog = new ProgressDialog(frameOwner, "Extracting Archive...", false);
|
||||
progressDialog.setVisible(true);
|
||||
|
||||
Thread extractionThread = new Thread(() -> {
|
||||
try {
|
||||
Path tempDir = java.nio.file.Files.createTempDirectory("kfmanager-archive-");
|
||||
final String[] usedPassword = new String[1];
|
||||
|
||||
FileOperations.extractArchive(archive, tempDir.toFile(), new FileOperations.ProgressCallback() {
|
||||
@Override
|
||||
public void onProgress(long current, long total, String currentFile) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
progressDialog.updateProgress(current, total, currentFile);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestPassword(String archiveName) {
|
||||
final String[] result = new String[1];
|
||||
try {
|
||||
progressDialog.setVisible(false);
|
||||
Runnable showPasswordDialog = () -> {
|
||||
JPasswordField pf = new JPasswordField() {
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
requestFocusInWindow();
|
||||
}
|
||||
};
|
||||
|
||||
Object[] message = {
|
||||
"Enter password for " + archiveName,
|
||||
pf
|
||||
};
|
||||
|
||||
JOptionPane pane = new JOptionPane(message, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
|
||||
JDialog dialog = pane.createDialog(FilePanelTab.this, "Password Required");
|
||||
|
||||
dialog.addWindowFocusListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowGainedFocus(java.awt.event.WindowEvent e) {
|
||||
pf.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.setVisible(true);
|
||||
Object selectedValue = pane.getValue();
|
||||
if (selectedValue != null && (Integer) selectedValue == JOptionPane.OK_OPTION) {
|
||||
result[0] = new String(pf.getPassword());
|
||||
usedPassword[0] = result[0];
|
||||
}
|
||||
};
|
||||
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
showPasswordDialog.run();
|
||||
} else {
|
||||
SwingUtilities.invokeAndWait(showPasswordDialog);
|
||||
}
|
||||
progressDialog.setVisible(result[0] != null);
|
||||
} catch (Exception e) {
|
||||
result[0] = null;
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileProgress(long current, long total) {}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return progressDialog == null || !progressDialog.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileOperations.OverwriteResponse confirmOverwrite(File source, File target) {
|
||||
return FileOperations.OverwriteResponse.YES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileOperations.ErrorResponse onError(File file, Exception e) {
|
||||
return FileOperations.ErrorResponse.ABORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileOperations.SymlinkResponse confirmSymlink(File file) {
|
||||
return FileOperations.SymlinkResponse.FOLLOW;
|
||||
}
|
||||
});
|
||||
|
||||
currentArchivePassword = usedPassword[0];
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
progressDialog.setVisible(false);
|
||||
progressDialog.dispose();
|
||||
onSuccess.accept(tempDir);
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
progressDialog.setVisible(false);
|
||||
progressDialog.dispose();
|
||||
onError.accept("Failed to extract archive: " + ex.getMessage());
|
||||
});
|
||||
}
|
||||
}, "ArchiveExtractionThread");
|
||||
|
||||
extractionThread.setDaemon(false);
|
||||
extractionThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user