diff --git a/source/net/sourceforge/filebot/cli/RenameAction.java b/source/net/sourceforge/filebot/RenameAction.java similarity index 75% rename from source/net/sourceforge/filebot/cli/RenameAction.java rename to source/net/sourceforge/filebot/RenameAction.java index 8157f17b..75589ac5 100644 --- a/source/net/sourceforge/filebot/cli/RenameAction.java +++ b/source/net/sourceforge/filebot/RenameAction.java @@ -1,5 +1,5 @@ -package net.sourceforge.filebot.cli; +package net.sourceforge.filebot; import java.io.File; diff --git a/source/net/sourceforge/filebot/cli/StandardRenameAction.java b/source/net/sourceforge/filebot/StandardRenameAction.java similarity index 98% rename from source/net/sourceforge/filebot/cli/StandardRenameAction.java rename to source/net/sourceforge/filebot/StandardRenameAction.java index 3725e488..8127f5bb 100644 --- a/source/net/sourceforge/filebot/cli/StandardRenameAction.java +++ b/source/net/sourceforge/filebot/StandardRenameAction.java @@ -1,5 +1,5 @@ -package net.sourceforge.filebot.cli; +package net.sourceforge.filebot; import java.io.File; diff --git a/source/net/sourceforge/filebot/cli/CmdlineOperations.java b/source/net/sourceforge/filebot/cli/CmdlineOperations.java index 68625457..b1e896d4 100644 --- a/source/net/sourceforge/filebot/cli/CmdlineOperations.java +++ b/source/net/sourceforge/filebot/cli/CmdlineOperations.java @@ -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; diff --git a/source/net/sourceforge/filebot/resources/action.rename.small.png b/source/net/sourceforge/filebot/resources/action.rename.small.png deleted file mode 100644 index 4e3688ed..00000000 Binary files a/source/net/sourceforge/filebot/resources/action.rename.small.png and /dev/null differ diff --git a/source/net/sourceforge/filebot/resources/action.settings.png b/source/net/sourceforge/filebot/resources/action.settings.png new file mode 100644 index 00000000..31b135da Binary files /dev/null and b/source/net/sourceforge/filebot/resources/action.settings.png differ diff --git a/source/net/sourceforge/filebot/resources/rename.action.copy.png b/source/net/sourceforge/filebot/resources/rename.action.copy.png new file mode 100644 index 00000000..8dd48c49 Binary files /dev/null and b/source/net/sourceforge/filebot/resources/rename.action.copy.png differ diff --git a/source/net/sourceforge/filebot/resources/rename.action.hardlink.png b/source/net/sourceforge/filebot/resources/rename.action.hardlink.png new file mode 100644 index 00000000..8679c4b5 Binary files /dev/null and b/source/net/sourceforge/filebot/resources/rename.action.hardlink.png differ diff --git a/source/net/sourceforge/filebot/resources/rename.action.keeplink.png b/source/net/sourceforge/filebot/resources/rename.action.keeplink.png new file mode 100644 index 00000000..ae8cae80 Binary files /dev/null and b/source/net/sourceforge/filebot/resources/rename.action.keeplink.png differ diff --git a/source/net/sourceforge/filebot/resources/rename.action.move.png b/source/net/sourceforge/filebot/resources/rename.action.move.png new file mode 100644 index 00000000..ed7849b4 Binary files /dev/null and b/source/net/sourceforge/filebot/resources/rename.action.move.png differ diff --git a/source/net/sourceforge/filebot/resources/rename.action.symlink.png b/source/net/sourceforge/filebot/resources/rename.action.symlink.png new file mode 100644 index 00000000..00be352c Binary files /dev/null and b/source/net/sourceforge/filebot/resources/rename.action.symlink.png differ diff --git a/source/net/sourceforge/filebot/ui/rename/FileNameFormatter.java b/source/net/sourceforge/filebot/ui/rename/FileNameFormatter.java index c78ac778..dd4ca204 100644 --- a/source/net/sourceforge/filebot/ui/rename/FileNameFormatter.java +++ b/source/net/sourceforge/filebot/ui/rename/FileNameFormatter.java @@ -11,40 +11,46 @@ import net.sourceforge.tuned.FileUtilities; class FileNameFormatter implements MatchFormatter { - private final boolean preserveExtension; + private boolean preserveExtension; + - public FileNameFormatter(boolean preserveExtension) { this.preserveExtension = preserveExtension; } - + @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; } - + @Override public String preview(Match match) { return format(match); } - + @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); } } diff --git a/source/net/sourceforge/filebot/ui/rename/RenameAction.java b/source/net/sourceforge/filebot/ui/rename/RenameAction.java index b24e4d61..39a3dde7 100644 --- a/source/net/sourceforge/filebot/ui/rename/RenameAction.java +++ b/source/net/sourceforge/filebot/ui/rename/RenameAction.java @@ -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 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, Void> implements Cancellable { + private final StandardRenameAction action; + private final Map renameMap; private final Map renameLog; - public RenameJob(Map renameMap) { + public RenameJob(Map renameMap, StandardRenameAction action) { + this.action = action; this.renameMap = synchronizedMap(renameMap); this.renameLog = synchronizedMap(new LinkedHashMap()); } @@ -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()); diff --git a/source/net/sourceforge/filebot/ui/rename/RenameListCellRenderer.java b/source/net/sourceforge/filebot/ui/rename/RenameListCellRenderer.java index 909ece95..50aaba7b 100644 --- a/source/net/sourceforge/filebot/ui/rename/RenameListCellRenderer.java +++ b/source/net/sourceforge/filebot/ui/rename/RenameListCellRenderer.java @@ -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; - setText(formattedFuture.isDone() && !formattedFuture.isCancelled() ? formattedFuture.toString() : formattedFuture.preview()); + + 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 match) { if (match.getValue() instanceof Episode) { float f = verificationMetric().getSimilarity(match.getValue(), match.getCandidate()); diff --git a/source/net/sourceforge/filebot/ui/rename/RenamePanel.java b/source/net/sourceforge/filebot/ui/rename/RenamePanel.java index 237bd253..794f36ae 100644 --- a/source/net/sourceforge/filebot/ui/rename/RenamePanel.java +++ b/source/net/sourceforge/filebot/ui/rename/RenamePanel.java @@ -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; diff --git a/source/net/sourceforge/tuned/ui/ActionPopup.java b/source/net/sourceforge/tuned/ui/ActionPopup.java index 4e6d4fa8..57b586ac 100644 --- a/source/net/sourceforge/tuned/ui/ActionPopup.java +++ b/source/net/sourceforge/tuned/ui/ActionPopup.java @@ -26,7 +26,7 @@ public class ActionPopup extends JPopupMenu { protected final JPanel actionPanel = new JPanel(new MigLayout("nogrid, insets 0, fill")); - + public ActionPopup(String label, Icon icon) { headerLabel.setText(label); headerLabel.setIcon(icon); @@ -46,70 +46,69 @@ public class ActionPopup extends JPopupMenu { add(statusLabel, "growx, h 11px!, gapx 3px, wrap 1px"); } - + public void addDescription(JComponent component) { actionPanel.add(component, "gapx 4px, wrap 3px"); } - + public void addAction(JComponent component) { actionPanel.add(component, "gapx 12px 12px, growx, wrap"); } - + @Override public void addSeparator() { actionPanel.add(new JSeparator(), "growx, wrap 1px"); } - + @Override 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("%s", link.getText())); + link.setText(String.format("%s", 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; } - + public void clear() { actionPanel.removeAll(); } - + @Override public void setLabel(String label) { headerLabel.setText(label); } - + @Override public String getLabel() { return headerLabel.getText(); } - + public void setStatus(String string) { statusLabel.setText(string); } - + public String getStatus() { return statusLabel.getText(); } - + private final ActionListener closeListener = new ActionListener() { @Override