better zip info support
This commit is contained in:
parent
2114d2d453
commit
0b23d2424a
@ -1714,120 +1714,42 @@ public class FilePanelTab extends JPanel {
|
|||||||
|
|
||||||
public void showArchiveFile(File archive, String entryName) {
|
public void showArchiveFile(File archive, String entryName) {
|
||||||
rememberArchiveReturnState(archive);
|
rememberArchiveReturnState(archive);
|
||||||
Path temp = extractArchiveToTemp(archive);
|
final String finalEntryName = entryName;
|
||||||
if (temp != null) {
|
|
||||||
// Delete any previous temp dir if different
|
// Extract archive asynchronously
|
||||||
try {
|
extractArchiveToTempAsync(archive,
|
||||||
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
temp -> {
|
||||||
deleteTempDirRecursively(currentArchiveTempDir);
|
try {
|
||||||
}
|
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
||||||
} catch (Exception ignore) {}
|
deleteTempDirRecursively(currentArchiveTempDir);
|
||||||
currentArchiveTempDir = temp;
|
|
||||||
currentArchiveSourceFile = archive;
|
|
||||||
|
|
||||||
if (entryName == null || entryName.isBlank()) {
|
|
||||||
loadDirectory(temp.toFile(), true, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
File targetFile = new File(temp.toFile(), entryName);
|
|
||||||
File targetDir = targetFile.isDirectory() ? targetFile : targetFile.getParentFile();
|
|
||||||
|
|
||||||
if (targetDir != null && targetDir.exists()) {
|
|
||||||
loadDirectory(targetDir, false, true, () -> {
|
|
||||||
if (!targetFile.isDirectory()) {
|
|
||||||
selectItem(targetFile.getName());
|
|
||||||
}
|
}
|
||||||
});
|
} catch (Exception ignore) {}
|
||||||
} else {
|
currentArchiveTempDir = temp;
|
||||||
loadDirectory(temp.toFile(), true, true);
|
currentArchiveSourceFile = archive;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clearArchiveReturnState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path extractArchiveToTemp(File archive) {
|
if (finalEntryName == null || finalEntryName.isBlank()) {
|
||||||
if (archive == null || !archive.isFile()) return null;
|
loadDirectory(temp.toFile(), true, true);
|
||||||
try {
|
return;
|
||||||
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
|
File targetFile = new File(temp.toFile(), finalEntryName);
|
||||||
public String requestPassword(String archiveName) {
|
File targetDir = targetFile.isDirectory() ? targetFile : targetFile.getParentFile();
|
||||||
final String[] result = new String[1];
|
|
||||||
try {
|
if (targetDir != null && targetDir.exists()) {
|
||||||
Runnable showPasswordDialog = () -> {
|
loadDirectory(targetDir, false, true, () -> {
|
||||||
JPasswordField pf = new JPasswordField() {
|
if (!targetFile.isDirectory()) {
|
||||||
@Override
|
selectItem(targetFile.getName());
|
||||||
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;
|
} else {
|
||||||
}
|
loadDirectory(temp.toFile(), true, true);
|
||||||
return result[0];
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
@Override
|
error -> {
|
||||||
public void onFileProgress(long current, long total) {}
|
clearArchiveReturnState();
|
||||||
|
JOptionPane.showMessageDialog(FilePanelTab.this, error, "Archive Error", JOptionPane.ERROR_MESSAGE);
|
||||||
@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) {
|
private void deleteTempDirRecursively(Path dir) {
|
||||||
@ -1881,20 +1803,25 @@ public class FilePanelTab extends JPanel {
|
|||||||
navigateUp();
|
navigateUp();
|
||||||
} else if (FileOperations.isArchiveFile(item.getFile())) {
|
} else if (FileOperations.isArchiveFile(item.getFile())) {
|
||||||
rememberArchiveReturnState(item.getFile());
|
rememberArchiveReturnState(item.getFile());
|
||||||
Path temp = extractArchiveToTemp(item.getFile());
|
final File archiveFile = item.getFile();
|
||||||
if (temp != null) {
|
|
||||||
// Delete any previous temp dir if different
|
// Extract archive asynchronously
|
||||||
try {
|
extractArchiveToTempAsync(archiveFile,
|
||||||
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
temp -> {
|
||||||
deleteTempDirRecursively(currentArchiveTempDir);
|
try {
|
||||||
}
|
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
||||||
} catch (Exception ignore) {}
|
deleteTempDirRecursively(currentArchiveTempDir);
|
||||||
currentArchiveTempDir = temp;
|
}
|
||||||
currentArchiveSourceFile = item.getFile();
|
} catch (Exception ignore) {}
|
||||||
loadDirectory(temp.toFile());
|
currentArchiveTempDir = temp;
|
||||||
} else {
|
currentArchiveSourceFile = archiveFile;
|
||||||
clearArchiveReturnState();
|
loadDirectory(temp.toFile());
|
||||||
}
|
},
|
||||||
|
error -> {
|
||||||
|
clearArchiveReturnState();
|
||||||
|
JOptionPane.showMessageDialog(FilePanelTab.this, error, "Archive Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
);
|
||||||
} else if (item.isDirectory()) {
|
} else if (item.isDirectory()) {
|
||||||
loadDirectory(item.getFile());
|
loadDirectory(item.getFile());
|
||||||
} else if (item.getFile().isFile()) {
|
} else if (item.getFile().isFile()) {
|
||||||
@ -2400,19 +2327,25 @@ public class FilePanelTab extends JPanel {
|
|||||||
navigateUp();
|
navigateUp();
|
||||||
} else if (FileOperations.isArchiveFile(item.getFile())) {
|
} else if (FileOperations.isArchiveFile(item.getFile())) {
|
||||||
rememberArchiveReturnState(item.getFile());
|
rememberArchiveReturnState(item.getFile());
|
||||||
Path temp = extractArchiveToTemp(item.getFile());
|
final File archiveFile = item.getFile();
|
||||||
if (temp != null) {
|
|
||||||
try {
|
// Extract archive asynchronously
|
||||||
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
extractArchiveToTempAsync(archiveFile,
|
||||||
deleteTempDirRecursively(currentArchiveTempDir);
|
temp -> {
|
||||||
}
|
try {
|
||||||
} catch (Exception ignore) {}
|
if (currentArchiveTempDir != null && !currentArchiveTempDir.equals(temp)) {
|
||||||
currentArchiveTempDir = temp;
|
deleteTempDirRecursively(currentArchiveTempDir);
|
||||||
currentArchiveSourceFile = item.getFile();
|
}
|
||||||
loadDirectory(temp.toFile(), true, true);
|
} catch (Exception ignore) {}
|
||||||
} else {
|
currentArchiveTempDir = temp;
|
||||||
clearArchiveReturnState();
|
currentArchiveSourceFile = archiveFile;
|
||||||
}
|
loadDirectory(temp.toFile(), true, true);
|
||||||
|
},
|
||||||
|
error -> {
|
||||||
|
clearArchiveReturnState();
|
||||||
|
JOptionPane.showMessageDialog(FilePanelTab.this, error, "Archive Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
);
|
||||||
} else if (item.isDirectory()) {
|
} else if (item.isDirectory()) {
|
||||||
loadDirectory(item.getFile());
|
loadDirectory(item.getFile());
|
||||||
} else if (item.getFile().isFile()) {
|
} else if (item.getFile().isFile()) {
|
||||||
@ -4437,4 +4370,139 @@ public class FilePanelTab extends JPanel {
|
|||||||
return null;
|
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