* make all file choosers compatible with the mas sandbox

This commit is contained in:
Reinhard Pointner 2014-07-28 19:20:55 +00:00
parent 95c8496bfb
commit 88008a2b0f
21 changed files with 346 additions and 351 deletions

View File

@ -248,8 +248,7 @@
<option value="-Xdock:name=${title}" />
<option value="-Xdock:icon=Contents/Resources/filebot.icns" />
<option value="-Dcom.apple.macos.use-file-dialog-packages=true" />
<option value="-Dcom.apple.macos.useScreenMenuBar=true" />
<option value="-Dapple.laf.useScreenMenuBar=true" />
</bundleapp>
<!-- application bundle folder as .tar.gz -->
@ -280,11 +279,9 @@
<option value="-Dapplication.cache=./Library/Caches/ehcache.disk.store" />
<option value="-Djava.io.tmpdir=./Library/Caches/java.io.tmpdir" />
<!-- FULL DIRECTORY ACCESS when processing files in the sandbox -->
<option value="-Dapple.awt.fileDialogForDirectories=true" />
<option value="-Dapplication.deployment=mas" />
<option value="-Dapplication.update=skip" />
<option value="-Dapplication.analytics=false" />
<option value="-Dunixfs=false" />
<option value="-DuseExtendedFileAttributes=true" />
<option value="-DuseCreationDate=false" />
@ -301,8 +298,10 @@
<option value="-Xdock:name=${title}" />
<option value="-Xdock:icon=Contents/Resources/filebot.icns" />
<option value="-Dcom.apple.macos.use-file-dialog-packages=true" />
<option value="-Dcom.apple.macos.useScreenMenuBar=true" />
<option value="-Dapple.laf.useScreenMenuBar=true" />
<argument value="--log-file" />
<argument value="filebot.log" />
</bundleapp>
</target>

View File

