mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-24 16:58:51 -05:00
* improved support for move/rename
This commit is contained in:
parent
0a2d323ac4
commit
f61b084769
@ -49,7 +49,6 @@ class ExpressionFormatDocument extends PlainDocument {
|
|||||||
RoundBrackets("()"),
|
RoundBrackets("()"),
|
||||||
SquareBrackets("[]"),
|
SquareBrackets("[]"),
|
||||||
CurlyBrackets("{}"),
|
CurlyBrackets("{}"),
|
||||||
RegexLiteral("//"),
|
|
||||||
SingleQuoteStringLiteral("''"),
|
SingleQuoteStringLiteral("''"),
|
||||||
DoubleQuoteStringLiteral("\"\"");
|
DoubleQuoteStringLiteral("\"\"");
|
||||||
|
|
||||||
|
@ -25,10 +25,10 @@ import net.sourceforge.tuned.ui.TunedUtilities;
|
|||||||
|
|
||||||
class HighlightListCellRenderer extends AbstractFancyListCellRenderer {
|
class HighlightListCellRenderer extends AbstractFancyListCellRenderer {
|
||||||
|
|
||||||
private final JTextComponent textComponent = new JTextField();
|
protected final JTextComponent textComponent = new JTextField();
|
||||||
|
|
||||||
private Pattern pattern;
|
protected final Pattern pattern;
|
||||||
private Highlighter.HighlightPainter highlightPainter;
|
protected final Highlighter.HighlightPainter highlightPainter;
|
||||||
|
|
||||||
|
|
||||||
public HighlightListCellRenderer(Pattern pattern, Highlighter.HighlightPainter highlightPainter, int padding) {
|
public HighlightListCellRenderer(Pattern pattern, Highlighter.HighlightPainter highlightPainter, int padding) {
|
||||||
|
@ -531,8 +531,14 @@ class HistoryDialog extends JDialog {
|
|||||||
File dir = directory != null ? directory : element.dir();
|
File dir = directory != null ? directory : element.dir();
|
||||||
|
|
||||||
// reverse
|
// reverse
|
||||||
File from = new File(dir, element.to());
|
File from = new File(element.to());
|
||||||
File to = new File(dir, element.from());
|
File to = new File(element.from());
|
||||||
|
|
||||||
|
// resolve against given directory or against the original base directory if the path is not absolute
|
||||||
|
if (!from.isAbsolute())
|
||||||
|
from = new File(dir, directory == null ? from.getPath() : from.getName());
|
||||||
|
if (!to.isAbsolute())
|
||||||
|
to = new File(dir, directory == null ? to.getPath() : to.getName());
|
||||||
|
|
||||||
renameMap.put(from, to);
|
renameMap.put(from, to);
|
||||||
}
|
}
|
||||||
@ -847,7 +853,12 @@ class HistoryDialog extends JDialog {
|
|||||||
|
|
||||||
public boolean isBroken(int row) {
|
public boolean isBroken(int row) {
|
||||||
Element element = data.get(row);
|
Element element = data.get(row);
|
||||||
File file = new File(element.dir(), element.to());
|
|
||||||
|
File file = new File(element.to());
|
||||||
|
|
||||||
|
// resolve relative path
|
||||||
|
if (!file.isAbsolute())
|
||||||
|
file = new File(element.dir(), file.getPath());
|
||||||
|
|
||||||
return !file.exists();
|
return !file.exists();
|
||||||
}
|
}
|
||||||
|
@ -91,10 +91,15 @@ class RenameAction extends AbstractAction {
|
|||||||
|
|
||||||
|
|
||||||
private File rename(File file, String path) throws IOException {
|
private File rename(File file, String path) throws IOException {
|
||||||
// same folder, different name
|
File destination = new File(path);
|
||||||
File destination = new File(file.getParentFile(), path);
|
|
||||||
|
|
||||||
// name may be a relative path, so we can't use file.getParentFile()
|
// resolve destination
|
||||||
|
if (!destination.isAbsolute()) {
|
||||||
|
// same folder, different name
|
||||||
|
destination = new File(file.getParentFile(), path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we that we can create the destination folder structure
|
||||||
File destinationFolder = destination.getParentFile();
|
File destinationFolder = destination.getParentFile();
|
||||||
|
|
||||||
// create parent folder if necessary
|
// create parent folder if necessary
|
||||||
|
@ -10,11 +10,15 @@ import java.awt.Color;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.io.File;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
@ -25,6 +29,7 @@ import javax.swing.JLabel;
|
|||||||
import javax.swing.JList;
|
import javax.swing.JList;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sourceforge.filebot.ResourceManager;
|
import net.sourceforge.filebot.ResourceManager;
|
||||||
@ -47,13 +52,37 @@ class ValidateDialog extends JDialog {
|
|||||||
list = new JList(model);
|
list = new JList(model);
|
||||||
list.setEnabled(false);
|
list.setEnabled(false);
|
||||||
|
|
||||||
list.setCellRenderer(new HighlightListCellRenderer(ILLEGAL_CHARACTERS, new CharacterHighlightPainter(new Color(0xFF4200), new Color(0xFF1200)), 4));
|
list.setCellRenderer(new HighlightListCellRenderer(ILLEGAL_CHARACTERS, new CharacterHighlightPainter(new Color(0xFF4200), new Color(0xFF1200)), 4) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateHighlighter() {
|
||||||
|
textComponent.getHighlighter().removeAllHighlights();
|
||||||
|
|
||||||
|
Matcher matcher = pattern.matcher(textComponent.getText());
|
||||||
|
File file = new File(textComponent.getText());
|
||||||
|
|
||||||
|
// highlight path components separately to ignore "illegal characters" that are either path separators or part of the drive letter (e.g. ':' in 'E:')
|
||||||
|
for (File element : listPath(file)) {
|
||||||
|
int limit = element.getPath().length();
|
||||||
|
matcher.region(limit - element.getName().length(), limit);
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
try {
|
||||||
|
textComponent.getHighlighter().addHighlight(matcher.start(0), matcher.end(0), highlightPainter);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
//should not happen
|
||||||
|
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
JLabel label = new JLabel("Some names contain invalid characters:");
|
JLabel label = new JLabel("Some names contain invalid characters:");
|
||||||
|
|
||||||
JComponent content = (JComponent) getContentPane();
|
JComponent content = (JComponent) getContentPane();
|
||||||
|
|
||||||
content.setLayout(new MigLayout("insets dialog, nogrid, fill"));
|
content.setLayout(new MigLayout("insets dialog, nogrid, fill", "", "[pref!][fill][pref!]"));
|
||||||
|
|
||||||
content.add(label, "wrap");
|
content.add(label, "wrap");
|
||||||
content.add(new JScrollPane(list), "grow, wrap 2mm");
|
content.add(new JScrollPane(list), "grow, wrap 2mm");
|
||||||
@ -94,7 +123,8 @@ class ValidateDialog extends JDialog {
|
|||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
// validate names
|
// validate names
|
||||||
for (int i = 0; i < model.length; i++) {
|
for (int i = 0; i < model.length; i++) {
|
||||||
model[i] = validateFileName(model[i]);
|
// remove illegal characters
|
||||||
|
model[i] = validateFilePath(new File(model[i])).getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update view
|
// update view
|
||||||
@ -126,22 +156,23 @@ class ValidateDialog extends JDialog {
|
|||||||
|
|
||||||
|
|
||||||
public static boolean validate(Component parent, List<String> source) {
|
public static boolean validate(Component parent, List<String> source) {
|
||||||
IndexView<String> invalid = new IndexView<String>(source);
|
IndexView<String> invalidFilePaths = new IndexView<String>(source);
|
||||||
|
|
||||||
for (int i = 0; i < source.size(); i++) {
|
for (int i = 0; i < source.size(); i++) {
|
||||||
String name = source.get(i);
|
String path = source.get(i);
|
||||||
|
|
||||||
if (isInvalidFileName(name)) {
|
// invalid file names are also invalid file paths
|
||||||
invalid.addIndex(i);
|
if (isInvalidFilePath(new File(path))) {
|
||||||
|
invalidFilePaths.addIndex(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalid.isEmpty()) {
|
// check if there is anything to do in the first place
|
||||||
// nothing to do
|
if (invalidFilePaths.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateDialog dialog = new ValidateDialog(getWindow(parent), invalid);
|
ValidateDialog dialog = new ValidateDialog(getWindow(parent), invalidFilePaths);
|
||||||
|
|
||||||
// show and block
|
// show and block
|
||||||
dialog.setVisible(true);
|
dialog.setVisible(true);
|
||||||
@ -151,11 +182,11 @@ class ValidateDialog extends JDialog {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> valid = dialog.getModel();
|
List<String> validatedFilePaths = dialog.getModel();
|
||||||
|
|
||||||
// validate source list via index view
|
// validate source list via index view
|
||||||
for (int i = 0; i < invalid.size(); i++) {
|
for (int i = 0; i < invalidFilePaths.size(); i++) {
|
||||||
invalid.set(i, valid.get(i));
|
invalidFilePaths.set(i, validatedFilePaths.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -9,6 +9,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -140,6 +142,17 @@ public final class FileUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static List<File> listPath(File file) {
|
||||||
|
LinkedList<File> nodes = new LinkedList<File>();
|
||||||
|
|
||||||
|
for (File node = file; node != null; node = node.getParentFile()) {
|
||||||
|
nodes.addFirst(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static List<File> listFiles(Iterable<File> folders, int maxDepth) {
|
public static List<File> listFiles(Iterable<File> folders, int maxDepth) {
|
||||||
List<File> files = new ArrayList<File>();
|
List<File> files = new ArrayList<File>();
|
||||||
|
|
||||||
@ -185,10 +198,47 @@ public final class FileUtilities {
|
|||||||
|
|
||||||
|
|
||||||
public static boolean isInvalidFileName(CharSequence filename) {
|
public static boolean isInvalidFileName(CharSequence filename) {
|
||||||
|
// check if file name contains any illegal characters
|
||||||
return ILLEGAL_CHARACTERS.matcher(filename).find();
|
return ILLEGAL_CHARACTERS.matcher(filename).find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static File validateFileName(File file) {
|
||||||
|
// windows drives (e.g. c:, d:, etc.) are never invalid because name will be an empty string
|
||||||
|
if (!isInvalidFileName(file.getName()))
|
||||||
|
return file;
|
||||||
|
|
||||||
|
// validate file name only
|
||||||
|
return new File(file.getParentFile(), validateFileName(file.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static File validateFilePath(File path) {
|
||||||
|
Iterator<File> nodes = listPath(path).iterator();
|
||||||
|
|
||||||
|
// initialize with root node, keep original root object if possible (so we don't loose the drive on windows)
|
||||||
|
File validatedPath = validateFileName(nodes.next());
|
||||||
|
|
||||||
|
// validate the rest of the path
|
||||||
|
while (nodes.hasNext()) {
|
||||||
|
validatedPath = new File(validatedPath, validateFileName(nodes.next().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return validatedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isInvalidFilePath(File path) {
|
||||||
|
// check if file name contains any illegal characters
|
||||||
|
for (File node = path; node != null; node = node.getParentFile()) {
|
||||||
|
if (isInvalidFileName(node.getName()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final long KILO = 1024;
|
public static final long KILO = 1024;
|
||||||
public static final long MEGA = KILO * 1024;
|
public static final long MEGA = KILO * 1024;
|
||||||
public static final long GIGA = MEGA * 1024;
|
public static final long GIGA = MEGA * 1024;
|
||||||
|
Loading…
Reference in New Issue
Block a user