+ support all rename actions (move, copy, hardlink, ...) in GUI as well
+ include/exclude extension mode evolved to Relative Name / Absolute Path modes
@ -1,5 +1,5 @@
|
||||
|
||||
package net.sourceforge.filebot.cli;
|
||||
package net.sourceforge.filebot;
|
||||
|
||||
|
||||
import java.io.File;
|
@ -1,5 +1,5 @@
|
||||
|
||||
package net.sourceforge.filebot.cli;
|
||||
package net.sourceforge.filebot;
|
||||
|
||||
|
||||
import java.io.File;
|
@ -46,6 +46,8 @@ import java.util.regex.Pattern;
|
||||
import net.sourceforge.filebot.Analytics;
|
||||
import net.sourceforge.filebot.HistorySpooler;
|
||||
import net.sourceforge.filebot.MediaTypes;
|
||||
import net.sourceforge.filebot.RenameAction;
|
||||
import net.sourceforge.filebot.StandardRenameAction;
|
||||
import net.sourceforge.filebot.WebServices;
|
||||
import net.sourceforge.filebot.archive.Archive;
|
||||
import net.sourceforge.filebot.archive.FileMapper;
|
||||
|
Before Width: | Height: | Size: 273 B |
BIN
source/net/sourceforge/filebot/resources/action.settings.png
Normal file
After Width: | Height: | Size: 947 B |
BIN
source/net/sourceforge/filebot/resources/rename.action.copy.png
Normal file
After Width: | Height: | Size: 498 B |
After Width: | Height: | Size: 679 B |
After Width: | Height: | Size: 655 B |
BIN
source/net/sourceforge/filebot/resources/rename.action.move.png
Normal file
After Width: | Height: | Size: 883 B |
After Width: | Height: | Size: 570 B |
@ -11,7 +11,7 @@ import net.sourceforge.tuned.FileUtilities;
|
||||
|
||||
class FileNameFormatter implements MatchFormatter {
|
||||
|
||||
private final boolean preserveExtension;
|
||||
private boolean preserveExtension;
|
||||
|
||||
|
||||
public FileNameFormatter(boolean preserveExtension) {
|
||||
@ -21,7 +21,7 @@ class FileNameFormatter implements MatchFormatter {
|
||||
|
||||
@Override
|
||||
public boolean canFormat(Match<?, ?> match) {
|
||||
return match.getValue() instanceof File || match.getValue() instanceof FileInfo;
|
||||
return match.getValue() instanceof File || match.getValue() instanceof FileInfo || match.getValue() instanceof String;
|
||||
}
|
||||
|
||||
|
||||
@ -33,18 +33,24 @@ class FileNameFormatter implements MatchFormatter {
|
||||
|
||||
@Override
|
||||
public String format(Match<?, ?> match) {
|
||||
if (match.getValue() instanceof File) {
|
||||
File file = (File) match.getValue();
|
||||
Object value = match.getValue();
|
||||
|
||||
if (value instanceof File) {
|
||||
File file = (File) value;
|
||||
return preserveExtension ? FileUtilities.getName(file) : file.getName();
|
||||
}
|
||||
|
||||
if (match.getValue() instanceof FileInfo) {
|
||||
FileInfo file = (FileInfo) match.getValue();
|
||||
if (value instanceof FileInfo) {
|
||||
FileInfo file = (FileInfo) value;
|
||||
return preserveExtension ? file.getName() : file.getPath();
|
||||
}
|
||||
|
||||
if (value instanceof String) {
|
||||
return preserveExtension ? FileUtilities.getNameWithoutExtension(value.toString()) : value.toString();
|
||||
}
|
||||
|
||||
// cannot format value
|
||||
throw new IllegalArgumentException("Illegal value: " + match.getValue());
|
||||
throw new IllegalArgumentException("Illegal value: " + value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ package net.sourceforge.filebot.ui.rename;
|
||||
|
||||
import static java.util.Collections.*;
|
||||
import static net.sourceforge.filebot.ui.NotificationLogging.*;
|
||||
import static net.sourceforge.tuned.FileUtilities.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.awt.Cursor;
|
||||
@ -33,6 +32,7 @@ import javax.swing.SwingWorker;
|
||||
import net.sourceforge.filebot.Analytics;
|
||||
import net.sourceforge.filebot.HistorySpooler;
|
||||
import net.sourceforge.filebot.ResourceManager;
|
||||
import net.sourceforge.filebot.StandardRenameAction;
|
||||
import net.sourceforge.tuned.ui.ProgressDialog;
|
||||
import net.sourceforge.tuned.ui.ProgressDialog.Cancellable;
|
||||
import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
|
||||
@ -40,15 +40,21 @@ import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
|
||||
|
||||
class RenameAction extends AbstractAction {
|
||||
|
||||
public static final String RENAME_ACTION = "RENAME_ACTION";
|
||||
|
||||
private final RenameModel model;
|
||||
|
||||
|
||||
public RenameAction(RenameModel model) {
|
||||
this.model = model;
|
||||
resetValues();
|
||||
}
|
||||
|
||||
|
||||
public void resetValues() {
|
||||
putValue(RENAME_ACTION, StandardRenameAction.MOVE);
|
||||
putValue(NAME, "Rename");
|
||||
putValue(SMALL_ICON, ResourceManager.getIcon("action.rename"));
|
||||
putValue(SHORT_DESCRIPTION, "Rename files");
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +68,7 @@ class RenameAction extends AbstractAction {
|
||||
Map<File, File> renameMap = checkRenamePlan(validate(model.getRenameMap(), window));
|
||||
|
||||
window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
RenameJob renameJob = new RenameJob(renameMap);
|
||||
RenameJob renameJob = new RenameJob(renameMap, (StandardRenameAction) getValue(RENAME_ACTION));
|
||||
renameJob.execute();
|
||||
|
||||
try {
|
||||
@ -192,11 +198,14 @@ class RenameAction extends AbstractAction {
|
||||
|
||||
protected class RenameJob extends SwingWorker<Map<File, File>, Void> implements Cancellable {
|
||||
|
||||
private final StandardRenameAction action;
|
||||
|
||||
private final Map<File, File> renameMap;
|
||||
private final Map<File, File> renameLog;
|
||||
|
||||
|
||||
public RenameJob(Map<File, File> renameMap) {
|
||||
public RenameJob(Map<File, File> renameMap, StandardRenameAction action) {
|
||||
this.action = action;
|
||||
this.renameMap = synchronizedMap(renameMap);
|
||||
this.renameLog = synchronizedMap(new LinkedHashMap<File, File>());
|
||||
}
|
||||
@ -213,7 +222,7 @@ class RenameAction extends AbstractAction {
|
||||
firePropertyChange("currentFile", mapping.getKey(), mapping.getValue());
|
||||
|
||||
// rename file, throw exception on failure
|
||||
moveRename(mapping.getKey(), mapping.getValue());
|
||||
action.rename(mapping.getKey(), mapping.getValue());
|
||||
|
||||
// remember successfully renamed matches for history entry and possible revert
|
||||
renameLog.put(mapping.getKey(), mapping.getValue());
|
||||
|
@ -89,12 +89,20 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
||||
if (renameModel.preserveExtension()) {
|
||||
setText(FileUtilities.getName(file));
|
||||
} else {
|
||||
setText(file.getName());
|
||||
setText(file.getAbsolutePath());
|
||||
}
|
||||
} else if (value instanceof FormattedFuture) {
|
||||
// display progress icon
|
||||
FormattedFuture formattedFuture = (FormattedFuture) value;
|
||||
|
||||
if (!renameModel.preserveExtension() && formattedFuture.isDone() && renameModel.hasComplement(index)) {
|
||||
// absolute path mode
|
||||
File targetDir = renameModel.getMatch(index).getCandidate().getParentFile();
|
||||
setText(resolveAbsolutePath(targetDir, formattedFuture.toString()));
|
||||
} else {
|
||||
// relative name mode
|
||||
setText(formattedFuture.isDone() && !formattedFuture.isCancelled() ? formattedFuture.toString() : formattedFuture.preview());
|
||||
}
|
||||
|
||||
switch (formattedFuture.getState()) {
|
||||
case PENDING:
|
||||
@ -128,6 +136,20 @@ class RenameListCellRenderer extends DefaultFancyListCellRenderer {
|
||||
}
|
||||
|
||||
|
||||
protected String resolveAbsolutePath(File targetDir, String path) {
|
||||
File f = new File(path);
|
||||
if (!f.isAbsolute()) {
|
||||
f = new File(targetDir, path); // resolve path against target folder
|
||||
}
|
||||
|
||||
try {
|
||||
return f.getCanonicalPath();
|
||||
} catch (Exception e) {
|
||||
return f.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected float getMatchProbablity(Match<Object, File> match) {
|
||||
if (match.getValue() instanceof Episode) {
|
||||
float f = verificationMetric().getSimilarity(match.getValue(), match.getCandidate());
|
||||
|
@ -16,6 +16,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -46,6 +47,7 @@ import net.sourceforge.filebot.History;
|
||||
import net.sourceforge.filebot.HistorySpooler;
|
||||
import net.sourceforge.filebot.ResourceManager;
|
||||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.StandardRenameAction;
|
||||
import net.sourceforge.filebot.WebServices;
|
||||
import net.sourceforge.filebot.similarity.Match;
|
||||
import net.sourceforge.filebot.ui.Language;
|
||||
@ -153,13 +155,19 @@ public class RenamePanel extends JComponent {
|
||||
}
|
||||
});
|
||||
|
||||
// create settings popup
|
||||
final Action settingsPopupAction = new ShowPopupAction("Options", ResourceManager.getIcon("action.report"));
|
||||
JButton settingsButton = createImageButton(settingsPopupAction);
|
||||
settingsButton.setAction(openHistoryAction);
|
||||
namesList.getListComponent().setComponentPopupMenu(fetchPopup);
|
||||
fetchButton.setComponentPopupMenu(fetchPopup);
|
||||
|
||||
// settings popup and button
|
||||
ActionPopup settingsPopup = createSettingsPopup();
|
||||
final Action settingsPopupAction = new ShowPopupAction("Settings", ResourceManager.getIcon("action.settings"));
|
||||
JButton settingsButton = createImageButton(settingsPopupAction);
|
||||
settingsButton.setComponentPopupMenu(settingsPopup);
|
||||
renameButton.setComponentPopupMenu(settingsPopup);
|
||||
filesList.getButtonPanel().add(settingsButton, "gap 0");
|
||||
namesList.getButtonPanel().add(settingsButton, "gap indent");
|
||||
|
||||
// open rename log button
|
||||
filesList.getButtonPanel().add(createImageButton(openHistoryAction), "gap 0");
|
||||
|
||||
setLayout(new MigLayout("fill, insets dialog, gapx 10px", "[fill][align center, pref!][fill]", "align 33%"));
|
||||
|
||||
@ -276,16 +284,18 @@ public class RenamePanel extends JComponent {
|
||||
|
||||
|
||||
protected ActionPopup createSettingsPopup() {
|
||||
ActionPopup actionPopup = new ActionPopup("Rename Options", ResourceManager.getIcon("action.rename.small"));
|
||||
ActionPopup actionPopup = new ActionPopup("Rename Options", ResourceManager.getIcon("action.settings"));
|
||||
|
||||
actionPopup.addDescription(new JLabel("Extension:"));
|
||||
|
||||
actionPopup.add(new OverrideExtensionAction(false, "Preserve", ResourceManager.getIcon("action.extension.preserve")));
|
||||
actionPopup.add(new OverrideExtensionAction(true, "Override", ResourceManager.getIcon("action.extension.override")));
|
||||
actionPopup.addDescription(new JLabel("Mode:"));
|
||||
actionPopup.add(new SetRenameMode(false, "Relative Name", ResourceManager.getIcon("action.extension.preserve")));
|
||||
actionPopup.add(new SetRenameMode(true, "Absolute Path", ResourceManager.getIcon("action.extension.override")));
|
||||
|
||||
actionPopup.addSeparator();
|
||||
actionPopup.addDescription(new JLabel("History:"));
|
||||
actionPopup.add(openHistoryAction);
|
||||
|
||||
actionPopup.addDescription(new JLabel("Action:"));
|
||||
for (StandardRenameAction action : EnumSet.of(StandardRenameAction.MOVE, StandardRenameAction.COPY, StandardRenameAction.KEEPLINK, StandardRenameAction.SYMLINK, StandardRenameAction.HARDLINK)) {
|
||||
actionPopup.add(new SetRenameAction(action, action.toString().toLowerCase(), ResourceManager.getIcon("rename.action." + action.toString().toLowerCase())));
|
||||
}
|
||||
|
||||
return actionPopup;
|
||||
}
|
||||
@ -328,12 +338,12 @@ public class RenamePanel extends JComponent {
|
||||
};
|
||||
|
||||
|
||||
protected class OverrideExtensionAction extends AbstractAction {
|
||||
protected class SetRenameMode extends AbstractAction {
|
||||
|
||||
private final boolean activate;
|
||||
|
||||
|
||||
private OverrideExtensionAction(boolean activate, String name, Icon icon) {
|
||||
private SetRenameMode(boolean activate, String name, Icon icon) {
|
||||
super(name, icon);
|
||||
this.activate = activate;
|
||||
}
|
||||
@ -352,6 +362,26 @@ public class RenamePanel extends JComponent {
|
||||
}
|
||||
|
||||
|
||||
protected class SetRenameAction extends AbstractAction {
|
||||
|
||||
private final StandardRenameAction action;
|
||||
|
||||
|
||||
public SetRenameAction(StandardRenameAction action, String name, Icon icon) {
|
||||
super(name, icon);
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
renameAction.putValue(RenameAction.RENAME_ACTION, action);
|
||||
renameAction.putValue(NAME, this.getValue(NAME));
|
||||
renameAction.putValue(SMALL_ICON, this.getValue(SMALL_ICON));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected class AutoCompleteAction extends AbstractAction {
|
||||
|
||||
private final AutoCompleteMatcher matcher;
|
||||
|
@ -67,18 +67,17 @@ public class ActionPopup extends JPopupMenu {
|
||||
public JMenuItem add(Action a) {
|
||||
LinkButton link = new LinkButton(a);
|
||||
|
||||
// close popup when action is triggered
|
||||
link.addActionListener(closeListener);
|
||||
|
||||
// underline text
|
||||
link.setText(String.format("<html><u>%s</u></html>", link.getText()));
|
||||
link.setText(String.format("<html><nobr><u>%s</u></nobr></html>", link.getText()));
|
||||
|
||||
// use rollover color
|
||||
link.setRolloverEnabled(false);
|
||||
link.setColor(link.getRolloverColor());
|
||||
|
||||
addAction(link);
|
||||
// close popup when action is triggered
|
||||
link.addActionListener(closeListener);
|
||||
|
||||
addAction(link);
|
||||
return null;
|
||||
}
|
||||
|
||||
|