diff --git a/source/net/sourceforge/filebot/ui/panel/rename/History.java b/source/net/sourceforge/filebot/ui/panel/rename/History.java index 467b12b7..fa2a9ea5 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/History.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/History.java @@ -11,7 +11,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Map.Entry; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -93,8 +92,15 @@ class History { private String to; - private Element() { - // hide constructor + public Element() { + // used by JAXB + } + + + public Element(String from, String to, File dir) { + this.from = from; + this.to = to; + this.dir = dir; } @@ -136,29 +142,10 @@ class History { } - public void add(Iterable> elements) { + public void add(Collection elements) { Sequence sequence = new Sequence(); - sequence.date = new Date(); - sequence.elements = new ArrayList(); - - for (Entry entry : elements) { - File from = entry.getKey(); - File to = entry.getValue(); - - // sanity check, parent folder must be the same for both files - if (!from.getParentFile().equals(to.getParentFile())) { - throw new IllegalArgumentException(String.format("Illegal entry: ", entry)); - } - - Element element = new Element(); - - element.dir = from.getParentFile(); - element.from = from.getName(); - element.to = to.getName(); - - sequence.elements.add(element); - } + sequence.elements = new ArrayList(elements); add(sequence); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/HistorySpooler.java b/source/net/sourceforge/filebot/ui/panel/rename/HistorySpooler.java index 4ec4af01..f08c89e0 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/HistorySpooler.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/HistorySpooler.java @@ -6,10 +6,14 @@ import static net.sourceforge.filebot.ui.panel.rename.History.*; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; +import net.sourceforge.filebot.ui.panel.rename.History.Element; + final class HistorySpooler { @@ -45,9 +49,15 @@ final class HistorySpooler { } - public synchronized void append(Iterable> elements) { + public synchronized void append(Iterable> elements) { + List sequence = new ArrayList(); + + for (Entry element : elements) { + sequence.add(new Element(element.getKey().getName(), element.getValue(), element.getKey().getParentFile())); + } + // append to session history - sessionHistory.add(elements); + sessionHistory.add(sequence); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/RenameAction.java b/source/net/sourceforge/filebot/ui/panel/rename/RenameAction.java index 8cfd0239..d95cd4f8 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/RenameAction.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/RenameAction.java @@ -26,7 +26,7 @@ class RenameAction extends AbstractAction { private final RenameModel model; - + public RenameAction(RenameModel model) { this.model = model; @@ -37,13 +37,12 @@ class RenameAction extends AbstractAction { public void actionPerformed(ActionEvent evt) { - List> renameLog = new ArrayList>(); + List> renameLog = new ArrayList>(); try { - for (Entry mapping : validate(model.getRenameMap(), getWindow(evt.getSource()))) { - // rename file - if (!mapping.getKey().renameTo(mapping.getValue())) - throw new IOException(String.format("Failed to rename file: \"%s\".", mapping.getKey().getName())); + for (Entry mapping : validate(model.getRenameMap(), getWindow(evt.getSource()))) { + // rename file, throw exception on failure + rename(mapping.getKey(), mapping.getValue()); // remember successfully renamed matches for history entry and possible revert renameLog.add(mapping); @@ -58,21 +57,27 @@ class RenameAction extends AbstractAction { Logger.getLogger("ui").warning(e.getMessage()); // revert rename operations in reverse order - for (ListIterator> iterator = renameLog.listIterator(renameLog.size()); iterator.hasPrevious();) { - Entry mapping = iterator.previous(); + for (ListIterator> iterator = renameLog.listIterator(renameLog.size()); iterator.hasPrevious();) { + Entry mapping = iterator.previous(); - if (mapping.getValue().renameTo(mapping.getKey())) { + try { + File source = mapping.getKey(); + File destination = new File(source.getParentFile(), mapping.getValue()); + + // revert rename + rename(destination, source.getName()); + // remove reverted rename operation from log iterator.remove(); - } else { + } catch (IOException ioe) { // failed to revert rename operation - Logger.getLogger("ui").severe(String.format("Failed to revert file: \"%s\".", mapping.getValue().getName())); + Logger.getLogger("ui").severe(String.format("Failed to revert file: \"%s\".", mapping.getValue())); } } } // remove renamed matches - for (Entry entry : renameLog) { + for (Entry entry : renameLog) { // find index of source file int index = model.files().indexOf(entry.getKey()); @@ -87,26 +92,40 @@ class RenameAction extends AbstractAction { } - private Iterable> validate(Map renameMap, Window parent) { - final List> source = new ArrayList>(renameMap.entrySet()); + private File rename(File file, String name) throws IOException { + // same folder, different name + File destination = new File(file.getParentFile(), name); + File destinationFolder = destination.getParentFile(); + + // create parent folder if necessary + if (!destinationFolder.isDirectory()) { + if (!destinationFolder.mkdirs()) { + throw new IOException("Failed to create folder: " + destinationFolder); + } + } + + if (!file.renameTo(destination)) { + throw new IOException("Failed to rename file: " + file.getName()); + } + + return destination; + } + + + private Iterable> validate(Map renameMap, Window parent) { + final List> source = new ArrayList>(renameMap.entrySet()); List destinationFileNameView = new AbstractList() { @Override public String get(int index) { - return source.get(index).getValue().getName(); + return source.get(index).getValue(); } @Override public String set(int index, String name) { - Entry entry = source.get(index); - File old = entry.getValue(); - - // update name - entry.setValue(new File(old.getParent(), name)); - - return old.getName(); + return source.get(index).setValue(name); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/RenameModel.java b/source/net/sourceforge/filebot/ui/panel/rename/RenameModel.java index f3d67712..c8c79bba 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/RenameModel.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/RenameModel.java @@ -78,8 +78,8 @@ public class RenameModel extends MatchModel { } - public Map getRenameMap() { - Map map = new LinkedHashMap(); + public Map getRenameMap() { + Map map = new LinkedHashMap(); for (int i = 0; i < names.size(); i++) { if (hasComplement(i)) { @@ -108,11 +108,8 @@ public class RenameModel extends MatchModel { } } - // same parent, different name - File newFile = new File(originalFile.getParentFile(), nameBuilder.toString()); - // insert mapping - if (map.put(originalFile, newFile) != null) { + if (map.put(originalFile, nameBuilder.toString()) != null) { throw new IllegalStateException(String.format("Duplicate file entry: \"%s\"", originalFile.getName())); } } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java b/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java index fd1fa548..140c9b2a 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java @@ -91,7 +91,7 @@ public class RenamePanel extends JComponent { filesList.getListComponent().setCellRenderer(cellrenderer); EventSelectionModel> selectionModel = new EventSelectionModel>(renameModel.matches()); - selectionModel.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); + selectionModel.setSelectionMode(ListSelection.SINGLE_SELECTION); // use the same selection model for both lists to synchronize selection namesList.getListComponent().setSelectionModel(selectionModel);