+ validate names before renaming

This commit is contained in:
Reinhard Pointner 2009-05-17 20:58:20 +00:00
parent 0dc12ec505
commit fd0c2412ef
4 changed files with 355 additions and 223 deletions

View File

@ -83,9 +83,13 @@ public class MatchModel<Value, Candidate> {
public boolean hasComplement(int index) { public boolean hasComplement(int index) {
if (index >= 0 && index < size()) {
return source.get(index).getValue() != null && source.get(index).getCandidate() != null; return source.get(index).getValue() != null && source.get(index).getCandidate() != null;
} }
return false;
}
public EventList<Match<Value, Candidate>> matches() { public EventList<Match<Value, Candidate>> matches() {
return source; return source;

View File

@ -2,11 +2,17 @@
package net.sourceforge.filebot.ui.panel.rename; package net.sourceforge.filebot.ui.panel.rename;
import static java.util.Collections.*;
import static net.sourceforge.tuned.ui.TunedUtilities.*;
import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -21,11 +27,11 @@ class RenameAction extends AbstractAction {
public RenameAction(RenameModel model) { public RenameAction(RenameModel model) {
super("Rename", ResourceManager.getIcon("action.rename"));
putValue(SHORT_DESCRIPTION, "Rename files");
this.model = model; this.model = model;
putValue(NAME, "Rename");
putValue(SMALL_ICON, ResourceManager.getIcon("action.rename"));
putValue(SHORT_DESCRIPTION, "Rename files");
} }
@ -33,7 +39,7 @@ class RenameAction extends AbstractAction {
List<Entry<File, File>> renameLog = new ArrayList<Entry<File, File>>(); List<Entry<File, File>> renameLog = new ArrayList<Entry<File, File>>();
try { try {
for (Entry<File, File> mapping : model.getRenameMap().entrySet()) { for (Entry<File, File> mapping : validate(model.getRenameMap(), getWindow(evt.getSource()))) {
// rename file // rename file
//DISABLE RENAME //DISABLE RENAME
// if (!mapping.getKey().renameTo(mapping.getValue())) // if (!mapping.getKey().renameTo(mapping.getValue()))
@ -44,7 +50,9 @@ class RenameAction extends AbstractAction {
} }
// renamed all matches successfully // renamed all matches successfully
if (renameLog.size() > 0) {
Logger.getLogger("ui").info(String.format("%d files renamed.", renameLog.size())); Logger.getLogger("ui").info(String.format("%d files renamed.", renameLog.size()));
}
} catch (Exception e) { } catch (Exception e) {
// could not rename one of the files, revert all changes // could not rename one of the files, revert all changes
Logger.getLogger("ui").warning(e.getMessage()); Logger.getLogger("ui").warning(e.getMessage());
@ -63,7 +71,58 @@ class RenameAction extends AbstractAction {
} }
} }
// remove renamed matches
for (Entry<File, File> entry : renameLog) {
// find index of source file
int index = model.files().indexOf(entry.getKey());
// remove complete match
model.matches().remove(index);
}
// update history // update history
if (renameLog.size() > 0) {
HistorySpooler.getInstance().append(renameLog); HistorySpooler.getInstance().append(renameLog);
} }
} }
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());
List<String> destinationFileNameView = new AbstractList<String>() {
@Override
public String get(int index) {
return source.get(index).getValue().getName();
}
@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();
}
@Override
public int size() {
return source.size();
}
};
if (ValidateDialog.validate(parent, destinationFileNameView)) {
// names have been validated via view
return source;
}
// return empty list if validation was cancelled
return emptyList();
}
}

View File

