* better handling of move/rename operations (display validation dialog, create folders if necessary, working revert)

This commit is contained in:
Reinhard Pointner 2009-07-20 11:03:24 +00:00
parent 472ed8aac0
commit 46764f7d63
5 changed files with 68 additions and 55 deletions

View File

@ -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<Entry<File, File>> elements) {
public void add(Collection<Element> elements) {
Sequence sequence = new Sequence();
sequence.date = new Date();
sequence.elements = new ArrayList<Element>();
for (Entry<File, File> 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<Element>(elements);
add(sequence);
}

View File

@ -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<Entry<File, File>> elements) {
public synchronized void append(Iterable<Entry<File, String>> elements) {
List<Element> sequence = new ArrayList<Element>();
for (Entry<File, String> element : elements) {
sequence.add(new Element(element.getKey().getName(), element.getValue(), element.getKey().getParentFile()));
}
// append to session history
sessionHistory.add(elements);
sessionHistory.add(sequence);
}

View File

@ -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<Entry<File, File>> renameLog = new ArrayList<Entry<File, File>>();
List<Entry<File, String>> renameLog = new ArrayList<Entry<File, String>>();
try {
for (Entry<File, File> 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<File, String> 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<Entry<File, File>> iterator = renameLog.listIterator(renameLog.size()); iterator.hasPrevious();) {
Entry<File, File> mapping = iterator.previous();
for (ListIterator<Entry<File, String>> iterator = renameLog.listIterator(renameLog.size()); iterator.hasPrevious();) {
Entry<File, String> 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<File, File> entry : renameLog) {
for (Entry<File, ?> entry : renameLog) {
// find index of source file
int index = model.files().indexOf(entry.getKey());
@ -87,26 +92,40 @@ class RenameAction extends AbstractAction {
}
private Iterable<Entry<File, File>> validate(Map<File, File> renameMap, Window parent) {
final List<Entry<File, File>> source = new ArrayList<Entry<File, File>>(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<Entry<File, String>> validate(Map<File, String> renameMap, Window parent) {
final List<Entry<File, String>> source = new ArrayList<Entry<File, String>>(renameMap.entrySet());
List<String> destinationFileNameView = new AbstractList<String>() {
@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<File, File> 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);
}

View File

@ -78,8 +78,8 @@ public class RenameModel extends MatchModel<Object, File> {
}
public Map<File, File> getRenameMap() {
Map<File, File> map = new LinkedHashMap<File, File>();
public Map<File, String> getRenameMap() {
Map<File, String> map = new LinkedHashMap<File, String>();
for (int i = 0; i < names.size(); i++) {
if (hasComplement(i)) {
@ -108,11 +108,8 @@ public class RenameModel extends MatchModel<Object, File> {
}
}
// 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()));
}
}

View File

@ -91,7 +91,7 @@ public class RenamePanel extends JComponent {
filesList.getListComponent().setCellRenderer(cellrenderer);
EventSelectionModel<Match<Object, File>> selectionModel = new EventSelectionModel<Match<Object, File>>(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);