2014-04-19 02:30:29 -04:00
|
|
|
package net.filebot.ui.rename;
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-05-17 16:58:20 -04:00
|
|
|
import static java.util.Collections.*;
|
2013-02-08 10:35:23 -05:00
|
|
|
import static javax.swing.JOptionPane.*;
|
2014-04-19 02:30:29 -04:00
|
|
|
import static net.filebot.Settings.*;
|
|
|
|
import static net.filebot.ui.NotificationLogging.*;
|
|
|
|
import static net.filebot.util.ExceptionUtilities.*;
|
|
|
|
import static net.filebot.util.FileUtilities.*;
|
2014-07-29 02:45:15 -04:00
|
|
|
import static net.filebot.util.ui.SwingUI.*;
|
2009-05-17 16:58:20 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
import java.awt.Cursor;
|
2013-02-08 10:35:23 -05:00
|
|
|
import java.awt.Dimension;
|
2009-05-17 16:58:20 -04:00
|
|
|
import java.awt.Window;
|
2007-12-23 14:28:04 -05:00
|
|
|
import java.awt.event.ActionEvent;
|
2011-11-04 03:45:48 -04:00
|
|
|
import java.beans.PropertyChangeEvent;
|
2007-12-23 14:28:04 -05:00
|
|
|
import java.io.File;
|
2014-08-08 13:05:10 -04:00
|
|
|
import java.io.IOException;
|
2009-05-17 16:58:20 -04:00
|
|
|
import java.util.AbstractList;
|
2012-02-10 11:43:09 -05:00
|
|
|
import java.util.AbstractMap.SimpleEntry;
|
2009-05-02 19:34:04 -04:00
|
|
|
import java.util.ArrayList;
|
2011-11-04 03:45:48 -04:00
|
|
|
import java.util.HashMap;
|
2011-09-21 09:29:21 -04:00
|
|
|
import java.util.HashSet;
|
2011-11-04 03:45:48 -04:00
|
|
|
import java.util.LinkedHashMap;
|
2009-05-02 19:34:04 -04:00
|
|
|
import java.util.List;
|
2009-05-17 16:58:20 -04:00
|
|
|
import java.util.Map;
|
2012-02-10 11:43:09 -05:00
|
|
|
import java.util.Map.Entry;
|
2011-11-04 03:45:48 -04:00
|
|
|
import java.util.Set;
|
2012-07-17 16:52:03 -04:00
|
|
|
import java.util.concurrent.CancellationException;
|
2012-08-13 01:58:27 -04:00
|
|
|
import java.util.concurrent.ExecutionException;
|
2012-07-17 16:52:03 -04:00
|
|
|
import java.util.concurrent.Semaphore;
|
2011-11-04 03:45:48 -04:00
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
import java.util.logging.Level;
|
2012-08-13 01:58:27 -04:00
|
|
|
import java.util.logging.Logger;
|
2014-08-08 15:15:37 -04:00
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Stream;
|
2007-12-23 14:28:04 -05:00
|
|
|
|
|
|
|
import javax.swing.AbstractAction;
|
2011-11-04 03:45:48 -04:00
|
|
|
import javax.swing.Icon;
|
2013-02-08 10:35:23 -05:00
|
|
|
import javax.swing.JList;
|
|
|
|
import javax.swing.JOptionPane;
|
|
|
|
import javax.swing.JScrollPane;
|
2011-11-04 03:45:48 -04:00
|
|
|
import javax.swing.SwingWorker;
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2014-04-19 02:30:29 -04:00
|
|
|
import net.filebot.Analytics;
|
|
|
|
import net.filebot.HistorySpooler;
|
|
|
|
import net.filebot.NativeRenameAction;
|
|
|
|
import net.filebot.ResourceManager;
|
|
|
|
import net.filebot.StandardRenameAction;
|
2014-08-08 13:05:10 -04:00
|
|
|
import net.filebot.mac.DropToUnlock;
|
2014-04-19 02:30:29 -04:00
|
|
|
import net.filebot.media.MediaDetection;
|
|
|
|
import net.filebot.similarity.Match;
|
|
|
|
import net.filebot.util.ui.ProgressDialog;
|
|
|
|
import net.filebot.util.ui.ProgressDialog.Cancellable;
|
|
|
|
import net.filebot.util.ui.SwingWorkerPropertyChangeAdapter;
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-01-17 06:03:09 -05:00
|
|
|
class RenameAction extends AbstractAction {
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-12 07:23:23 -04:00
|
|
|
public static final String RENAME_ACTION = "RENAME_ACTION";
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-04-26 09:34:22 -04:00
|
|
|
private final RenameModel model;
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-04-26 09:34:22 -04:00
|
|
|
public RenameAction(RenameModel model) {
|
2009-05-17 16:58:20 -04:00
|
|
|
this.model = model;
|
2012-07-12 07:23:23 -04:00
|
|
|
resetValues();
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-12 07:23:23 -04:00
|
|
|
public void resetValues() {
|
|
|
|
putValue(RENAME_ACTION, StandardRenameAction.MOVE);
|
2009-05-17 16:58:20 -04:00
|
|
|
putValue(NAME, "Rename");
|
|
|
|
putValue(SMALL_ICON, ResourceManager.getIcon("action.rename"));
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-19 23:38:47 -04:00
|
|
|
@Override
|
2009-01-11 16:23:03 -05:00
|
|
|
public void actionPerformed(ActionEvent evt) {
|
2011-11-11 10:51:50 -05:00
|
|
|
Window window = getWindow(evt.getSource());
|
2009-01-11 16:23:03 -05:00
|
|
|
try {
|
2013-10-28 01:49:00 -04:00
|
|
|
if (model.files().isEmpty() || model.values().isEmpty()) {
|
|
|
|
UILogger.info("Nothing to rename. Please add some files and fetch naming data first.");
|
2012-08-13 01:58:27 -04:00
|
|
|
return;
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
Map<File, File> renameMap = checkRenamePlan(validate(model.getRenameMap(), window), window);
|
|
|
|
if (renameMap.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
// start processing
|
2014-01-08 12:23:04 -05:00
|
|
|
List<Match<Object, File>> matches = new ArrayList<Match<Object, File>>(model.matches());
|
|
|
|
StandardRenameAction action = (StandardRenameAction) getValue(RENAME_ACTION);
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2014-01-08 12:23:04 -05:00
|
|
|
window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
if (useNativeShell() && isNativeActionSupported(action)) {
|
|
|
|
RenameJob renameJob = new NativeRenameJob(renameMap, NativeRenameAction.valueOf(action.name()));
|
|
|
|
renameJob.execute();
|
|
|
|
try {
|
|
|
|
renameJob.get(); // wait for native operation to finish or be cancelled
|
|
|
|
} catch (CancellationException e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RenameJob renameJob = new RenameJob(renameMap, action);
|
|
|
|
renameJob.execute();
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
try {
|
|
|
|
// wait a for little while (renaming might finish in less than a second)
|
|
|
|
renameJob.get(2, TimeUnit.SECONDS);
|
|
|
|
} catch (TimeoutException ex) {
|
|
|
|
// move/renaming will probably take a while
|
|
|
|
ProgressDialog dialog = createProgressDialog(window, renameJob);
|
|
|
|
dialog.setLocation(getOffsetLocation(dialog.getOwner()));
|
|
|
|
dialog.setIndeterminate(true);
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
// display progress dialog and stop blocking EDT
|
|
|
|
window.setCursor(Cursor.getDefaultCursor());
|
|
|
|
dialog.setVisible(true);
|
|
|
|
}
|
2009-05-17 16:58:20 -04:00
|
|
|
}
|
2014-01-08 12:23:04 -05:00
|
|
|
|
|
|
|
// write metadata into xattr if xattr is enabled
|
2014-01-25 22:51:47 -05:00
|
|
|
if (useExtendedFileAttributes() || useCreationDate()) {
|
2014-01-08 12:23:04 -05:00
|
|
|
try {
|
|
|
|
for (Match<Object, File> match : matches) {
|
|
|
|
File file = match.getCandidate();
|
|
|
|
Object meta = match.getValue();
|
|
|
|
if (renameMap.containsKey(file) && meta != null) {
|
|
|
|
File destination = resolveDestination(file, renameMap.get(file), false);
|
|
|
|
if (destination.isFile()) {
|
2014-01-25 22:51:47 -05:00
|
|
|
MediaDetection.storeMetaInfo(destination, meta, file.getName(), useExtendedFileAttributes(), useCreationDate());
|
2014-01-08 12:23:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Throwable e) {
|
|
|
|
Logger.getLogger(RenameAction.class.getName()).warning("Failed to write xattr: " + e.getMessage());
|
|
|
|
}
|
|
|
|
}
|
2012-08-13 01:58:27 -04:00
|
|
|
} catch (ExecutionException e) {
|
|
|
|
// ignore, handled in rename worker
|
2012-07-19 23:38:47 -04:00
|
|
|
} catch (Throwable e) {
|
2011-11-20 16:32:24 -05:00
|
|
|
UILogger.log(Level.WARNING, e.getMessage(), e);
|
2009-05-17 16:58:20 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-11 10:51:50 -05:00
|
|
|
window.setCursor(Cursor.getDefaultCursor());
|
2011-11-04 03:45:48 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
public boolean isNativeActionSupported(StandardRenameAction action) {
|
|
|
|
try {
|
|
|
|
return NativeRenameAction.isSupported() && NativeRenameAction.valueOf(action.name()) != null;
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2014-08-08 13:05:10 -04:00
|
|
|
private Map<File, File> checkRenamePlan(List<Entry<File, File>> renamePlan, Window parent) throws IOException {
|
|
|
|
// ask for user permissions to output paths
|
|
|
|
if (isMacSandbox()) {
|
2014-08-28 15:23:28 -04:00
|
|
|
if (!DropToUnlock.showUnlockFoldersDialog(parent, renamePlan.stream().flatMap(e -> Stream.of(e.getKey(), resolveDestination(e.getKey(), e.getValue()))).map(f -> new File(f.getAbsolutePath())).collect(Collectors.toList()))) {
|
2014-08-08 13:05:10 -04:00
|
|
|
return emptyMap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// build rename map and perform some sanity checks
|
|
|
|
Map<File, File> renameMap = new HashMap<File, File>();
|
2012-03-07 09:26:47 -05:00
|
|
|
Set<File> destinationSet = new HashSet<File>();
|
2013-02-08 10:35:23 -05:00
|
|
|
List<String> issues = new ArrayList<String>();
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
for (Entry<File, File> mapping : renamePlan) {
|
|
|
|
File source = mapping.getKey();
|
|
|
|
File destination = mapping.getValue();
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// resolve destination
|
|
|
|
if (!destination.isAbsolute()) {
|
|
|
|
// same folder, different name
|
|
|
|
destination = new File(source.getParentFile(), destination.getPath());
|
2011-09-21 09:29:21 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
try {
|
|
|
|
if (renameMap.containsKey(source))
|
|
|
|
throw new IllegalArgumentException("Duplicate source file: " + source.getPath());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
if (destinationSet.contains(destination))
|
|
|
|
throw new IllegalArgumentException("Conflict detected: " + mapping.getValue().getPath());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-04-13 02:14:38 -04:00
|
|
|
if (destination.exists() && !resolveDestination(mapping.getKey(), mapping.getValue(), false).equals(mapping.getKey()))
|
|
|
|
throw new IllegalArgumentException("File already exists: " + mapping.getValue().getPath());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2014-02-17 06:44:59 -05:00
|
|
|
if (getExtension(destination) == null && destination.isFile())
|
2013-11-14 21:54:33 -05:00
|
|
|
throw new IllegalArgumentException("Missing extension: " + mapping.getValue().getPath());
|
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
// use original mapping values
|
|
|
|
renameMap.put(mapping.getKey(), mapping.getValue());
|
|
|
|
destinationSet.add(destination);
|
|
|
|
} catch (Exception e) {
|
|
|
|
issues.add(e.getMessage());
|
|
|
|
}
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
if (issues.size() > 0) {
|
2014-08-01 11:49:58 -04:00
|
|
|
String text = "These files will be ignored. Do you want to continue?";
|
2013-02-08 10:35:23 -05:00
|
|
|
JList issuesComponent = new JList(issues.toArray()) {
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
@Override
|
|
|
|
public Dimension getPreferredScrollableViewportSize() {
|
|
|
|
// adjust component size
|
|
|
|
return new Dimension(80, 80);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Object[] message = new Object[] { text, new JScrollPane(issuesComponent) };
|
|
|
|
String[] actions = new String[] { "Continue", "Cancel" };
|
|
|
|
JOptionPane pane = new JOptionPane(message, PLAIN_MESSAGE, YES_NO_OPTION, null, actions, actions[1]);
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
// display option dialog
|
|
|
|
pane.createDialog(getWindow(parent), "Conflicting Files").setVisible(true);
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-02-08 10:35:23 -05:00
|
|
|
if (pane.getValue() != actions[0]) {
|
|
|
|
return emptyMap();
|
|
|
|
}
|
2009-05-17 16:58:20 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
return renameMap;
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
private List<Entry<File, File>> validate(Map<File, String> renameMap, Window parent) {
|
2011-10-10 12:21:54 -04:00
|
|
|
final List<Entry<File, File>> source = new ArrayList<Entry<File, File>>(renameMap.size());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-10-10 12:21:54 -04:00
|
|
|
for (Entry<File, String> entry : renameMap.entrySet()) {
|
|
|
|
source.add(new SimpleEntry<File, File>(entry.getKey(), new File(entry.getValue())));
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-10-10 12:21:54 -04:00
|
|
|
List<File> destinationFileNameView = new AbstractList<File>() {
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-05-17 16:58:20 -04:00
|
|
|
@Override
|
2011-10-10 12:21:54 -04:00
|
|
|
public File get(int index) {
|
2009-07-20 07:03:24 -04:00
|
|
|
return source.get(index).getValue();
|
2009-05-17 16:58:20 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-05-17 16:58:20 -04:00
|
|
|
@Override
|
2011-10-10 12:21:54 -04:00
|
|
|
public File set(int index, File name) {
|
2009-07-20 07:03:24 -04:00
|
|
|
return source.get(index).setValue(name);
|
2009-05-17 16:58:20 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-05-17 16:58:20 -04:00
|
|
|
@Override
|
|
|
|
public int size() {
|
|
|
|
return source.size();
|
|
|
|
}
|
|
|
|
};
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-05-17 16:58:20 -04:00
|
|
|
if (ValidateDialog.validate(parent, destinationFileNameView)) {
|
|
|
|
// names have been validated via view
|
|
|
|
return source;
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2009-05-17 16:58:20 -04:00
|
|
|
// return empty list if validation was cancelled
|
|
|
|
return emptyList();
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
protected ProgressDialog createProgressDialog(Window parent, final RenameJob job) {
|
|
|
|
final ProgressDialog dialog = new ProgressDialog(parent, job);
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// configure dialog
|
2014-09-21 12:51:20 -04:00
|
|
|
dialog.setTitle("Processing files...");
|
2011-11-04 03:45:48 -04:00
|
|
|
dialog.setIcon((Icon) getValue(SMALL_ICON));
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// close progress dialog when worker is finished
|
|
|
|
job.addPropertyChangeListener(new SwingWorkerPropertyChangeAdapter() {
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
@Override
|
|
|
|
protected void event(String name, Object oldValue, Object newValue) {
|
|
|
|
if (name.equals("currentFile")) {
|
|
|
|
int i = job.renameLog.size();
|
|
|
|
int n = job.renameMap.size();
|
|
|
|
dialog.setNote(String.format("%d of %d", i + 1, n));
|
2014-09-21 12:51:20 -04:00
|
|
|
|
|
|
|
// OSX LaF progress bar may not display progress bar text in indeterminate mode
|
|
|
|
if (isMacApp()) {
|
|
|
|
dialog.setTitle("Processing files... " + String.format("%d of %d", i + 1, n));
|
|
|
|
}
|
|
|
|
|
2012-02-24 08:39:32 -05:00
|
|
|
if (newValue instanceof File) {
|
2014-09-21 12:51:20 -04:00
|
|
|
dialog.setWindowTitle("Processing " + ((File) oldValue).getName());
|
2012-02-24 08:39:32 -05:00
|
|
|
}
|
2011-11-04 03:45:48 -04:00
|
|
|
}
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
@Override
|
|
|
|
protected void done(PropertyChangeEvent evt) {
|
|
|
|
dialog.close();
|
|
|
|
}
|
|
|
|
});
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
return dialog;
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
protected class RenameJob extends SwingWorker<Map<File, File>, Void> implements Cancellable {
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2014-04-19 02:30:29 -04:00
|
|
|
protected final net.filebot.RenameAction action;
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
protected final Map<File, File> renameMap;
|
|
|
|
protected final Map<File, File> renameLog;
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
protected final Semaphore postprocess = new Semaphore(0);
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2014-04-19 02:30:29 -04:00
|
|
|
public RenameJob(Map<File, File> renameMap, net.filebot.RenameAction action) {
|
2012-07-12 07:23:23 -04:00
|
|
|
this.action = action;
|
2011-11-04 03:45:48 -04:00
|
|
|
this.renameMap = synchronizedMap(renameMap);
|
|
|
|
this.renameLog = synchronizedMap(new LinkedHashMap<File, File>());
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
@Override
|
|
|
|
protected Map<File, File> doInBackground() throws Exception {
|
2012-07-17 16:52:03 -04:00
|
|
|
try {
|
|
|
|
for (Entry<File, File> mapping : renameMap.entrySet()) {
|
|
|
|
if (isCancelled())
|
|
|
|
return renameLog;
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
// update progress dialog
|
|
|
|
firePropertyChange("currentFile", mapping.getKey(), mapping.getValue());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
// rename file, throw exception on failure
|
2013-03-23 08:34:15 -04:00
|
|
|
File source = mapping.getKey();
|
|
|
|
File destination = resolveDestination(mapping.getKey(), mapping.getValue(), false);
|
2014-04-16 10:37:52 -04:00
|
|
|
boolean isSameFile = source.equals(destination);
|
|
|
|
if (!isSameFile || (isSameFile && !source.getName().equals(destination.getName()))) {
|
2013-03-23 08:34:15 -04:00
|
|
|
action.rename(source, destination);
|
2012-07-24 13:34:53 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-19 23:38:47 -04:00
|
|
|
// remember successfully renamed matches for history entry and possible revert
|
2012-07-17 16:52:03 -04:00
|
|
|
renameLog.put(mapping.getKey(), mapping.getValue());
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
postprocess.release();
|
2011-11-04 03:45:48 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
return renameLog;
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
@Override
|
|
|
|
protected void done() {
|
|
|
|
try {
|
2012-07-17 16:52:03 -04:00
|
|
|
postprocess.acquire();
|
2012-07-26 04:40:20 -04:00
|
|
|
this.get(); // grab exception if any
|
|
|
|
} catch (Exception e) {
|
2012-08-13 01:58:27 -04:00
|
|
|
if (!isCancelled()) {
|
|
|
|
UILogger.log(Level.SEVERE, String.format("%s: %s", getRootCause(e).getClass().getSimpleName(), getRootCauseMessage(e)), e);
|
|
|
|
} else {
|
|
|
|
Logger.getLogger(RenameAction.class.getName()).log(Level.SEVERE, e.getMessage(), e);
|
|
|
|
}
|
2011-11-04 03:45:48 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// collect renamed types
|
2012-07-26 04:40:20 -04:00
|
|
|
final List<Class<?>> types = new ArrayList<Class<?>>();
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// remove renamed matches
|
|
|
|
for (File source : renameLog.keySet()) {
|
|
|
|
// find index of source file
|
|
|
|
int index = model.files().indexOf(source);
|
|
|
|
types.add(model.values().get(index).getClass());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// remove complete match
|
|
|
|
model.matches().remove(index);
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
if (renameLog.size() > 0) {
|
|
|
|
UILogger.info(String.format("%d files renamed.", renameLog.size()));
|
|
|
|
HistorySpooler.getInstance().append(renameLog.entrySet());
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
// count global statistics
|
2012-07-26 04:40:20 -04:00
|
|
|
for (Class<?> it : new HashSet<Class<?>>(types)) {
|
2011-11-04 03:45:48 -04:00
|
|
|
Analytics.trackEvent("GUI", "Rename", it.getSimpleName(), frequency(types, it));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2011-11-04 03:45:48 -04:00
|
|
|
@Override
|
|
|
|
public boolean cancel() {
|
|
|
|
return cancel(true);
|
|
|
|
}
|
2012-07-17 16:52:03 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
protected class NativeRenameJob extends RenameJob implements Cancellable {
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
public NativeRenameJob(Map<File, File> renameMap, NativeRenameAction action) {
|
|
|
|
super(renameMap, action);
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
@Override
|
|
|
|
protected Map<File, File> doInBackground() throws Exception {
|
|
|
|
NativeRenameAction shell = (NativeRenameAction) action;
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2013-03-23 08:34:15 -04:00
|
|
|
// prepare delta, ignore files already named as desired
|
|
|
|
Map<File, File> todo = new LinkedHashMap<File, File>();
|
|
|
|
for (Entry<File, File> mapping : renameMap.entrySet()) {
|
|
|
|
File source = mapping.getKey();
|
|
|
|
File destination = resolveDestination(mapping.getKey(), mapping.getValue(), false);
|
|
|
|
if (!source.equals(destination)) {
|
|
|
|
todo.put(source, destination);
|
|
|
|
}
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
// call native shell move/copy
|
|
|
|
try {
|
2013-03-23 08:34:15 -04:00
|
|
|
shell.rename(todo);
|
2012-07-17 16:52:03 -04:00
|
|
|
} catch (CancellationException e) {
|
|
|
|
// set as cancelled and propagate the exception
|
|
|
|
super.cancel(false);
|
|
|
|
throw e;
|
|
|
|
} finally {
|
2012-07-19 23:38:47 -04:00
|
|
|
// check status of renamed files
|
2012-07-17 16:52:03 -04:00
|
|
|
for (Entry<File, File> it : renameMap.entrySet()) {
|
2012-08-13 01:58:27 -04:00
|
|
|
if (resolveDestination(it.getKey(), it.getValue(), false).exists()) {
|
2012-07-17 16:52:03 -04:00
|
|
|
renameLog.put(it.getKey(), it.getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
postprocess.release();
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
return renameLog;
|
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2012-07-17 16:52:03 -04:00
|
|
|
@Override
|
|
|
|
public boolean cancel() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
2011-11-04 03:45:48 -04:00
|
|
|
}
|
2013-09-30 00:46:33 -04:00
|
|
|
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|