Use new ConflictDialog in RenameAction
This commit is contained in:
parent
049d84fa6b
commit
ad4befb36b
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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>> {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue