From a731023ed01d816013d60b9224d6fc78b259ca23 Mon Sep 17 00:00:00 2001 From: rdavidek Date: Wed, 21 Jan 2026 21:12:20 +0100 Subject: [PATCH] fixed follow link, selection improved --- .../kfmanager/service/FileOperationQueue.java | 5 + .../kfmanager/service/FileOperations.java | 283 +++++++++++++----- .../java/cz/kamma/kfmanager/ui/FilePanel.java | 12 + .../cz/kamma/kfmanager/ui/FilePanelTab.java | 26 ++ .../cz/kamma/kfmanager/ui/MainWindow.java | 73 ++++- 5 files changed, 317 insertions(+), 82 deletions(-) diff --git a/src/main/java/cz/kamma/kfmanager/service/FileOperationQueue.java b/src/main/java/cz/kamma/kfmanager/service/FileOperationQueue.java index 4da8aae..d349dbc 100644 --- a/src/main/java/cz/kamma/kfmanager/service/FileOperationQueue.java +++ b/src/main/java/cz/kamma/kfmanager/service/FileOperationQueue.java @@ -147,6 +147,11 @@ public class FileOperationQueue { return FileOperations.OverwriteResponse.YES; } + @Override + public FileOperations.SymlinkResponse confirmSymlink(File symlink) { + return FileOperations.SymlinkResponse.IGNORE; + } + @Override public FileOperations.ErrorResponse onError(File file, Exception e) { // For background queue, maybe skip on error? diff --git a/src/main/java/cz/kamma/kfmanager/service/FileOperations.java b/src/main/java/cz/kamma/kfmanager/service/FileOperations.java index c90278c..30a8dc9 100644 --- a/src/main/java/cz/kamma/kfmanager/service/FileOperations.java +++ b/src/main/java/cz/kamma/kfmanager/service/FileOperations.java @@ -6,7 +6,9 @@ import java.io.*; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.regex.Pattern; import java.util.zip.*; @@ -24,9 +26,19 @@ public class FileOperations { } List cleanedItems = cleanDuplicateItems(items); + // Sort items so symlinks are last + cleanedItems.sort((a, b) -> { + boolean aSym = Files.isSymbolicLink(a.getFile().toPath()); + boolean bSym = Files.isSymbolicLink(b.getFile().toPath()); + if (aSym && !bSym) return 1; + if (!aSym && bSym) return -1; + return 0; + }); + long totalItems = calculateTotalItems(cleanedItems); final long[] currentItem = {0}; final OverwriteResponse[] globalResponse = {null}; + final SymlinkResponse[] globalSymlinkResponse = {null}; for (FileItem item : cleanedItems) { if (callback != null && callback.isCancelled()) break; @@ -64,15 +76,48 @@ public class FileOperations { while (true) { try { - if (Files.isSymbolicLink(source.toPath())) { - copySymlink(source.toPath(), target.toPath(), totalItems, currentItem, callback); + Path sourcePath = source.toPath(); + System.out.println("[DEBUG] Processing item: " + sourcePath + " (isLink: " + Files.isSymbolicLink(sourcePath) + ")"); + if (Files.isSymbolicLink(sourcePath)) { + SymlinkResponse sRes = getSymlinkResponse(source, callback, globalSymlinkResponse); + System.out.println("[DEBUG] Symlink response for " + source.getName() + ": " + sRes); + if (sRes == SymlinkResponse.CANCEL) { + return; + } + if (sRes == SymlinkResponse.IGNORE || sRes == SymlinkResponse.IGNORE_ALL) { + currentItem[0] += countItems(sourcePath); + break; + } + // If FOLLOW, sRes will be FOLLOW or FOLLOW_ALL + if (Files.exists(sourcePath)) { + if (Files.isDirectory(sourcePath)) { + System.out.println("[DEBUG] Following symlink as directory: " + sourcePath); + copyDirectory(sourcePath, target.toPath(), totalItems, currentItem, callback, globalResponse, globalSymlinkResponse, null); + // Count the symlink itself as processed to match countItems prediction + currentItem[0]++; + } else { + System.out.println("[DEBUG] Following symlink as file: " + sourcePath); + copyFileWithProgress(sourcePath, target.toPath(), totalItems, currentItem, callback); + } + } else { + // Link is broken, follow is impossible, copy as link + System.out.println("[DEBUG] Broken link encountered, copying as link: " + sourcePath); + copySymlink(sourcePath, target.toPath(), totalItems, currentItem, callback); + } + break; } else if (source.isDirectory()) { - copyDirectory(source.toPath(), target.toPath(), totalItems, currentItem, callback, globalResponse); + System.out.println("[DEBUG] Copying directory: " + sourcePath); + copyDirectory(sourcePath, target.toPath(), totalItems, currentItem, callback, globalResponse, globalSymlinkResponse, null); + // Directory itself counted in countItems but copyDirectory skips increment for root. + // So we increment here. + currentItem[0]++; } else { - copyFileWithProgress(source.toPath(), target.toPath(), totalItems, currentItem, callback); + System.out.println("[DEBUG] Copying file: " + sourcePath); + copyFileWithProgress(sourcePath, target.toPath(), totalItems, currentItem, callback); } break; } catch (IOException e) { + System.out.println("[DEBUG] Error processing " + source.getName() + ": " + e.getMessage()); if (callback != null) { ErrorResponse res = callback.onError(source, e); if (res == ErrorResponse.ABORT) throw e; @@ -86,6 +131,15 @@ public class FileOperations { } } + private static SymlinkResponse getSymlinkResponse(File source, ProgressCallback callback, SymlinkResponse[] globalSymlinkResponse) { + if (globalSymlinkResponse[0] != null) return globalSymlinkResponse[0]; + if (callback == null) return SymlinkResponse.IGNORE; + SymlinkResponse res = callback.confirmSymlink(source); + if (res == SymlinkResponse.FOLLOW_ALL) globalSymlinkResponse[0] = SymlinkResponse.FOLLOW_ALL; + if (res == SymlinkResponse.IGNORE_ALL) globalSymlinkResponse[0] = SymlinkResponse.IGNORE_ALL; + return res; + } + private static long calculateTotalItems(List items) { long total = 0; for (FileItem item : items) { @@ -154,79 +208,114 @@ public class FileOperations { } } - private static void copyDirectory(Path source, Path target, long totalItems, final long[] currentItem, ProgressCallback callback, final OverwriteResponse[] globalResponse) throws IOException { - Files.walkFileTree(source, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - Path targetDir = target.resolve(source.relativize(dir)); - if (Files.exists(targetDir) && !Files.isDirectory(targetDir)) { - Files.delete(targetDir); - } - while (true) { - try { - Files.createDirectories(targetDir); - if (!dir.equals(source)) { - currentItem[0]++; - if (callback != null) { - callback.onProgress(currentItem[0], totalItems, dir.getFileName().toString()); + private static void copyDirectory(Path source, Path target, long totalItems, final long[] currentItem, ProgressCallback callback, final OverwriteResponse[] globalResponse, final SymlinkResponse[] globalSymlinkResponse, Set visitedPaths) throws IOException { + final Path effectiveSource = Files.isSymbolicLink(source) ? source.toRealPath() : source.toAbsolutePath().normalize(); + final Path finalTarget = target.toAbsolutePath().normalize(); + + if (visitedPaths == null) visitedPaths = new HashSet<>(); + if (!visitedPaths.add(effectiveSource)) { + // Cycle detected, skip this directory + return; + } + + try { + final Set finalVisitedPaths = visitedPaths; + Files.walkFileTree(effectiveSource, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + Path targetDir = finalTarget.resolve(effectiveSource.relativize(dir.toAbsolutePath().normalize())); + if (Files.exists(targetDir, LinkOption.NOFOLLOW_LINKS) && !Files.isDirectory(targetDir, LinkOption.NOFOLLOW_LINKS)) { + Files.delete(targetDir); + } + while (true) { + try { + Files.createDirectories(targetDir); + if (!dir.toAbsolutePath().normalize().equals(effectiveSource)) { + currentItem[0]++; + if (callback != null) { + callback.onProgress(currentItem[0], totalItems, dir.getFileName().toString()); + } } - } - return FileVisitResult.CONTINUE; - } catch (IOException e) { - if (callback != null) { - ErrorResponse res = callback.onError(dir.toFile(), e); - if (res == ErrorResponse.ABORT) return FileVisitResult.TERMINATE; - if (res == ErrorResponse.RETRY) continue; - return FileVisitResult.SKIP_SUBTREE; - } - throw e; - } - } - } - - @Override - 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(file.toFile(), targetFile.toFile()); - if (res == OverwriteResponse.CANCEL) return FileVisitResult.TERMINATE; - if (res == OverwriteResponse.NO_TO_ALL) { - globalResponse[0] = OverwriteResponse.NO_TO_ALL; return FileVisitResult.CONTINUE; + } catch (IOException e) { + if (callback != null) { + ErrorResponse res = callback.onError(dir.toFile(), e); + if (res == ErrorResponse.ABORT) return FileVisitResult.TERMINATE; + if (res == ErrorResponse.RETRY) continue; + return FileVisitResult.SKIP_SUBTREE; + } + throw e; } - if (res == OverwriteResponse.NO) return FileVisitResult.CONTINUE; - if (res == OverwriteResponse.YES_TO_ALL) globalResponse[0] = OverwriteResponse.YES_TO_ALL; - } - // If we are here, we are overwriting. If target is a directory, delete it. - if (Files.isDirectory(targetFile)) { - deleteDirectoryInternal(targetFile); } } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (callback != null && callback.isCancelled()) return FileVisitResult.TERMINATE; + Path targetFile = finalTarget.resolve(effectiveSource.relativize(file.toAbsolutePath().normalize())); + System.out.println("[DEBUG] Recursive visit (file): " + file + " (isLink: " + attrs.isSymbolicLink() + ")"); - while (true) { - try { - if (Files.isSymbolicLink(file)) { - copySymlink(file, targetFile, totalItems, currentItem, callback); + if (Files.exists(targetFile, LinkOption.NOFOLLOW_LINKS)) { + if (globalResponse[0] == OverwriteResponse.NO_TO_ALL) return FileVisitResult.CONTINUE; + if (globalResponse[0] != OverwriteResponse.YES_TO_ALL) { + OverwriteResponse res = callback.confirmOverwrite(file.toFile(), 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; + } + // Handle directory vs file clash + if (Files.isDirectory(targetFile, LinkOption.NOFOLLOW_LINKS)) { + deleteDirectoryInternal(targetFile); } else { - copyFileWithProgress(file, targetFile, totalItems, currentItem, callback); + Files.delete(targetFile); } - return FileVisitResult.CONTINUE; - } catch (IOException e) { - if (callback != null) { - ErrorResponse res = callback.onError(file.toFile(), e); - if (res == ErrorResponse.ABORT) return FileVisitResult.TERMINATE; - if (res == ErrorResponse.RETRY) continue; + } + + while (true) { + try { + if (attrs.isSymbolicLink()) { + SymlinkResponse sRes = getSymlinkResponse(file.toFile(), callback, globalSymlinkResponse); + if (sRes == SymlinkResponse.CANCEL) return FileVisitResult.TERMINATE; + if (sRes == SymlinkResponse.IGNORE || sRes == SymlinkResponse.IGNORE_ALL) { + currentItem[0]++; + return FileVisitResult.CONTINUE; + } + // FOLLOW or FOLLOW_ALL + if (Files.exists(file)) { + if (Files.isDirectory(file)) { + copyDirectory(file, targetFile, totalItems, currentItem, callback, globalResponse, globalSymlinkResponse, finalVisitedPaths); + // Count the symlink itself as processed to match countItems prediction + currentItem[0]++; + } else { + copyFileWithProgress(file, targetFile, totalItems, currentItem, callback); + } + } else { + // Link is broken, follow is impossible, copy as link + copySymlink(file, targetFile, totalItems, currentItem, callback); + } + } else { + copyFileWithProgress(file, targetFile, totalItems, currentItem, callback); + } return FileVisitResult.CONTINUE; + } catch (IOException e) { + if (callback != null) { + ErrorResponse res = callback.onError(file.toFile(), e); + if (res == ErrorResponse.ABORT) return FileVisitResult.TERMINATE; + if (res == ErrorResponse.RETRY) continue; + return FileVisitResult.CONTINUE; + } + throw e; } - throw e; } } - } - }); + }); + } finally { + visitedPaths.remove(effectiveSource); + } } private static void deleteDirectoryInternal(Path path) throws IOException { @@ -257,9 +346,19 @@ public class FileOperations { } List cleanedItems = cleanDuplicateItems(items); + // Sort items so symlinks are last + cleanedItems.sort((a, b) -> { + boolean aSym = Files.isSymbolicLink(a.getFile().toPath()); + boolean bSym = Files.isSymbolicLink(b.getFile().toPath()); + if (aSym && !bSym) return 1; + if (!aSym && bSym) return -1; + return 0; + }); + long totalItems = calculateTotalItems(cleanedItems); long[] currentItem = {0}; final OverwriteResponse[] globalResponse = {null}; + final SymlinkResponse[] globalSymlinkResponse = {null}; for (FileItem item : cleanedItems) { if (callback != null && callback.isCancelled()) break; @@ -295,7 +394,32 @@ public class FileOperations { long itemCount = countItems(source.toPath()); while (true) { try { - Files.move(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); + Path sourcePath = source.toPath(); + if (Files.isSymbolicLink(sourcePath)) { + SymlinkResponse sRes = getSymlinkResponse(source, callback, globalSymlinkResponse); + if (sRes == SymlinkResponse.CANCEL) return; + if (sRes == SymlinkResponse.IGNORE || sRes == SymlinkResponse.IGNORE_ALL) { + currentItem[0] += itemCount; + break; + } + if (sRes == SymlinkResponse.FOLLOW || sRes == SymlinkResponse.FOLLOW_ALL) { + if (Files.exists(sourcePath)) { + if (Files.isDirectory(sourcePath)) { + copyDirectory(sourcePath, target.toPath(), totalItems, currentItem, callback, globalResponse, globalSymlinkResponse, null); + currentItem[0]++; + } else { + copyFileWithProgress(sourcePath, target.toPath(), totalItems, currentItem, callback); + } + } else { + // Link is broken, follow is impossible, copy as link + copySymlink(sourcePath, target.toPath(), totalItems, currentItem, callback); + } + Files.delete(sourcePath); + break; + } + } + + Files.move(sourcePath, target.toPath(), StandardCopyOption.REPLACE_EXISTING); currentItem[0] += itemCount; if (callback != null) { callback.onProgress(currentItem[0], totalItems, source.getName()); @@ -305,7 +429,7 @@ public class FileOperations { // Fallback for cross-device moves (e.g., to network/Samba mounts) try { if (source.isDirectory()) { - copyDirectory(source.toPath(), target.toPath(), totalItems, currentItem, callback, globalResponse); + copyDirectory(source.toPath(), target.toPath(), totalItems, currentItem, callback, globalResponse, globalSymlinkResponse, null); currentItem[0]++; // For the directory itself which copyDirectory skips deleteDirectoryInternal(source.toPath()); } else { @@ -398,19 +522,15 @@ public class FileOperations { private static boolean isSubfolder(File parent, File child) { if (parent == null || child == null) return false; - try { - String parentPath = parent.getCanonicalPath(); - String childPath = child.getCanonicalPath(); - - if (parentPath.equals(childPath)) return true; - - if (!parentPath.endsWith(File.separator)) { - parentPath += File.separator; - } - return childPath.startsWith(parentPath); - } catch (IOException e) { - return child.getAbsolutePath().startsWith(parent.getAbsolutePath()); + String parentPath = parent.getAbsolutePath(); + String childPath = child.getAbsolutePath(); + + if (parentPath.equals(childPath)) return true; + + if (!parentPath.endsWith(File.separator)) { + parentPath += File.separator; } + return childPath.startsWith(parentPath); } /** @@ -911,6 +1031,10 @@ public class FileOperations { YES, NO, YES_TO_ALL, NO_TO_ALL, CANCEL } + public enum SymlinkResponse { + FOLLOW, IGNORE, FOLLOW_ALL, IGNORE_ALL, CANCEL + } + public enum ErrorResponse { SKIP, RETRY, ABORT } @@ -920,6 +1044,7 @@ public class FileOperations { default void onFileProgress(long current, long total) {} default boolean isCancelled() { return false; } default OverwriteResponse confirmOverwrite(File source, File destination) { return OverwriteResponse.YES; } + default SymlinkResponse confirmSymlink(File symlink) { return SymlinkResponse.IGNORE; } default ErrorResponse onError(File file, Exception e) { return ErrorResponse.ABORT; } } diff --git a/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java b/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java index 96172f2..6d0d875 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java +++ b/src/main/java/cz/kamma/kfmanager/ui/FilePanel.java @@ -42,6 +42,18 @@ public class FilePanel extends JPanel { if (tab != null) tab.selectByWildcard(pattern); } + /** Invert selection in the current tab. */ + public void invertSelection() { + FilePanelTab tab = getCurrentTab(); + if (tab != null) tab.invertSelection(); + } + + /** Unselect all files in the current tab. */ + public void unselectAll() { + FilePanelTab tab = getCurrentTab(); + if (tab != null) tab.unselectAll(); + } + private Runnable switchPanelCallback; public void setSwitchPanelCallback(Runnable cb) { diff --git a/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java b/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java index e6457ac..28d031f 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java +++ b/src/main/java/cz/kamma/kfmanager/ui/FilePanelTab.java @@ -1773,6 +1773,32 @@ public class FilePanelTab extends JPanel { public void selectItem(String name, boolean requestFocus) { selectItemByName(name, requestFocus); } + + public void invertSelection() { + if (tableModel == null || tableModel.items == null) return; + for (FileItem item : tableModel.items) { + if (!item.getName().equals("..")) { + item.setMarked(!item.isMarked()); + } + } + fileTable.repaint(); + updateStatus(); + } + + public void unselectAll() { + if (tableModel == null || tableModel.items == null) return; + boolean changed = false; + for (FileItem item : tableModel.items) { + if (item.isMarked()) { + item.setMarked(false); + changed = true; + } + } + if (changed) { + fileTable.repaint(); + updateStatus(); + } + } public void toggleSelectionAndMoveDown() { int selectedRow = fileTable.getSelectedRow(); diff --git a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java index d31a9e6..c390842 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java +++ b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java @@ -809,8 +809,14 @@ public class MainWindow extends JFrame { searchItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F7, InputEvent.ALT_DOWN_MASK)); searchItem.addActionListener(e -> showSearchDialog()); + JMenuItem selectAllItem = new JMenuItem("Invert Selection"); + selectAllItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK)); + selectAllItem.addActionListener(e -> { + if (activePanel != null) activePanel.invertSelection(); + }); + JMenuItem selectWildcardItem = new JMenuItem("Select by wildcard..."); - selectWildcardItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK)); + selectWildcardItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0)); selectWildcardItem.addActionListener(e -> showWildcardSelectDialog()); JMenuItem refreshItem = new JMenuItem("Refresh"); @@ -826,6 +832,7 @@ public class MainWindow extends JFrame { exitItem.addActionListener(e -> saveConfigAndExit()); fileMenu.add(searchItem); + fileMenu.add(selectAllItem); fileMenu.add(selectWildcardItem); fileMenu.add(refreshItem); fileMenu.add(queueItem); @@ -1355,11 +1362,33 @@ public class MainWindow extends JFrame { } }); - // Wildcard selection (Ctrl+A and +) + // Selection (Ctrl+A for Invert, + for Wildcard) table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) - .put(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK), "wildcardSelect"); + .put(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK), "invertSelection"); + table.getActionMap().put("invertSelection", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (activePanel != null) { + activePanel.invertSelection(); + } + } + }); + + table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "unselectAll"); + table.getActionMap().put("unselectAll", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (activePanel != null) { + activePanel.unselectAll(); + } + } + }); + table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyStroke.getKeyStroke('+'), "wildcardSelect"); + table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "wildcardSelect"); table.getActionMap().put("wildcardSelect", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -2306,6 +2335,44 @@ public class MainWindow extends JFrame { return result[0]; } + @Override + public FileOperations.SymlinkResponse confirmSymlink(File symlink) { + final FileOperations.SymlinkResponse[] result = new FileOperations.SymlinkResponse[1]; + try { + SwingUtilities.invokeAndWait(() -> { + String message = String.format( + "Symbolic link encountered: %s\n\n" + + "What do you want to do?", + symlink.getAbsolutePath() + ); + + Object[] options = {"Follow", "Follow All", "Ignore", "Ignore All", "Cancel"}; + int n = JOptionPane.showOptionDialog(progressDialog, + message, + "Symlink Encountered", + JOptionPane.DEFAULT_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0]); + + switch (n) { + case 0: result[0] = FileOperations.SymlinkResponse.FOLLOW; break; + case 1: result[0] = FileOperations.SymlinkResponse.FOLLOW_ALL; break; + case 2: result[0] = FileOperations.SymlinkResponse.IGNORE; break; + case 3: result[0] = FileOperations.SymlinkResponse.IGNORE_ALL; break; + default: + result[0] = FileOperations.SymlinkResponse.CANCEL; + progressDialog.cancel(); + break; + } + }); + } catch (Exception e) { + result[0] = FileOperations.SymlinkResponse.CANCEL; + } + return result[0]; + } + @Override public FileOperations.ErrorResponse onError(File file, Exception e) { final FileOperations.ErrorResponse[] result = new FileOperations.ErrorResponse[1];