@ -0,0 +1,284 @@
package net.sourceforge.filebot.ui.panel.rename;
import static java.util.Collections.*;
import static net.sourceforge.filebot.FileBotUtilities.*;
import static net.sourceforge.tuned.ui.TunedUtilities.*;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import net.miginfocom.swing.MigLayout;
import net.sourceforge.filebot.ResourceManager;
class ValidateDialog extends JDialog {
private final JList list;
private final Action validateAction = new ValidateAction();
private final Action continueAction = new ContinueAction();
private final Action cancelAction = new CancelAction();
private String[] model;
private boolean cancelled = true;
public ValidateDialog(Window owner, Collection<String> source) {
super(owner, "Invalid Names", ModalityType.DOCUMENT_MODAL);
model = source.toArray(new String[0]);
list = new JList(model);
list.setEnabled(false);
list.setCellRenderer(new HighlightListCellRenderer(INVALID_CHARACTERS_PATTERN, new CharacterHighlightPainter(new Color(0xFF4200), new Color(0xFF1200)), 4));
JLabel label = new JLabel("Some names contain invalid characters:");
JComponent content = (JComponent) getContentPane();
content.setLayout(new MigLayout("insets dialog, nogrid, fill"));
content.add(label, "wrap");
content.add(new JScrollPane(list), "grow, wrap 2mm");
content.add(new JButton(validateAction), "align center");
content.add(new AlphaButton(continueAction), "gap related");
content.add(new JButton(cancelAction), "gap 12mm");
installAction(content, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
setSize(365, 280);
}
public List<String> getModel() {
return unmodifiableList(Arrays.asList(model));
}
public boolean isCancelled() {
return cancelled;
}
private void finish(boolean cancelled) {
this.cancelled = cancelled;
setVisible(false);
dispose();
}
private class ValidateAction extends AbstractAction {
public ValidateAction() {
putValue(NAME, "Validate");
putValue(SMALL_ICON, ResourceManager.getIcon("dialog.continue"));
putValue(SHORT_DESCRIPTION, "Remove invalid characters");
}
@Override
public void actionPerformed(ActionEvent e) {
// validate names
for (int i = 0; i < model.length; i++) {
model[i] = validateFileName(model[i]);
}
// update view
list.repaint();
continueAction.putValue(SMALL_ICON, getValue(SMALL_ICON));
continueAction.putValue(ContinueAction.ALPHA, 1.0f);
// disable action
setEnabled(false);
}
}
private class ContinueAction extends AbstractAction {
public static final String ALPHA = "alpha";
public ContinueAction() {
putValue(NAME, "Continue");
putValue(SMALL_ICON, ResourceManager.getIcon("dialog.continue.invalid"));
putValue(ALPHA, 0.75f);
}
public void actionPerformed(ActionEvent e) {
finish(false);
}
}
protected class CancelAction extends AbstractAction {
public CancelAction() {
putValue(NAME, "Cancel");
putValue(SMALL_ICON, ResourceManager.getIcon("dialog.cancel"));
}
public void actionPerformed(ActionEvent e) {
finish(true);
}
}
protected static class AlphaButton extends JButton {
private float alpha;
public AlphaButton(Action action) {
super(action);
}
@Override
protected void configurePropertiesFromAction(Action action) {
super.configurePropertiesFromAction(action);
alpha = getAlpha(action);
}
@Override
protected void actionPropertyChanged(Action action, String propertyName) {
super.actionPropertyChanged(action, propertyName);
if (propertyName.equals(ContinueAction.ALPHA)) {
alpha = getAlpha(action);
}
}
private float getAlpha(Action action) {
Object value = action.getValue(ContinueAction.ALPHA);
if (value instanceof Float) {
return (Float) value;
}
return 1.0f;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
super.paintComponent(g2d);
}
}
public static boolean validate(Component parent, List<String> source) {
IndexView<String> invalid = new IndexView<String>(source);
for (int i = 0; i < source.size(); i++) {
String name = source.get(i);
if (isInvalidFileName(name)) {
invalid.addIndex(i);
}
}
if (invalid.isEmpty()) {
// nothing to do
return true;
}
ValidateDialog dialog = new ValidateDialog(getWindow(parent), invalid);
// show and block
dialog.setVisible(true);
if (dialog.isCancelled()) {
// no output
return false;
}
List<String> valid = dialog.getModel();
// validate source list via index view
for (int i = 0; i < invalid.size(); i++) {
invalid.set(i, valid.get(i));
}
return true;
}
private static class IndexView<E> extends AbstractList<E> {
private final List<Integer> mapping = new ArrayList<Integer>();
private final List<E> source;
public IndexView(List<E> source) {
this.source = source;
}
public boolean addIndex(int index) {
return mapping.add(index);
}
@Override
public E get(int index) {
int sourceIndex = mapping.get(index);
if (sourceIndex >= 0)
return source.get(sourceIndex);
return null;
}
@Override
public E set(int index, E element) {
return source.set(mapping.get(index), element);
}
@Override
public int size() {
return mapping.size();
}
}
}

View File

@ -1,215 +0,0 @@
package net.sourceforge.filebot.ui.panel.rename;
import static net.sourceforge.filebot.FileBotUtilities.*;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import net.miginfocom.swing.MigLayout;
import net.sourceforge.filebot.ResourceManager;
import net.sourceforge.tuned.ui.TunedUtilities;
class ValidateNamesDialog extends JDialog {
private final List<String> source;
private String[] validatedValues;
private boolean cancelled = true;
protected final JList list;
protected final Action validateAction = new ValidateAction();
protected final Action continueAction = new ContinueAction();
protected final Action cancelAction = new CancelAction();
public ValidateNamesDialog(Window owner, List<String> source) {
super(owner, "Invalid Names", ModalityType.DOCUMENT_MODAL);
this.source = source;
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
list = new JList(source.toArray());
list.setEnabled(false);
list.setCellRenderer(new HighlightListCellRenderer(INVALID_CHARACTERS_PATTERN, new CharacterHighlightPainter(new Color(0xFF4200), new Color(0xFF1200)), 4));
JLabel label = new JLabel("Some names contain invalid characters:");
JComponent c = (JComponent) getContentPane();
c.setLayout(new MigLayout("insets dialog, nogrid, fill"));
c.add(label, "wrap");
c.add(new JScrollPane(list), "grow, wrap 2mm");
c.add(new JButton(validateAction), "align center");
c.add(new AlphaButton(continueAction), "gap related");
c.add(new JButton(cancelAction), "gap 12mm");
setSize(365, 280);
setLocation(TunedUtilities.getPreferredLocation(this));
TunedUtilities.installAction(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
}
public boolean isCancelled() {
return cancelled;
}
private void finish(boolean cancelled) {
this.cancelled = cancelled;
setVisible(false);
dispose();
if (validatedValues != null && !cancelled) {
// update source list
for (int i = 0; i < validatedValues.length; i++) {
source.set(i, validatedValues[i]);
}
}
}
private class ValidateAction extends AbstractAction {
public ValidateAction() {
super("Validate", ResourceManager.getIcon("dialog.continue"));
putValue(SHORT_DESCRIPTION, "Remove invalid characters");
}
@Override
public void actionPerformed(ActionEvent e) {
validatedValues = new String[source.size()];
for (int i = 0; i < validatedValues.length; i++) {
validatedValues[i] = validateFileName(source.get(i));
}
setEnabled(false);
continueAction.putValue(SMALL_ICON, getValue(SMALL_ICON));
continueAction.putValue(ContinueAction.ALPHA, 1.0f);
// update displayed values
list.setModel(new AbstractListModel() {
@Override
public Object getElementAt(int i) {
return validatedValues[i];
}
@Override
public int getSize() {
return validatedValues.length;
}
});
}
};
private class ContinueAction extends AbstractAction {
public static final String ALPHA = "Alpha";
public ContinueAction() {
super("Continue", ResourceManager.getIcon("dialog.continue.invalid"));
putValue(ALPHA, 0.75f);
}
public void actionPerformed(ActionEvent e) {
finish(false);
}
};
protected class CancelAction extends AbstractAction {
public CancelAction() {
super("Cancel", ResourceManager.getIcon("dialog.cancel"));
}
public void actionPerformed(ActionEvent e) {
finish(true);
}
};
protected static class AlphaButton extends JButton {
private float alpha;
public AlphaButton(Action action) {
super(action);
alpha = getAlpha(action);
}
@Override
protected void actionPropertyChanged(Action action, String propertyName) {
super.actionPropertyChanged(action, propertyName);
if (propertyName.equals(ContinueAction.ALPHA)) {
alpha = getAlpha(action);
}
}
private float getAlpha(Action action) {
Object value = action.getValue(ContinueAction.ALPHA);
if (value instanceof Float) {
return (Float) value;
}
return 1.0f;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
super.paintComponent(g2d);
}
}
public static boolean showDialog(Component parent, List<String> source) {
ValidateNamesDialog dialog = new ValidateNamesDialog(TunedUtilities.getWindow(parent), source);
dialog.setVisible(true);
return !dialog.isCancelled();
}
}