* added persistent rename history
* renamed some setting keys
This commit is contained in:
parent
049ae3e8ef
commit
63f5f4ba26
|
@ -39,8 +39,8 @@
|
|||
|
||||
Subdirectories can be specified below the property e.g. java.io.tmpdir/one
|
||||
-->
|
||||
<diskStore path="java.io.tmpdir/filebot-ehcache" />
|
||||
|
||||
<diskStore path="java.io.tmpdir/filebot-cache" />
|
||||
|
||||
<!--
|
||||
Cache configuration
|
||||
===================
|
||||
|
@ -114,9 +114,7 @@
|
|||
timeToIdleSeconds="120"
|
||||
timeToLiveSeconds="120"
|
||||
overflowToDisk="false"
|
||||
maxElementsOnDisk="1000"
|
||||
diskPersistent="false"
|
||||
diskExpiryThreadIntervalSeconds="120"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
||||
|
@ -129,6 +127,7 @@
|
|||
eternal="false"
|
||||
timeToIdleSeconds="300"
|
||||
timeToLiveSeconds="300"
|
||||
overflowToDisk="false"
|
||||
diskPersistent="false"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
@ -141,7 +140,8 @@
|
|||
maxElementsInMemory="4200"
|
||||
eternal="false"
|
||||
timeToIdleSeconds="7200"
|
||||
timeToLiveSeconds="7200"
|
||||
timeToLiveSeconds="7200"
|
||||
overflowToDisk="false"
|
||||
diskPersistent="false"
|
||||
memoryStoreEvictionPolicy="LRU"
|
||||
/>
|
||||
|
|
|
@ -90,7 +90,7 @@ public abstract class AbstractSearchPanel<S, E> extends JComponent {
|
|||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
getSettings().put("search", Integer.toString(searchTextField.getSelectButton().getSelectedIndex()));
|
||||
getSettings().put("engine.selected", Integer.toString(searchTextField.getSelectButton().getSelectedIndex()));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -368,7 +368,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
private void checkFormatInBackground() {
|
||||
try {
|
||||
// check syntax in foreground
|
||||
final ExpressionFormat format = new ExpressionFormat(editor.getText().trim());
|
||||
final ExpressionFormat format = new ExpressionFormat(getExpression());
|
||||
|
||||
// format in background
|
||||
final Timer progressIndicatorTimer = TunedUtilities.invokeLater(400, new Runnable() {
|
||||
|
@ -430,7 +430,7 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
|
||||
|
||||
public String getExpression() {
|
||||
return editor.getText();
|
||||
return editor.getText().trim();
|
||||
}
|
||||
|
||||
|
||||
|
@ -473,10 +473,10 @@ public class EpisodeFormatDialog extends JDialog {
|
|||
throw new IllegalStateException("Format has not been verified yet.");
|
||||
|
||||
// check syntax
|
||||
new ExpressionFormat(editor.getText());
|
||||
ExpressionFormat format = new ExpressionFormat(getExpression());
|
||||
|
||||
// remember format
|
||||
Settings.userRoot().put("dialog.format", editor.getText());
|
||||
Settings.userRoot().put("dialog.format", format.getExpression());
|
||||
|
||||
finish(Option.APPROVE);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -52,7 +52,7 @@ public class MainFrame extends JFrame {
|
|||
|
||||
private HeaderPanel headerPanel = new HeaderPanel();
|
||||
|
||||
private final PreferencesEntry<Integer> persistentSelectedPanel = Settings.userRoot().entry("selectedPanel", SimpleAdapter.forClass(Integer.class));
|
||||
private final PreferencesEntry<Integer> persistentSelectedPanel = Settings.userRoot().entry("panel.selected", SimpleAdapter.forClass(Integer.class));
|
||||
|
||||
|
||||
public MainFrame() {
|
||||
|
|
|
@ -58,6 +58,7 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListProvider, E
|
|||
|
||||
// add after text field
|
||||
add(seasonSpinner, 1);
|
||||
|
||||
// add after tabbed pane
|
||||
tabbedPaneGroup.add(new JButton(new SaveAction(new SelectedTabExportHandler())));
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
|
||||
@XmlRootElement(name = "history")
|
||||
class History {
|
||||
|
||||
@XmlElement(name = "sequence")
|
||||
private List<Sequence> sequences = new ArrayList<Sequence>();
|
||||
|
||||
|
||||
public static class Sequence {
|
||||
|
||||
@XmlAttribute(name = "date", required = true)
|
||||
private Date date;
|
||||
|
||||
@XmlElement(name = "rename", required = true)
|
||||
private List<Element> elements;
|
||||
|
||||
|
||||
private Sequence() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
|
||||
public Date date() {
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
public List<Element> elements() {
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Element {
|
||||
|
||||
@XmlAttribute(name = "dir", required = true)
|
||||
private File dir;
|
||||
|
||||
@XmlAttribute(name = "from", required = true)
|
||||
private String from;
|
||||
|
||||
@XmlAttribute(name = "to", required = true)
|
||||
private String to;
|
||||
|
||||
|
||||
private Element() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
|
||||
public File dir() {
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
public File from() {
|
||||
return new File(dir, from);
|
||||
}
|
||||
|
||||
|
||||
public File to() {
|
||||
return new File(dir, to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Sequence> sequences() {
|
||||
return Collections.unmodifiableList(sequences);
|
||||
}
|
||||
|
||||
|
||||
public void add(Iterable<Entry<File, File>> elements) {
|
||||
Sequence sequence = new Sequence();
|
||||
|
||||
sequence.date = new Date();
|
||||
sequence.elements = new ArrayList<Element>();
|
||||
|
||||
for (Entry<File, File> entry : elements) {
|
||||
File from = entry.getKey();
|
||||
File to = entry.getValue();
|
||||
|
||||
// sanity check, parent folder must be the same for both files
|
||||
if (!from.getParentFile().equals(to.getParentFile())) {
|
||||
throw new IllegalArgumentException(String.format("Illegal entry: ", entry));
|
||||
}
|
||||
|
||||
Element element = new Element();
|
||||
|
||||
element.dir = from.getParentFile();
|
||||
element.from = from.getName();
|
||||
element.to = to.getName();
|
||||
|
||||
sequence.elements.add(element);
|
||||
}
|
||||
|
||||
sequences.add(sequence);
|
||||
}
|
||||
|
||||
|
||||
public void add(History other) {
|
||||
this.sequences.addAll(other.sequences);
|
||||
}
|
||||
|
||||
|
||||
public int size() {
|
||||
return sequences.size();
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
sequences.clear();
|
||||
}
|
||||
|
||||
|
||||
public void store(File file) throws JAXBException {
|
||||
Marshaller marshaller = JAXBContext.newInstance(History.class).createMarshaller();
|
||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
||||
|
||||
marshaller.marshal(this, file);
|
||||
}
|
||||
|
||||
|
||||
public void load(File file) throws JAXBException {
|
||||
Unmarshaller unmarshaller = JAXBContext.newInstance(History.class).createUnmarshaller();
|
||||
|
||||
History history = ((History) unmarshaller.unmarshal(file));
|
||||
|
||||
clear();
|
||||
add(history);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
final class HistorySpooler {
|
||||
|
||||
private static final HistorySpooler instance = new HistorySpooler();
|
||||
|
||||
|
||||
public static HistorySpooler getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final History sessionHistory = new History();
|
||||
|
||||
private final File file = new File("history.xml");
|
||||
|
||||
|
||||
public synchronized History getHistory() {
|
||||
History history = new History();
|
||||
|
||||
// add persistent history
|
||||
if (file.exists()) {
|
||||
try {
|
||||
history.load(file);
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger("global").log(Level.SEVERE, "Failed to load history", e);
|
||||
}
|
||||
}
|
||||
|
||||
// add session history
|
||||
history.add(sessionHistory);
|
||||
|
||||
return history;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void append(Collection<Entry<File, File>> elements) {
|
||||
if (elements.isEmpty())
|
||||
return;
|
||||
|
||||
// append to session history
|
||||
sessionHistory.add(elements);
|
||||
}
|
||||
|
||||
|
||||
public synchronized void commit() {
|
||||
if (sessionHistory.size() > 0) {
|
||||
try {
|
||||
getHistory().store(file);
|
||||
|
||||
// clear session history
|
||||
sessionHistory.clear();
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger("global").log(Level.SEVERE, "Failed to store history", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private HistorySpooler() {
|
||||
// commit session history on shutdown
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
commit();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -6,8 +6,8 @@ import java.awt.event.ActionEvent;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -49,16 +49,21 @@ class RenameAction extends AbstractAction {
|
|||
// could not rename one of the files, revert all changes
|
||||
Logger.getLogger("ui").warning(e.getMessage());
|
||||
|
||||
// revert in reverse order
|
||||
Collections.reverse(renameLog);
|
||||
|
||||
// revert rename operations
|
||||
for (Entry<File, File> mapping : renameLog) {
|
||||
if (!mapping.getValue().renameTo(mapping.getKey())) {
|
||||
// revert rename operations in reverse order
|
||||
for (ListIterator<Entry<File, File>> iterator = renameLog.listIterator(renameLog.size()); iterator.hasPrevious();) {
|
||||
Entry<File, File> mapping = iterator.previous();
|
||||
|
||||
if (mapping.getValue().renameTo(mapping.getKey())) {
|
||||
// remove reverted rename operation from log
|
||||
iterator.remove();
|
||||
} else {
|
||||
// failed to revert rename operation
|
||||
Logger.getLogger("ui").severe(String.format("Failed to revert file: \"%s\".", mapping.getValue().getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update history
|
||||
HistorySpooler.getInstance().append(renameLog);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import net.sourceforge.filebot.web.TheTVDBClient;
|
|||
import net.sourceforge.tuned.ExceptionUtilities;
|
||||
import net.sourceforge.tuned.PreferencesMap.AbstractAdapter;
|
||||
import net.sourceforge.tuned.PreferencesMap.PreferencesEntry;
|
||||
import net.sourceforge.tuned.PreferencesMap.SimpleAdapter;
|
||||
import net.sourceforge.tuned.ui.ActionPopup;
|
||||
import net.sourceforge.tuned.ui.LoadingOverlayPane;
|
||||
import ca.odell.glazedlists.ListSelection;
|
||||
|
@ -68,6 +69,8 @@ public class RenamePanel extends JComponent {
|
|||
|
||||
protected final RenameAction renameAction = new RenameAction(renameModel);
|
||||
|
||||
private final PreferencesEntry<Boolean> persistentPreserveExtension = Settings.userRoot().entry("rename.extension.preserve", SimpleAdapter.forClass(Boolean.class));
|
||||
|
||||
|
||||
public RenamePanel() {
|
||||
namesList.setTitle("New Names");
|
||||
|
@ -76,8 +79,13 @@ public class RenamePanel extends JComponent {
|
|||
filesList.setTitle("Original Files");
|
||||
filesList.setTransferablePolicy(new FilesListTransferablePolicy(renameModel.files()));
|
||||
|
||||
// restore state
|
||||
renameModel.setPreserveExtension(Boolean.valueOf(Settings.userRoot().get("rename.preserveExtension", "true")));
|
||||
try {
|
||||
// restore state
|
||||
renameModel.setPreserveExtension(persistentPreserveExtension.getValue());
|
||||
} catch (Exception e) {
|
||||
// preserve extension by default
|
||||
renameModel.setPreserveExtension(true);
|
||||
}
|
||||
|
||||
// filename formatter
|
||||
renameModel.useFormatter(File.class, new FileNameFormatter(renameModel.preserveExtension()));
|
||||
|
@ -227,9 +235,8 @@ public class RenamePanel extends JComponent {
|
|||
filesList.repaint();
|
||||
|
||||
// save state
|
||||
Settings.userRoot().put("rename.preserveExtension", Boolean.toString(activate));
|
||||
persistentPreserveExtension.setValue(activate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -340,7 +347,7 @@ public class RenamePanel extends JComponent {
|
|||
}
|
||||
}
|
||||
|
||||
protected final PreferencesEntry<EpisodeExpressionFormatter> persistentFormatExpression = Settings.userRoot().entry("rename.format", new AbstractAdapter<EpisodeExpressionFormatter>() {
|
||||
private final PreferencesEntry<EpisodeExpressionFormatter> persistentFormatExpression = Settings.userRoot().entry("rename.format", new AbstractAdapter<EpisodeExpressionFormatter>() {
|
||||
|
||||
@Override
|
||||
public EpisodeExpressionFormatter get(Preferences prefs, String key) {
|
||||
|
|
Loading…
Reference in New Issue