confirmations

This commit is contained in:
rdavidek 2026-01-18 10:57:16 +01:00
parent b28b090fa9
commit b05a6fa3b7
6 changed files with 135 additions and 25 deletions

View File

@ -25,6 +25,7 @@ public class FileOperations {
long totalSize = calculateTotalSize(items);
final long[] currentCopied = {0};
final OverwriteResponse[] globalResponse = {null};
for (FileItem item : items) {
if (callback != null && callback.isCancelled()) break;
@ -34,10 +35,22 @@ public class FileOperations {
// If target is the same as source (copying to the same directory), rename target
if (source.getAbsolutePath().equals(target.getAbsolutePath())) {
target = new File(targetDirectory, "copy-of-" + source.getName());
} else if (target.exists()) {
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) continue;
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
OverwriteResponse res = callback.confirmOverwrite(target);
if (res == OverwriteResponse.CANCEL) break;
if (res == OverwriteResponse.NO_TO_ALL) {
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
continue;
}
if (res == OverwriteResponse.NO) continue;
if (res == OverwriteResponse.YES_TO_ALL) globalResponse[0] = OverwriteResponse.YES_TO_ALL;
}
}
if (source.isDirectory()) {
copyDirectory(source.toPath(), target.toPath(), totalSize, currentCopied, callback);
copyDirectory(source.toPath(), target.toPath(), totalSize, currentCopied, callback, globalResponse);
} else {
copyFileWithProgress(source.toPath(), target.toPath(), totalSize, currentCopied, callback);
}
@ -87,7 +100,7 @@ public class FileOperations {
Files.setLastModifiedTime(target, Files.getLastModifiedTime(source));
}
private static void copyDirectory(Path source, Path target, long totalSize, final long[] totalCopied, ProgressCallback callback) throws IOException {
private static void copyDirectory(Path source, Path target, long totalSize, final long[] totalCopied, ProgressCallback callback, final OverwriteResponse[] globalResponse) throws IOException {
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
@ -100,6 +113,21 @@ public class FileOperations {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (callback != null && callback.isCancelled()) return FileVisitResult.TERMINATE;
Path targetFile = target.resolve(source.relativize(file));
if (Files.exists(targetFile)) {
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) return FileVisitResult.CONTINUE;
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
OverwriteResponse res = callback.confirmOverwrite(targetFile.toFile());
if (res == OverwriteResponse.CANCEL) return FileVisitResult.TERMINATE;
if (res == OverwriteResponse.NO_TO_ALL) {
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
return FileVisitResult.CONTINUE;
}
if (res == OverwriteResponse.NO) return FileVisitResult.CONTINUE;
if (res == OverwriteResponse.YES_TO_ALL) globalResponse[0] = OverwriteResponse.YES_TO_ALL;
}
}
copyFileWithProgress(file, targetFile, totalSize, totalCopied, callback);
return FileVisitResult.CONTINUE;
}
@ -116,6 +144,7 @@ public class FileOperations {
int current = 0;
int total = items.size();
final OverwriteResponse[] globalResponse = {null};
for (FileItem item : items) {
if (callback != null && callback.isCancelled()) break;
@ -123,6 +152,20 @@ public class FileOperations {
File source = item.getFile();
File target = new File(targetDirectory, source.getName());
if (target.exists() && !source.getAbsolutePath().equals(target.getAbsolutePath())) {
if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) continue;
if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) {
OverwriteResponse res = callback.confirmOverwrite(target);
if (res == OverwriteResponse.CANCEL) break;
if (res == OverwriteResponse.NO_TO_ALL) {
globalResponse[0] = OverwriteResponse.NO_TO_ALL;
continue;
}
if (res == OverwriteResponse.NO) continue;
if (res == OverwriteResponse.YES_TO_ALL) globalResponse[0] = OverwriteResponse.YES_TO_ALL;
}
}
if (callback != null) {
callback.onProgress(current, total, source.getName());
}
@ -374,9 +417,14 @@ public class FileOperations {
/**
* Callback for operation progress
*/
public enum OverwriteResponse {
YES, NO, YES_TO_ALL, NO_TO_ALL, CANCEL
}
public interface ProgressCallback {
void onProgress(long current, long total, String currentFile);
default boolean isCancelled() { return false; }
default OverwriteResponse confirmOverwrite(File file) { return OverwriteResponse.YES; }
}
/**

View File

@ -1566,33 +1566,59 @@ public class FilePanelTab extends JPanel {
File targetDir = getCurrentDirectory();
Window parentWindow = SwingUtilities.getWindowAncestor(this);
String operationName = action == ClipboardService.ClipboardAction.CUT ? "Moving" : "Copying";
ProgressDialog progressDialog = new ProgressDialog(parentWindow instanceof Frame ? (Frame)parentWindow : null, operationName);
String titleName = action == ClipboardService.ClipboardAction.CUT ? "Moving" : "Copying";
ProgressDialog progressDialog = new ProgressDialog(parentWindow instanceof Frame ? (Frame)parentWindow : null, titleName);
new Thread(() -> {
try {
FileOperations.ProgressCallback callback = new FileOperations.ProgressCallback() {
@Override
public void onProgress(long current, long total, String currentFile) {
progressDialog.updateProgress(current, total, currentFile);
}
@Override
public boolean isCancelled() {
return progressDialog.isCancelled();
}
@Override
public FileOperations.OverwriteResponse confirmOverwrite(File file) {
final FileOperations.OverwriteResponse[] result = new FileOperations.OverwriteResponse[1];
try {
SwingUtilities.invokeAndWait(() -> {
Object[] options = {"Yes", "Yes to All", "No", "No to All", "Cancel"};
int n = JOptionPane.showOptionDialog(progressDialog,
"File already exists: " + file.getName() + "\nOverwrite?",
"Overwrite Confirmation",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
switch (n) {
case 0: result[0] = FileOperations.OverwriteResponse.YES; break;
case 1: result[0] = FileOperations.OverwriteResponse.YES_TO_ALL; break;
case 2: result[0] = FileOperations.OverwriteResponse.NO; break;
case 3: result[0] = FileOperations.OverwriteResponse.NO_TO_ALL; break;
default:
result[0] = FileOperations.OverwriteResponse.CANCEL;
progressDialog.cancel();
break;
}
});
} catch (Exception e) {
result[0] = FileOperations.OverwriteResponse.CANCEL;
}
return result[0];
}
};
if (action == ClipboardService.ClipboardAction.CUT) {
FileOperations.move(itemsToPaste, targetDir, new FileOperations.ProgressCallback() {
@Override
public void onProgress(long current, long total, String currentFile) {
progressDialog.updateProgress(current, total, currentFile);
}
@Override
public boolean isCancelled() {
return progressDialog.isCancelled();
}
});
FileOperations.move(itemsToPaste, targetDir, callback);
} else {
FileOperations.copy(itemsToPaste, targetDir, new FileOperations.ProgressCallback() {
@Override
public void onProgress(long current, long total, String currentFile) {
progressDialog.updateProgress(current, total, currentFile);
}
@Override
public boolean isCancelled() {
return progressDialog.isCancelled();
}
});
FileOperations.copy(itemsToPaste, targetDir, callback);
}
SwingUtilities.invokeLater(() -> {
progressDialog.dispose();

View File

@ -1781,6 +1781,38 @@ public class MainWindow extends JFrame {
public boolean isCancelled() {
return progressDialog.isCancelled();
}
@Override
public FileOperations.OverwriteResponse confirmOverwrite(File file) {
final FileOperations.OverwriteResponse[] result = new FileOperations.OverwriteResponse[1];
try {
SwingUtilities.invokeAndWait(() -> {
Object[] options = {"Yes", "Yes to All", "No", "No to All", "Cancel"};
int n = JOptionPane.showOptionDialog(progressDialog,
"File already exists: " + file.getName() + "\nOverwrite?",
"Overwrite Confirmation",
JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
switch (n) {
case 0: result[0] = FileOperations.OverwriteResponse.YES; break;
case 1: result[0] = FileOperations.OverwriteResponse.YES_TO_ALL; break;
case 2: result[0] = FileOperations.OverwriteResponse.NO; break;
case 3: result[0] = FileOperations.OverwriteResponse.NO_TO_ALL; break;
default:
result[0] = FileOperations.OverwriteResponse.CANCEL;
progressDialog.cancel();
break;
}
});
} catch (Exception e) {
result[0] = FileOperations.OverwriteResponse.CANCEL;
}
return result[0];
}
};
// Run operation in a background thread

View File

@ -75,6 +75,10 @@ public class ProgressDialog extends JDialog {
setLocationRelativeTo(owner);
}
public void cancel() {
cancelled = true;
}
private boolean displayAsBytes = false;
public void setDisplayAsBytes(boolean displayAsBytes) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB