Use new ConflictDialog in RenameAction

This commit is contained in:
Reinhard Pointner 2016-08-17 03:37:30 +08:00
parent 049d84fa6b
commit ad4befb36b
3 changed files with 80 additions and 161 deletions

View File

@ -15,7 +15,6 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -30,81 +29,15 @@ import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import net.filebot.ResourceManager;
import net.filebot.StandardRenameAction;
import net.filebot.UserFiles;
import net.miginfocom.swing.MigLayout;
class ConflictDialog extends JDialog {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
File s = new File(args[0]);
File d = new File(args[1]);
Map<File, File> map = new HashMap<>();
map.put(s, d);
Map<File, File> check = ConflictDialog.check(null, map);
System.out.println(check);
System.exit(0);
});
}
public static Map<File, File> check(Component parent, Map<File, File> renameMap) {
List<Conflict> conflicts = new ArrayList<Conflict>();
// sanity checks
Set<File> destFiles = new HashSet<File>();
renameMap.forEach((from, to) -> {
List<Object> issues = new ArrayList<Object>();
// resolve relative paths
to = resolve(from, to);
// output files must have a valid file extension
if (getExtension(to) == null && to.isFile()) {
issues.add("Missing extension");
}
// one file per unique output path
if (!destFiles.add(to)) {
issues.add("Duplicate destination path");
}
// check if destination path already exists
if (to.exists() && !to.equals(from)) {
issues.add("File already exists");
}
if (issues.size() > 0) {
conflicts.add(new Conflict(from, to, issues));
}
});
if (conflicts.isEmpty()) {
return renameMap;
}
ConflictDialog dialog = new ConflictDialog(getWindow(parent), conflicts);
dialog.setVisible(true);
if (dialog.cancel()) {
return emptyMap();
}
// exclude conflicts from rename map
for (Conflict it : dialog.getConflicts()) {
renameMap.remove(it.source);
}
return renameMap;
}
private ConflictTableModel model = new ConflictTableModel();
private boolean cancel = true;
@ -168,7 +101,7 @@ class ConflictDialog extends JDialog {
if (c.destination.exists()) {
try {
StandardRenameAction.trash(c.destination);
UserFiles.trash(c.destination);
} catch (Exception e) {
return new Conflict(c.source, c.destination, singletonList(e.getMessage()));
}
@ -316,4 +249,55 @@ class ConflictDialog extends JDialog {
}
}
public static boolean check(Component parent, Map<File, File> renameMap) {
List<Conflict> conflicts = new ArrayList<Conflict>();
// sanity checks
Set<File> destFiles = new HashSet<File>();
renameMap.forEach((from, to) -> {
List<Object> issues = new ArrayList<Object>();
// resolve relative paths
to = resolve(from, to);
// output files must have a valid file extension
if (getExtension(to) == null && to.isFile()) {
issues.add("Missing extension");
}
// one file per unique output path
if (!destFiles.add(to)) {
issues.add("Duplicate destination path");
}
// check if destination path already exists
if (to.exists() && !to.equals(from)) {
issues.add("File already exists");
}
if (issues.size() > 0) {
conflicts.add(new Conflict(from, to, issues));
}
});
if (conflicts.isEmpty()) {
return true;
}
ConflictDialog dialog = new ConflictDialog(getWindow(parent), conflicts);
dialog.setLocation(getOffsetLocation(dialog.getOwner()));
dialog.setVisible(true);
if (dialog.cancel()) {
return false;
}
// exclude conflicts from rename map
for (Conflict it : dialog.getConflicts()) {
renameMap.remove(it.source);
}
return true;
}
}

View File