@ -5,6 +5,7 @@ import static net.filebot.util.XPathUtilities.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -30,7 +31,7 @@ public class MediaTypes {
private static MediaTypes parseDefault() {
try {
Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(MediaTypes.class.getResourceAsStream("media.types"));
Map<String, List<String>> types = new HashMap<String, List<String>>();
Map<String, List<String>> types = new LinkedHashMap<String, List<String>>();
for (Node it : getChildren("type", dom.getFirstChild())) {
List<String> extensions = new ArrayList<String>(2);
@ -94,6 +95,14 @@ public class MediaTypes {
return getDefault().getFilter(name);
}
public static ExtensionFileFilter combineFilter(ExtensionFileFilter... filters) {
List<String> extensions = new ArrayList<String>();
for (ExtensionFileFilter it : filters) {
addAll(extensions, it.extensions());
}
return new ExtensionFileFilter(extensions);
}
// some convenience filters
public static final ExtensionFileFilter AUDIO_FILES = getDefaultFilter("audio");
public static final ExtensionFileFilter VIDEO_FILES = getDefaultFilter("video");

View File

@ -63,7 +63,7 @@ public final class Settings {
}
public static boolean isSandboxed() {
return "mas".equals(System.getProperty("application.deployment"));
return "mas".equals(getApplicationDeployment());
}
public static int getPreferredThreadPoolSize() {

View File

@ -6,7 +6,6 @@ import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.ui.TunedUtilities.*;
import java.awt.Color;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.io.File;
@ -22,7 +21,6 @@ import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
@ -31,6 +29,7 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.archive.Archive;
import net.filebot.archive.FileMapper;
import net.filebot.util.FileUtilities;
@ -110,21 +109,15 @@ class ExtractTool extends Tool<TableModel> {
@Override
public void actionPerformed(ActionEvent evt) {
final List<File> archives = ((ArchiveEntryModel) table.getModel()).getArchiveList();
if (archives.isEmpty()) {
if (archives.isEmpty())
return;
}
Window window = getWindow(evt.getSource());
JFileChooser chooser = new JFileChooser(archives.get(0).getParentFile());
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
if (chooser.showSaveDialog(window) != JFileChooser.APPROVE_OPTION) {
File selectedFile = showOpenDialogSelectFolder(archives.get(0).getParentFile(), "Extract to ...", evt.getSource(), Settings.isSandboxed());
if (selectedFile == null)
return;
}
final ExtractJob job = new ExtractJob(archives, chooser.getSelectedFile());
final ProgressDialog dialog = new ProgressDialog(window, job);
final ExtractJob job = new ExtractJob(archives, selectedFile);
final ProgressDialog dialog = new ProgressDialog(getWindow(evt.getSource()), job);
dialog.setLocation(getOffsetLocation(dialog.getOwner()));
dialog.setTitle("Extracting files...");
dialog.setIcon((Icon) getValue(SMALL_ICON));

View File

@ -91,7 +91,7 @@ class FileTreeTransferablePolicy extends BackgroundFileTransferablePolicy<TreeNo
@Override
public String getFileFilterDescription() {
return "folders";
return "Folders";
}
}

View File

@ -74,7 +74,7 @@ class FileListTransferablePolicy extends FileTransferablePolicy {
@Override
public String getFileFilterDescription() {
return "files, folders and torrents";
return "Files, Folders and Torrents";
}
}

View File

@ -15,7 +15,6 @@ import java.text.Format;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -33,7 +32,6 @@ import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
@ -44,13 +42,13 @@ import javax.swing.RowFilter;
import javax.swing.SwingWorker;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.format.ExpressionFormat;
import net.filebot.format.MediaBindingBean;
import net.filebot.media.MediaDetection;
@ -58,6 +56,7 @@ import net.filebot.mediainfo.MediaInfo;
import net.filebot.mediainfo.MediaInfo.StreamKind;
import net.filebot.mediainfo.MediaInfoException;
import net.filebot.util.DefaultThreadFactory;
import net.filebot.util.FileUtilities.ExtensionFileFilter;
import net.filebot.util.ui.LazyDocumentListener;
import net.miginfocom.swing.MigLayout;
@ -351,31 +350,19 @@ class BindingDialog extends JDialog {
};
protected final Action selectFileAction = new AbstractAction("Select File", ResourceManager.getIcon("action.load")) {
protected final Action selectFileAction = new AbstractAction("Select Media File", ResourceManager.getIcon("action.load")) {
@Override
public void actionPerformed(ActionEvent evt) {
JFileChooser chooser = new JFileChooser();
chooser.setSelectedFile(getMediaFile());
ExtensionFileFilter mediaFiles = combineFilter(VIDEO_FILES, AUDIO_FILES, SUBTITLE_FILES);
File[] file = showLoadDialogSelectFiles(false, false, getMediaFile(), mediaFiles, (String) getValue(NAME), evt.getSource(), Settings.isSandboxed());
// collect media file extensions (video, audio and subtitle files)
List<String> extensions = new ArrayList<String>();
Collections.addAll(extensions, VIDEO_FILES.extensions());
Collections.addAll(extensions, AUDIO_FILES.extensions());
Collections.addAll(extensions, SUBTITLE_FILES.extensions());
chooser.setFileFilter(new FileNameExtensionFilter("Media files", extensions.toArray(new String[0])));
chooser.setMultiSelectionEnabled(false);
if (chooser.showOpenDialog(getWindow(evt.getSource())) == JFileChooser.APPROVE_OPTION) {
if (file.length > 0) {
// update text field
File file = chooser.getSelectedFile();
// set file
mediaFileTextField.setText(file.getAbsolutePath());
mediaFileTextField.setText(file[0].getAbsolutePath());
// set info object from xattr if possible
Object object = MediaDetection.readMetaInfo(file);
Object object = MediaDetection.readMetaInfo(file[0]);
if (object != null && infoObjectFormat.format(object) != null) {
setInfoObject(object);
}

View File

@ -100,7 +100,7 @@ class FilesListTransferablePolicy extends BackgroundFileTransferablePolicy<File>
@Override
public String getFileFilterDescription() {
return "files and folders";
return "Files and Folders";
}
@Override

View File

@ -5,6 +5,7 @@ import static java.util.Collections.*;
import static java.util.regex.Pattern.*;
import static javax.swing.JOptionPane.*;
import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.ui.TunedUtilities.*;
import java.awt.Color;
import java.awt.Component;
@ -39,7 +40,6 @@ import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
@ -459,7 +459,7 @@ class HistoryDialog extends JDialog {
}
@Override
public void actionPerformed(ActionEvent e) {
public void actionPerformed(ActionEvent evt) {
List<Element> elements = elements();
if (elements.isEmpty())
return;
@ -515,13 +515,7 @@ class HistoryDialog extends JDialog {
// change directory option
if (selectedOption == Option.ChangeDirectory) {
JFileChooser chooser = new JFileChooser(directory);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
directory = chooser.getSelectedFile();
}
directory = showOpenDialogSelectFolder(directory, selectedOption.toString(), evt.getSource(), Settings.isSandboxed());
}
}
@ -625,7 +619,7 @@ class HistoryDialog extends JDialog {
@Override
public String getFileFilterDescription() {
return "history files (.xml)";
return "History Files (.xml)";
}
};

View File

@ -152,7 +152,7 @@ class NamesListTransferablePolicy extends FileTransferablePolicy {
@Override
public String getFileFilterDescription() {
return "text files, verification files, torrent files";
return "Text Files, Verification Files, Torrent Files";
}
}

View File

@ -168,7 +168,7 @@ class ChecksumTableTransferablePolicy extends BackgroundFileTransferablePolicy<C
@Override
public String getFileFilterDescription() {
return "files, folders and sfv files";
return "Files, Folders and SFV Files";
}
private static class VerificationTracker {

View File

@ -1,7 +1,5 @@
package net.filebot.ui.subtitle;
import static javax.swing.BorderFactory.*;
import java.awt.Color;
@ -15,17 +13,15 @@ import javax.swing.plaf.basic.ComboPopup;
import net.filebot.ResourceManager;
public class SimpleComboBox extends JComboBox {
public SimpleComboBox() {
setUI(new SimpleComboBoxUI());
setBorder(createEmptyBorder());
}
private static class SimpleComboBoxUI extends BasicComboBoxUI {
@Override
protected JButton createArrowButton() {
JButton button = new JButton(ResourceManager.getIcon("arrow.down"));
@ -33,38 +29,37 @@ public class SimpleComboBox extends JComboBox {
button.setBorderPainted(false);
button.setFocusPainted(false);
button.setOpaque(false);
return button;
}
@Override
protected ComboPopup createPopup() {
return new BasicComboPopup(comboBox) {
@Override
protected Rectangle computePopupBounds(int px, int py, int pw, int ph) {
Rectangle bounds = super.computePopupBounds(px, py, pw, ph);
// allow combobox popup to be wider than the combobox itself
bounds.width = Math.max(bounds.width, list.getPreferredSize().width);
return bounds;
}
@Override
protected void configurePopup() {
super.configurePopup();
setOpaque(true);
setBackground(list.getBackground());
list.setBackground(Color.white);
setBackground(Color.white);
// use gray instead of black border for combobox popup
setBorder(createCompoundBorder(createLineBorder(Color.gray, 1), createEmptyBorder(1, 1, 1, 1)));
}
};
}
}
}

View File

@ -35,6 +35,7 @@ import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
@ -168,6 +169,7 @@ class SubtitleAutoMatchDialog extends JDialog {
protected void addSubtitleService(final SubtitleServiceBean service, final JPanel servicePanel) {
final LinkButton component = new LinkButton(service.getName(), ResourceManager.getIcon("database"), service.getLink());
component.setBorder(BorderFactory.createEmptyBorder());
component.setVisible(false);
service.addPropertyChangeListener(new PropertyChangeListener() {
@ -351,6 +353,7 @@ class SubtitleAutoMatchDialog extends JDialog {
private final JComboBox optionComboBox = new SimpleComboBox();
public SubtitleMappingOptionRenderer() {
optionComboBox.setBackground(Color.white);
optionComboBox.setRenderer(new SubtitleOptionRenderer(false));
}

View File

@ -1,7 +1,5 @@
package net.filebot.ui.subtitle;
import static net.filebot.MediaTypes.*;
import static net.filebot.subtitle.SubtitleUtilities.*;
import static net.filebot.ui.NotificationLogging.*;
@ -17,6 +15,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CancellationException;
@ -41,6 +40,7 @@ import javax.swing.border.LineBorder;
import net.filebot.Analytics;
import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.subtitle.SubtitleFormat;
import net.filebot.ui.subtitle.SubtitlePackage.Download.Phase;
import net.filebot.ui.transfer.DefaultTransferHandler;
@ -62,180 +62,169 @@ import ca.odell.glazedlists.swing.EventListModel;
import ca.odell.glazedlists.swing.EventSelectionModel;
import ca.odell.glazedlists.swing.TextComponentMatcherEditor;
class SubtitleDownloadComponent extends JComponent {
private EventList<SubtitlePackage> packages = new BasicEventList<SubtitlePackage>();
private EventList<MemoryFile> files = new BasicEventList<MemoryFile>();
private SubtitlePackageCellRenderer renderer = new SubtitlePackageCellRenderer();
private JTextField filterEditor = new JTextField();
public SubtitleDownloadComponent() {
final JList packageList = new JList(createPackageListModel());
packageList.setFixedCellHeight(32);
packageList.setCellRenderer(renderer);
// better selection behaviour
EventSelectionModel<SubtitlePackage> packageSelection = new EventSelectionModel<SubtitlePackage>(packages);
packageSelection.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE);
packageList.setSelectionModel(packageSelection);
// context menu and fetch on double click
packageList.addMouseListener(packageListMouseHandler);
// file list view
final JList fileList = new ListView(createFileListModel()) {
@Override
protected String convertValueToText(Object value) {
MemoryFile file = (MemoryFile) value;
return file.getName();
}
@Override
protected Icon convertValueToIcon(Object value) {
if (SUBTITLE_FILES.accept(value.toString()))
return ResourceManager.getIcon("file.subtitle");
return ResourceManager.getIcon("file.unknown");
}
};
// better selection behaviour
EventSelectionModel<MemoryFile> fileSelection = new EventSelectionModel<MemoryFile>(files);
fileSelection.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE);
fileList.setSelectionModel(fileSelection);
// install dnd and clipboard export handler
MemoryFileListExportHandler memoryFileExportHandler = new MemoryFileListExportHandler();
fileList.setTransferHandler(new DefaultTransferHandler(null, memoryFileExportHandler, memoryFileExportHandler));
fileList.setDragEnabled(true);
fileList.addMouseListener(fileListMouseHandler);
JButton clearButton = new JButton(clearFilterAction);
clearButton.setOpaque(false);
setLayout(new MigLayout("nogrid, fill", "[fill]", "[pref!][fill]"));
add(new JLabel("Filter:"), "gap indent:push");
add(filterEditor, "wmin 120px, gap rel");
add(clearButton, "w 24px!, h 24px!");
add(new JScrollPane(packageList), "newline, hmin 80px");
JScrollPane scrollPane = new JScrollPane(fileList);
scrollPane.setViewportBorder(new LineBorder(fileList.getBackground()));
add(scrollPane, "newline, hmin max(80px, 30%)");
// install fetch action
TunedUtilities.installAction(packageList, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), new AbstractAction("Fetch") {
@Override
public void actionPerformed(ActionEvent e) {
fetch(packageList.getSelectedValues());
}
});
// install open action
TunedUtilities.installAction(fileList, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), new AbstractAction("Open") {
@Override
public void actionPerformed(ActionEvent e) {
open(fileList.getSelectedValues());
}
});
}
protected ListModel createPackageListModel() {
// allow filtering by language name and subtitle name
MatcherEditor<SubtitlePackage> matcherEditor = new TextComponentMatcherEditor<SubtitlePackage>(filterEditor, new TextFilterator<SubtitlePackage>() {
@Override
public void getFilterStrings(List<String> list, SubtitlePackage element) {
list.add(element.getLanguage().getName());
list.add(element.getName());
}
});
// source list
EventList<SubtitlePackage> source = getPackageModel();
// filter list
source = new FilterList<SubtitlePackage>(source, matcherEditor);
// listen to changes (e.g. download progress)
source = new ObservableElementList<SubtitlePackage>(source, GlazedLists.beanConnector(SubtitlePackage.class));
// as list model
return new EventListModel<SubtitlePackage>(source);
}
protected ListModel createFileListModel() {
// source list
EventList<MemoryFile> source = getFileModel();
// sort by name
source = new SortedList<MemoryFile>(source, new Comparator<MemoryFile>() {
@Override
public int compare(MemoryFile m1, MemoryFile m2) {
return m1.getName().compareToIgnoreCase(m2.getName());
}
});
// as list model
return new EventListModel<MemoryFile>(source);
}
public void reset() {
// cancel and reset download workers
for (SubtitlePackage subtitle : packages) {
subtitle.reset();
}
files.clear();
}
public EventList<SubtitlePackage> getPackageModel() {
return packages;
}
public EventList<MemoryFile> getFileModel() {
return files;
}
public void setLanguageVisible(boolean visible) {
renderer.getLanguageLabel().setVisible(visible);
}
private void fetch(Object[] selection) {
for (Object value : selection) {
fetch((SubtitlePackage) value);
}
}
private void fetch(final SubtitlePackage subtitle) {
if (subtitle.getDownload().isStarted()) {
// download has been started already
return;
}
// listen to download
subtitle.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == Phase.DONE) {
@ -247,27 +236,26 @@ class SubtitleDownloadComponent extends JComponent {
// ignore cancellation
} catch (Exception e) {
UILogger.log(Level.WARNING, ExceptionUtilities.getRootCauseMessage(e), e);
// reset download
subtitle.reset();
}
// listener no longer required
subtitle.removePropertyChangeListener(this);
}
}
});
// enqueue worker
subtitle.getDownload().start();
}
private void open(Object[] selection) {
try {
for (Object object : selection) {
MemoryFile file = (MemoryFile) object;
// only open subtitle files
if (SUBTITLE_FILES.accept(file.getName())) {
open(file);
@ -277,248 +265,222 @@ class SubtitleDownloadComponent extends JComponent {
UILogger.log(Level.WARNING, e.getMessage(), e);
}
}
private void open(MemoryFile file) throws IOException {
SubtitleViewer viewer = new SubtitleViewer(file.getName());
viewer.getTitleLabel().setText("Subtitle Viewer");
viewer.getInfoLabel().setText(file.getPath());
viewer.setData(decodeSubtitles(file));
viewer.setVisible(true);
}
private void save(Object[] selection) {
try {
if (selection.length == 1) {
// single file
MemoryFile file = (MemoryFile) selection[0];
JFileChooser fc = new JFileChooser();
fc.setSelectedFile(new File(validateFileName(file.getName())));
if (fc.showSaveDialog(getWindow(this)) == JFileChooser.APPROVE_OPTION) {
writeFile(file.getData(), fc.getSelectedFile());
}
} else {
// multiple files
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fc.showSaveDialog(getWindow(this)) == JFileChooser.APPROVE_OPTION) {
File folder = fc.getSelectedFile();
for (Object object : selection) {
MemoryFile file = (MemoryFile) object;
File destination = new File(folder, validateFileName(file.getName()));
writeFile(file.getData(), destination);
}
// multiple files
File outputFolder = showOpenDialogSelectFolder(null, "Save Subtitles", this, Settings.isSandboxed());
if (outputFolder != null) {
for (Object object : selection) {
MemoryFile file = (MemoryFile) object;
File destination = new File(outputFolder, validateFileName(file.getName()));
writeFile(file.getData(), destination);
}
}
} catch (IOException e) {
} catch (Exception e) {
UILogger.log(Level.WARNING, e.getMessage(), e);
}
}
private void export(Object[] selection) {
try {
if (selection.length == 1) {
// single file
MemoryFile file = (MemoryFile) selection[0];
SubtitleFileChooser sf = new SubtitleFileChooser();
// normalize name and auto-adjust extension
String ext = sf.getSelectedFormat().getFilter().extension();
String name = validateFileName(getNameWithoutExtension(file.getName()));
sf.setSelectedFile(new File(name + "." + ext));
if (sf.showSaveDialog(getWindow(this)) == JFileChooser.APPROVE_OPTION) {
SubtitleFormat targetFormat = sf.getSelectedFormat().getFilter().accept(file.getName()) ? null : sf.getSelectedFormat();
writeFile(exportSubtitles(file, targetFormat, sf.getTimingOffset(), sf.getSelectedEncoding()), sf.getSelectedFile());
}
File selectedOutputFolder = null;
// default values
SubtitleFormat selectedFormat = SubtitleFormat.SubRip;
long selectedTimingOffset = 0;
Charset selectedEncoding = Charset.forName("UTF-8");
// just use default values when we can't use a JFC with accessory component
if (Settings.isSandboxed()) {
// AWT
selectedOutputFolder = showOpenDialogSelectFolder(null, "Export Subtitles", this, Settings.isSandboxed());
} else {
// multiple files
SubtitleFileChooser sf = new SubtitleFileChooser();
sf.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (sf.showSaveDialog(getWindow(this)) == JFileChooser.APPROVE_OPTION) {
File folder = sf.getSelectedFile();
for (Object object : selection) {
MemoryFile file = (MemoryFile) object;
// normalize name and auto-adjust extension
String ext = sf.getSelectedFormat().getFilter().extension();
String name = validateFileName(getNameWithoutExtension(file.getName()));
File destination = new File(folder, name + "." + ext);
SubtitleFormat targetFormat = sf.getSelectedFormat().getFilter().accept(file.getName()) ? null : sf.getSelectedFormat();
writeFile(exportSubtitles(file, targetFormat, sf.getTimingOffset(), sf.getSelectedEncoding()), destination);
}
// Swing
SubtitleFileChooser sfc = new SubtitleFileChooser();
sfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (sfc.showSaveDialog(getWindow(this)) == JFileChooser.APPROVE_OPTION) {
selectedOutputFolder = sfc.getSelectedFile();
selectedFormat = sfc.getSelectedFormat();
selectedTimingOffset = sfc.getTimingOffset();
selectedEncoding = sfc.getSelectedEncoding();
}
}
} catch (IOException e) {
if (selectedOutputFolder != null) {
for (Object object : selection) {
MemoryFile file = (MemoryFile) object;
// normalize name and auto-adjust extension
String name = validateFileName(getNameWithoutExtension(file.getName()));
File destination = new File(selectedOutputFolder, name + "." + selectedFormat.getFilter().extension());
SubtitleFormat targetFormat = selectedFormat.getFilter().accept(file.getName()) ? null : selectedFormat; // check if format conversion is necessary
writeFile(exportSubtitles(file, targetFormat, selectedTimingOffset, selectedEncoding), destination);
}
}
} catch (Exception e) {
UILogger.log(Level.WARNING, e.getMessage(), e);
}
}
private final Action clearFilterAction = new AbstractAction(null, ResourceManager.getIcon("edit.clear")) {
@Override
public void actionPerformed(ActionEvent e) {
filterEditor.setText("");
}
};
private final MouseListener packageListMouseHandler = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// fetch on double click
if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) {
JList list = (JList) e.getSource();
fetch(list.getSelectedValues());
}
}
@Override
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
@Override
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
JList list = (JList) e.getSource();
int index = list.locationToIndex(e.getPoint());
if (index >= 0 && !list.isSelectedIndex(index)) {
// auto-select clicked element
list.setSelectedIndex(index);
}
final Object[] selection = list.getSelectedValues();
if (selection.length > 0) {
JPopupMenu contextMenu = new JPopupMenu();
JMenuItem item = contextMenu.add(new AbstractAction("Download", ResourceManager.getIcon("package.fetch")) {
@Override
public void actionPerformed(ActionEvent e) {
fetch(selection);
}
});
// disable menu item if all selected elements have been fetched already
item.setEnabled(isPending(selection));
contextMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
private boolean isPending(Object[] selection) {
for (Object value : selection) {
SubtitlePackage subtitle = (SubtitlePackage) value;
if (!subtitle.getDownload().isStarted()) {
// pending download found
return true;
}
}
return false;
}
};
private final MouseListener fileListMouseHandler = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// open on double click
if (SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) {
JList list = (JList) e.getSource();
// open selection
open(list.getSelectedValues());
}
}
@Override
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
@Override
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
JList list = (JList) e.getSource();
int index = list.locationToIndex(e.getPoint());
if (index >= 0 && !list.isSelectedIndex(index)) {
// auto-select clicked element
list.setSelectedIndex(index);
}
final Object[] selection = list.getSelectedValues();
if (selection.length > 0) {
JPopupMenu contextMenu = new JPopupMenu();
// Open
contextMenu.add(new AbstractAction("Open") {
contextMenu.add(new AbstractAction("Preview", ResourceManager.getIcon("action.find")) {
@Override
public void actionPerformed(ActionEvent evt) {
open(selection);
}
});
// Save As...
contextMenu.add(new AbstractAction("Save As...", ResourceManager.getIcon("action.save")) {
@Override
public void actionPerformed(ActionEvent evt) {
save(selection);
}
});
// Export...
contextMenu.add(new AbstractAction("Export...", ResourceManager.getIcon("action.export")) {
@Override
public void actionPerformed(ActionEvent evt) {
export(selection);
}
});
contextMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
};
}

View File

@ -1,5 +1,6 @@
package net.filebot.ui.subtitle;
import static java.util.Arrays.*;
import static net.filebot.MediaTypes.*;
import static net.filebot.media.MediaDetection.*;
import static net.filebot.ui.NotificationLogging.*;
@ -18,10 +19,7 @@ import java.awt.dnd.DropTargetEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -31,10 +29,9 @@ import java.util.logging.Level;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.util.FileUtilities;
import net.filebot.util.FileUtilities.ParentFilter;
import net.filebot.web.OpenSubtitlesClient;
@ -130,21 +127,12 @@ abstract class SubtitleDropTarget extends JButton {
@Override
public void actionPerformed(ActionEvent evt) {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setMultiSelectionEnabled(true);
// collect media file extensions (video and subtitle files)
List<String> extensions = new ArrayList<String>();
Collections.addAll(extensions, VIDEO_FILES.extensions());
Collections.addAll(extensions, SUBTITLE_FILES.extensions());
chooser.setFileFilter(new FileNameExtensionFilter("Media files", extensions.toArray(new String[0])));
File[] files = showLoadDialogSelectFiles(true, true, null, combineFilter(VIDEO_FILES, SUBTITLE_FILES), "Select Video Folder", evt.getSource(), Settings.isSandboxed());
if (chooser.showOpenDialog(getWindow(evt.getSource())) == JFileChooser.APPROVE_OPTION) {
List<File> files = Arrays.asList(chooser.getSelectedFiles());
if (getDropAction(files) != DropAction.Cancel) {
handleDrop(Arrays.asList(chooser.getSelectedFiles()));
if (files.length > 0) {
if (getDropAction(asList(files)) != DropAction.Cancel) {
handleDrop(asList(files));
}
}
}

View File

@ -35,7 +35,6 @@ import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
@ -43,7 +42,6 @@ import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.SwingWorker;
import javax.swing.event.CellEditorListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
@ -52,6 +50,7 @@ import javax.swing.table.TableCellRenderer;
import net.filebot.Analytics;
import net.filebot.Language;
import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.WebServices;
import net.filebot.media.MediaDetection;
import net.filebot.ui.LanguageComboBox;
@ -228,16 +227,11 @@ public class SubtitleUploadDialog extends JDialog {
SubtitleMappingTableModel model = (SubtitleMappingTableModel) table.getModel();
SubtitleMapping mapping = model.getData()[table.convertRowIndexToModel(row)];
JFileChooser chooser = new JFileChooser(mapping.getSubtitle().getParentFile());
chooser.setFileFilter(new FileNameExtensionFilter("Video files", VIDEO_FILES.extensions()));
chooser.setMultiSelectionEnabled(false);
if (chooser.showOpenDialog(getWindow(SubtitleUploadDialog.this)) == JFileChooser.APPROVE_OPTION) {
if (chooser.getSelectedFile() != null) {
mapping.setVideo(chooser.getSelectedFile());
mapping.setState(SubtitleMapping.Status.CheckPending);
startChecking();
}
File[] files = showLoadDialogSelectFiles(false, false, mapping.getSubtitle().getParentFile(), VIDEO_FILES, "Select Video File", getWindow(SubtitleUploadDialog.this), Settings.isSandboxed());
if (files.length > 0) {
mapping.setVideo(files[0]);
mapping.setState(SubtitleMapping.Status.CheckPending);
startChecking();
}
return null;
}

View File

@ -1,16 +1,15 @@
package net.filebot.ui.transfer;
import static net.filebot.ui.NotificationLogging.*;
import static net.filebot.util.ui.TunedUtilities.*;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JFileChooser;
import net.filebot.ResourceManager;
import net.filebot.Settings;
@ -56,52 +55,18 @@ public class LoadAction extends AbstractAction {
return;
}
File[] files = showSelectFiles(new TransferablePolicyFileFilter(transferablePolicy));
File[] files = showLoadDialogSelectFiles(true, true, getDefaultFolder(), new TransferablePolicyFileFilter(transferablePolicy), (String) getValue(Action.NAME), evt.getSource(), Settings.isSandboxed());
if (files == null || files.length == 0) {
return;
}
FileTransferable transferable = new FileTransferable(files);
if (transferablePolicy.accept(transferable)) {
transferablePolicy.handleTransferable(transferable, getTransferAction(evt));
}
} catch (Exception e) {
UILogger.log(Level.WARNING, e.getMessage(), e);
UILogger.log(Level.WARNING, e.toString(), e);
}
}
public File[] showSelectFiles(TransferablePolicyFileFilter fileFilter) {
if (Settings.isSandboxed()) {
Frame[] frames = Frame.getFrames();
Frame mainFrame = frames.length > 0 ? frames[0] : null;
FileDialog fileDialog = new FileDialog(mainFrame, "", FileDialog.LOAD);
File currentFolder = getDefaultFolder();
if (currentFolder != null) {
fileDialog.setDirectory(currentFolder.getPath());
}
fileDialog.setMultipleMode(true);
fileDialog.setVisible(true);
File[] files = fileDialog.getFiles();
if (files.length > 0) {
setDefaultFolder(new File(fileDialog.getDirectory()));
}
return files;
}
// use normal Swing JFileChooser by default
JFileChooser chooser = new JFileChooser(getDefaultFolder());
chooser.setFileFilter(fileFilter);
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setMultiSelectionEnabled(true);
if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
return null;
}
setDefaultFolder(chooser.getCurrentDirectory());
return chooser.getSelectedFiles();
}
}

View File

@ -1,8 +1,7 @@
package net.filebot.ui.transfer;
import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.ui.TunedUtilities.*;
import java.awt.event.ActionEvent;
import java.io.File;
@ -11,81 +10,69 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import net.filebot.ResourceManager;
import net.filebot.Settings;
public class SaveAction extends AbstractAction {
public static final String EXPORT_HANDLER = "exportHandler";
public SaveAction(FileExportHandler exportHandler) {
this("Save as ...", ResourceManager.getIcon("action.save"), exportHandler);
}
public SaveAction(String name, Icon icon, FileExportHandler exportHandler) {
putValue(NAME, name);
putValue(SMALL_ICON, icon);
putValue(EXPORT_HANDLER, exportHandler);
}
public FileExportHandler getExportHandler() {
return (FileExportHandler) getValue(EXPORT_HANDLER);
}
protected boolean canExport() {
return getExportHandler().canExport();
}
protected void export(File file) throws IOException {
getExportHandler().export(file);
}
protected String getDefaultFileName() {
return getExportHandler().getDefaultFileName();
}
protected File getDefaultFolder() {
String lastLocation = Settings.forPackage(SaveAction.class).get("save.location");
if (lastLocation == null || lastLocation.isEmpty())
return null;
return new File(lastLocation);
}
protected void setDefaultFolder(File folder) {
Settings.forPackage(LoadAction.class).put("save.location", folder.getPath());
}
public void actionPerformed(ActionEvent evt) {
if (!canExport())
return;
JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(false);
chooser.setSelectedFile(new File(getDefaultFolder(), validateFileName(getDefaultFileName())));
if (chooser.showSaveDialog((JComponent) evt.getSource()) != JFileChooser.APPROVE_OPTION)
return;
try {
export(chooser.getSelectedFile());
} catch (IOException e) {
if (canExport()) {
File defaultFile = new File(getDefaultFolder(), validateFileName(getDefaultFileName()));
File file = showSaveDialogSelectFile(false, defaultFile, (String) getValue(Action.NAME), evt.getSource(), Settings.isSandboxed());
if (file != null) {
setDefaultFolder(file.getParentFile());
export(file);
}
}
} catch (Exception e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.toString(), e);
}
// remember last location
Settings.forPackage(SaveAction.class).put("save.location", chooser.getCurrentDirectory().getPath());
}
}

View File

@ -32,11 +32,15 @@ public class TransferablePolicyFileFilter extends FileFilter implements Filename
@Override
public String getDescription() {
return this.toString();
}
@Override
public String toString() {
if (transferablePolicy instanceof FileTransferablePolicy) {
return ((FileTransferablePolicy) transferablePolicy).getFileFilterDescription();
}
return null;
return super.toString();
}
}

View File

@ -695,7 +695,7 @@ public final class FileUtilities {
}
}
public static class ExtensionFileFilter implements FileFilter {
public static class ExtensionFileFilter implements FileFilter, FilenameFilter {
private final String[] extensions;
@ -707,6 +707,11 @@ public final class FileUtilities {
this.extensions = extensions.toArray(new String[0]);
}
@Override
public boolean accept(File dir, String name) {
return hasExtension(name, extensions);
}
@Override
public boolean accept(File file) {
return hasExtension(file, extensions);
@ -732,6 +737,18 @@ public final class FileUtilities {
public String[] extensions() {
return extensions.clone();
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
for (String it : extensions) {
if (s.length() > 0) {
s.append(", ");
}
s.append("*.").append(it);
}
return s.toString();
}
}
public static class RegexFileFilter implements FileFilter, FilenameFilter {

View File

@ -5,7 +5,9 @@ import static javax.swing.JOptionPane.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Image;
@ -17,6 +19,8 @@ import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
@ -28,6 +32,7 @@ import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
@ -40,7 +45,98 @@ import javax.swing.undo.UndoManager;
public final class TunedUtilities {
public static final Color TRANSLUCENT = new Color(255, 255, 255, 0);
public static File[] showLoadDialogSelectFiles(boolean folderMode, boolean multiSelection, File defaultFile, final FilenameFilter filter, String title, Object parent, boolean useNative) {
if (useNative) {
FileDialog fileDialog = createFileDialog(parent, title, FileDialog.LOAD, folderMode);
if (defaultFile != null) {
fileDialog.setFile(defaultFile.getPath());
}
if (filter != null) {
fileDialog.setFilenameFilter(filter);
}
fileDialog.setMultipleMode(multiSelection);
fileDialog.setVisible(true);
return fileDialog.getFiles();
}
// use normal Swing JFileChooser by default
JFileChooser chooser = new JFileChooser();
if (filter != null) {
chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
@Override
public String getDescription() {
return filter.toString();
}
@Override
public boolean accept(File f) {
return f.isDirectory() || filter.accept(f.getParentFile(), f.getName());
}
});
}
chooser.setSelectedFile(defaultFile);
chooser.setFileSelectionMode(folderMode && filter == null ? JFileChooser.DIRECTORIES_ONLY : JFileChooser.FILES_AND_DIRECTORIES);
chooser.setMultiSelectionEnabled(multiSelection);
if (chooser.showOpenDialog(getWindow(parent)) == JFileChooser.APPROVE_OPTION) {
if (chooser.getSelectedFiles().length > 0)
return chooser.getSelectedFiles();
if (chooser.getSelectedFile() != null)
return new File[] { chooser.getSelectedFile() };
}
return new File[0];
}
public static File showOpenDialogSelectFolder(File defaultFile, String title, Object parent, boolean useNative) {
File[] folder = showLoadDialogSelectFiles(true, false, defaultFile, null, title, parent, useNative);
return folder.length > 0 ? folder[0] : null;
}
public static File showSaveDialogSelectFile(boolean folderMode, File defaultFile, String title, Object parent, boolean useNative) {
if (useNative) {
FileDialog fileDialog = createFileDialog(getWindow(parent), title, FileDialog.SAVE, folderMode);
if (defaultFile != null) {
if (defaultFile.getParentFile() != null) {
fileDialog.setDirectory(defaultFile.getParentFile().getPath());
}
fileDialog.setFile(defaultFile.getName());
}
fileDialog.setMultipleMode(false);
fileDialog.setVisible(true);
File[] files = fileDialog.getFiles();
return files.length > 0 ? files[0] : null;
}
JFileChooser chooser = new JFileChooser();
chooser.setSelectedFile(defaultFile);
chooser.setFileSelectionMode(folderMode ? JFileChooser.DIRECTORIES_ONLY : JFileChooser.FILES_AND_DIRECTORIES);
chooser.setMultiSelectionEnabled(false);
if (chooser.showSaveDialog(getWindow(parent)) != JFileChooser.APPROVE_OPTION) {
return null;
}
return chooser.getSelectedFile();
}
public static FileDialog createFileDialog(Object parent, String title, int mode, boolean fileDialogForDirectories) {
System.setProperty("apple.awt.fileDialogForDirectories", String.valueOf(fileDialogForDirectories));
if (parent instanceof Frame) {
return new FileDialog((Frame) parent, title, mode);
}
if (parent instanceof Dialog) {
return new FileDialog((Dialog) parent, title, mode);
}
Frame[] frames = Frame.getFrames();
return new FileDialog(frames.length > 0 ? frames[0] : null, title, mode);
}
public static void checkEventDispatchThread() {
if (!SwingUtilities.isEventDispatchThread()) {
@ -48,6 +144,8 @@ public final class TunedUtilities {
}
}
public static final Color TRANSLUCENT = new Color(255, 255, 255, 0);
public static Color interpolateHSB(Color c1, Color c2, float f) {
float[] hsb1 = Color.RGBtoHSB(c1.getRed(), c1.getGreen(), c1.getBlue(), null);
float[] hsb2 = Color.RGBtoHSB(c2.getRed(), c2.getGreen(), c2.getBlue(), null);