@ -3,7 +3,6 @@ package net.filebot.ui.rename;
import static java.util.Arrays.*;
import static java.util.Collections.*;
import static java.util.stream.Collectors.*;
import static javax.swing.JOptionPane.*;
import static net.filebot.Logging.*;
import static net.filebot.Settings.*;
import static net.filebot.media.MediaDetection.*;
@ -12,16 +11,11 @@ import static net.filebot.util.ExceptionUtilities.*;
import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.ui.SwingUI.*;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.AbstractList;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -36,14 +30,12 @@ import java.util.logging.Level;
import java.util.stream.Stream;
import javax.swing.AbstractAction;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import net.filebot.HistorySpooler;
import net.filebot.NativeRenameAction;
import net.filebot.ResourceManager;
import net.filebot.StandardRenameAction;
import net.filebot.UserFiles;
import net.filebot.mac.MacAppUtilities;
import net.filebot.similarity.Match;
import net.filebot.util.ui.ProgressMonitor;
@ -76,7 +68,8 @@ class RenameAction extends AbstractAction {
try {
Window window = getWindow(evt.getSource());
withWaitCursor(window, () -> {
Map<File, File> renameMap = checkRenamePlan(validate(model.getRenameMap(), window), window);
Map<File, File> renameMap = validate(model.getRenameMap(), window);
if (renameMap.isEmpty()) {
return;
}
@ -183,7 +176,7 @@ class RenameAction extends AbstractAction {
try {
for (File file : deleteFiles) {
if (file.exists()) {
StandardRenameAction.trash(file);
UserFiles.trash(file);
}
}
} catch (Throwable e) {
@ -191,101 +184,43 @@ class RenameAction extends AbstractAction {
}
}
private Map<File, File> checkRenamePlan(List<Entry<File, File>> renamePlan, Window parent) throws IOException {
// ask for user permissions to output paths
if (isMacSandbox()) {
if (!MacAppUtilities.askUnlockFolders(parent, renamePlan.stream().flatMap(e -> Stream.of(e.getKey(), resolve(e.getKey(), e.getValue()))).map(f -> new File(f.getAbsolutePath())).collect(toList()))) {
return emptyMap();
}
}
private Map<File, File> validate(Map<File, File> renameMap, Window parent) {
// rename map values as modifiable list
List<File> destinationPathView = new AbstractList<File>() {
// build rename map and perform some sanity checks
Map<File, File> renameMap = new HashMap<File, File>();
Set<File> destinationFiles = new HashSet<File>();
List<String> issues = new ArrayList<String>();
for (Entry<File, File> mapping : renamePlan) {
File source = mapping.getKey();
File destination = resolve(source, mapping.getValue());
try {
if (renameMap.containsKey(source))
throw new IllegalArgumentException("Duplicate input path: " + source.getPath());
if (destinationFiles.contains(destination))
throw new IllegalArgumentException("Duplicate output path: " + mapping.getValue());
if (destination.exists() && !resolve(mapping.getKey(), mapping.getValue()).equals(mapping.getKey()))
throw new IllegalArgumentException("File already exists: " + mapping.getValue().getPath());
if (getExtension(destination) == null && destination.isFile())
throw new IllegalArgumentException("Missing extension: " + mapping.getValue().getPath());
// use original mapping values
renameMap.put(mapping.getKey(), mapping.getValue());
destinationFiles.add(destination);
} catch (Exception e) {
issues.add(e.getMessage());
}
}
if (issues.size() > 0) {
String text = "These files will be ignored. Do you want to continue?";
JList issuesComponent = new JList(issues.toArray()) {
@Override
public Dimension getPreferredScrollableViewportSize() {
// adjust component size
return new Dimension(80, 80);
}
};
Object[] message = new Object[] { text, new JScrollPane(issuesComponent) };
String[] actions = new String[] { "Continue", "Cancel" };
JOptionPane pane = new JOptionPane(message, PLAIN_MESSAGE, YES_NO_OPTION, null, actions, actions[1]);
// display option dialog
pane.createDialog(getWindow(parent), "Conflicting Files").setVisible(true);
if (pane.getValue() != actions[0]) {
return emptyMap();
}
}
return renameMap;
}
private List<Entry<File, File>> validate(Map<File, String> renameMap, Window parent) {
List<Entry<File, File>> source = new ArrayList<Entry<File, File>>(renameMap.size());
for (Entry<File, String> entry : renameMap.entrySet()) {
source.add(new SimpleEntry<File, File>(entry.getKey(), new File(entry.getValue())));
}
List<File> destinationFileNameView = new AbstractList<File>() {
private File[] keyIndex = renameMap.keySet().toArray(new File[0]);
@Override
public File get(int index) {
return source.get(index).getValue();
public File get(int i) {
return renameMap.get(keyIndex[i]);
}
@Override
public File set(int index, File name) {
return source.get(index).setValue(name);
public File set(int i, File value) {
return renameMap.put(keyIndex[i], value);
}
@Override
public int size() {
return source.size();
return keyIndex.length;
}
};
if (ValidateDialog.validate(parent, destinationFileNameView)) {
// names have been validated via view
return source;
if (ValidateDialog.validate(parent, destinationPathView)) {
// ask for user permissions for output folders so we can check them
if (isMacSandbox()) {
if (!MacAppUtilities.askUnlockFolders(parent, renameMap.entrySet().stream().flatMap(e -> Stream.of(e.getKey(), resolve(e.getKey(), e.getValue()))).collect(toList()))) {
return emptyMap();
}
}
if (ConflictDialog.check(parent, renameMap)) {
return renameMap;
}
}
// return empty list if validation was cancelled
return emptyList();
return emptyMap();
}
protected static class StandardRenameWorker implements ProgressWorker<Map<File, File>> {

View File

@ -73,8 +73,8 @@ public class RenameModel extends MatchModel<Object, File> {
this.preserveExtension = preserveExtension;
}
public Map<File, String> getRenameMap() {
Map<File, String> map = new LinkedHashMap<File, String>();
public Map<File, File> getRenameMap() {
Map<File, File> map = new LinkedHashMap<File, File>();
for (int i = 0; i < names.size(); i++) {
if (hasComplement(i)) {
@ -104,7 +104,7 @@ public class RenameModel extends MatchModel<Object, File> {
}
// insert mapping
if (map.put(source, destination.toString()) != null) {
if (map.put(source, new File(destination.toString())) != null) {
throw new IllegalStateException("Duplicate source file: " + source.getName());
}
}