diff --git a/source/net/sourceforge/filebot/FileBotUtil.java b/source/net/sourceforge/filebot/FileBotUtil.java index 4cb93d6c..508bf017 100644 --- a/source/net/sourceforge/filebot/FileBotUtil.java +++ b/source/net/sourceforge/filebot/FileBotUtil.java @@ -2,24 +2,17 @@ package net.sourceforge.filebot; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Window; import java.io.File; import java.io.FileFilter; +import java.io.FilenameFilter; import java.util.List; import java.util.regex.Pattern; -import javax.swing.Action; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.KeyStroke; - public class FileBotUtil { private FileBotUtil() { - + // hide constructor } /** @@ -36,7 +29,7 @@ public class FileBotUtil { * @return filename stripped of invalid characters */ public static String validateFileName(String filename) { - // strip \, /, :, *, ?, ", <, > and | + // strip invalid characters from filename return INVALID_CHARACTERS_PATTERN.matcher(filename).replaceAll(""); } @@ -54,7 +47,12 @@ public class FileBotUtil { return t; } - + private static final String[] TORRENT_FILE_EXTENSIONS = { "torrent" }; + private static final String[] SFV_FILE_EXTENSIONS = { "sfv" }; + private static final String[] LIST_FILE_EXTENSIONS = { "txt", "list", "" }; + private static final String[] SUBTITLE_FILE_EXTENSIONS = { "srt", "sub", "ssa" }; + + public static boolean containsOnlyFolders(List files) { for (File file : files) { if (!file.isDirectory()) @@ -66,54 +64,29 @@ public class FileBotUtil { public static boolean containsOnlyTorrentFiles(List files) { - for (File file : files) { - if (!FileFormat.hasExtension(file, "torrent")) - return false; - } - - return true; + return containsOnly(files, TORRENT_FILE_EXTENSIONS); } public static boolean containsOnlySfvFiles(List files) { - for (File file : files) { - if (!FileFormat.hasExtension(file, "sfv")) - return false; - } - - return true; + return containsOnly(files, SFV_FILE_EXTENSIONS); } public static boolean containsOnlyListFiles(List files) { + return containsOnly(files, LIST_FILE_EXTENSIONS); + } + + + private static boolean containsOnly(List files, String[] extensions) { for (File file : files) { - if (!FileFormat.hasExtension(file, "txt", "list", "")) + if (!FileFormat.hasExtension(file, extensions)) return false; } return true; } - - public static void registerActionForKeystroke(JComponent component, KeyStroke keystroke, Action action) { - Integer key = action.hashCode(); - component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keystroke, key); - component.getActionMap().put(key, action); - } - - - public static Point getPreferredLocation(JDialog dialog) { - Window owner = dialog.getOwner(); - - if (owner == null) - return new Point(120, 80); - - Point p = owner.getLocation(); - Dimension d = owner.getSize(); - - return new Point(p.x + d.width / 4, p.y + d.height / 7); - } - public static final FileFilter FOLDERS_ONLY = new FileFilter() { @Override @@ -131,4 +104,14 @@ public class FileBotUtil { } }; + + public static final FilenameFilter SUBTITLES_ONLY = new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + return FileFormat.hasExtension(name, SUBTITLE_FILE_EXTENSIONS); + } + + }; + } diff --git a/source/net/sourceforge/filebot/FileFormat.java b/source/net/sourceforge/filebot/FileFormat.java index f74b5e6c..20341008 100644 --- a/source/net/sourceforge/filebot/FileFormat.java +++ b/source/net/sourceforge/filebot/FileFormat.java @@ -35,7 +35,12 @@ public class FileFormat { if (file.isDirectory()) return false; - String extension = getExtension(file); + return hasExtension(file.getName(), extensions); + } + + + public static boolean hasExtension(String filename, String... extensions) { + String extension = getExtension(filename, false); for (String ext : extensions) { if (ext.equalsIgnoreCase(extension)) diff --git a/source/net/sourceforge/filebot/ui/FileBotList.java b/source/net/sourceforge/filebot/ui/FileBotList.java index 9c9aa40d..2a782bf5 100644 --- a/source/net/sourceforge/filebot/ui/FileBotList.java +++ b/source/net/sourceforge/filebot/ui/FileBotList.java @@ -19,7 +19,6 @@ import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.border.TitledBorder; -import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.ui.transfer.DefaultTransferHandler; import net.sourceforge.filebot.ui.transfer.ExportHandler; import net.sourceforge.filebot.ui.transfer.FileTransferable; @@ -32,6 +31,7 @@ import net.sourceforge.filebot.ui.transferablepolicies.NullTransferablePolicy; import net.sourceforge.filebot.ui.transferablepolicies.TransferablePolicy; import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer; import net.sourceforge.tuned.ui.SimpleListModel; +import net.sourceforge.tuned.ui.TunedUtil; public class FileBotList extends JPanel implements Saveable, TransferablePolicySupport { @@ -81,7 +81,7 @@ public class FileBotList extends JPanel implements Saveable, TransferablePolicyS if (enableRemoveAction) { // Shortcut DELETE - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction); } } diff --git a/source/net/sourceforge/filebot/ui/FileBotWindow.java b/source/net/sourceforge/filebot/ui/FileBotWindow.java index 3701470b..d457b005 100644 --- a/source/net/sourceforge/filebot/ui/FileBotWindow.java +++ b/source/net/sourceforge/filebot/ui/FileBotWindow.java @@ -21,13 +21,13 @@ import javax.swing.border.EmptyBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.Settings; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.tuned.MessageBus; import net.sourceforge.tuned.MessageHandler; import net.sourceforge.tuned.ui.ShadowBorder; import net.sourceforge.tuned.ui.SimpleListModel; +import net.sourceforge.tuned.ui.TunedUtil; public class FileBotWindow extends JFrame implements ListSelectionListener { @@ -56,7 +56,7 @@ public class FileBotWindow extends JFrame implements ListSelectionListener { setContentPane(contentPane); // Shortcut ESC - FileBotUtil.registerActionForKeystroke(contentPane, KeyStroke.getKeyStroke("released ESCAPE"), closeAction); + TunedUtil.registerActionForKeystroke(contentPane, KeyStroke.getKeyStroke("released ESCAPE"), closeAction); setSize(760, 615); diff --git a/source/net/sourceforge/filebot/ui/HistoryPanel.java b/source/net/sourceforge/filebot/ui/HistoryPanel.java index a289bfc1..5cca7dd1 100644 --- a/source/net/sourceforge/filebot/ui/HistoryPanel.java +++ b/source/net/sourceforge/filebot/ui/HistoryPanel.java @@ -7,7 +7,6 @@ import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; import java.net.URL; -import java.text.NumberFormat; import javax.swing.BorderFactory; import javax.swing.Icon; @@ -16,18 +15,22 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; -import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; import net.sourceforge.tuned.ui.HyperlinkLabel; public class HistoryPanel extends JPanel { - private JPanel grid = new JPanel(new GridLayout(0, 3, 15, 10)); + private final JPanel grid = new JPanel(new GridLayout(0, 3, 15, 10)); + + private final JLabel columnHeader1 = new JLabel(); + private final JLabel columnHeader2 = new JLabel(); + private final JLabel columnHeader3 = new JLabel(); - public HistoryPanel(String titleHeader, String infoHeader) { - setLayout(new FlowLayout(FlowLayout.CENTER)); + public HistoryPanel() { + super(new FlowLayout(FlowLayout.CENTER)); JScrollPane scrollPane = new JScrollPane(grid, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBorder(BorderFactory.createEmptyBorder()); @@ -38,48 +41,53 @@ public class HistoryPanel extends JPanel { setOpaque(true); grid.setOpaque(false); - JLabel titleLabel = new JLabel(titleHeader); - JLabel infoLabel = new JLabel(infoHeader); - JLabel durationLabel = new JLabel("Duration"); + Font font = columnHeader1.getFont().deriveFont(Font.BOLD); - Font font = titleLabel.getFont().deriveFont(Font.BOLD); + columnHeader1.setHorizontalAlignment(SwingConstants.CENTER); + columnHeader2.setHorizontalAlignment(SwingConstants.CENTER); + columnHeader3.setHorizontalAlignment(SwingConstants.RIGHT); - titleLabel.setHorizontalAlignment(SwingConstants.CENTER); - infoLabel.setHorizontalAlignment(SwingConstants.CENTER); - durationLabel.setHorizontalAlignment(SwingConstants.RIGHT); + columnHeader1.setFont(font); + columnHeader2.setFont(font); + columnHeader3.setFont(font); - titleLabel.setFont(font); - infoLabel.setFont(font); - durationLabel.setFont(font); - - grid.add(titleLabel); - grid.add(infoLabel); - grid.add(durationLabel); + grid.add(columnHeader1); + grid.add(columnHeader2); + grid.add(columnHeader3); } - private final Border infoBorder = BorderFactory.createEmptyBorder(0, 0, 0, 10); - - - public void add(String title, URL url, String info, long duration, Icon icon) { - - String durationString = NumberFormat.getInstance().format(duration) + " ms"; - - JLabel titleLabel = (url != null) ? new HyperlinkLabel(title, url) : new JLabel(title); - JLabel infoLabel = new JLabel(info); - JLabel durationLabel = new JLabel(durationString); - - infoLabel.setBorder(infoBorder); - - titleLabel.setHorizontalAlignment(SwingConstants.LEFT); - infoLabel.setHorizontalAlignment(SwingConstants.RIGHT); - durationLabel.setHorizontalAlignment(SwingConstants.RIGHT); - - titleLabel.setIcon(icon); - titleLabel.setIconTextGap(7); - - grid.add(titleLabel); - grid.add(infoLabel); - grid.add(durationLabel); + + public void setColumnHeader1(String text) { + columnHeader1.setText(text); } + + public void setColumnHeader2(String text) { + columnHeader2.setText(text); + } + + + public void setColumnHeader3(String text) { + columnHeader3.setText(text); + } + + + public void add(String column1, URL url, Icon icon, String column2, String column3) { + JLabel label1 = (url != null) ? new HyperlinkLabel(column1, url) : new JLabel(column1); + JLabel label2 = new JLabel(column2); + JLabel label3 = new JLabel(column3); + + label1.setHorizontalAlignment(SwingConstants.LEFT); + label2.setHorizontalAlignment(SwingConstants.RIGHT); + label3.setHorizontalAlignment(SwingConstants.RIGHT); + + label1.setIcon(icon); + label1.setIconTextGap(7); + + label2.setBorder(new EmptyBorder(0, 0, 0, 10)); + + grid.add(label1); + grid.add(label2); + grid.add(label3); + } } diff --git a/source/net/sourceforge/filebot/ui/SelectDialog.java b/source/net/sourceforge/filebot/ui/SelectDialog.java index b01d277a..68104656 100644 --- a/source/net/sourceforge/filebot/ui/SelectDialog.java +++ b/source/net/sourceforge/filebot/ui/SelectDialog.java @@ -24,10 +24,10 @@ import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; -import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.tuned.ui.DefaultFancyListCellRenderer; import net.sourceforge.tuned.ui.SimpleListModel; +import net.sourceforge.tuned.ui.TunedUtil; public class SelectDialog extends JDialog { @@ -75,7 +75,7 @@ public class SelectDialog extends JDialog { // bounds and location setMinimumSize(new Dimension(175, 175)); setSize(new Dimension(200, 190)); - setLocation(FileBotUtil.getPreferredLocation(this)); + setLocation(TunedUtil.getPreferredLocation(this)); // default selection list.setModel(new SimpleListModel(options)); diff --git a/source/net/sourceforge/filebot/ui/panel/analyze/FileTreePanel.java b/source/net/sourceforge/filebot/ui/panel/analyze/FileTreePanel.java index d8906b13..dcdfdce9 100644 --- a/source/net/sourceforge/filebot/ui/panel/analyze/FileTreePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/analyze/FileTreePanel.java @@ -14,10 +14,10 @@ import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.border.EmptyBorder; -import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.ui.transfer.LoadAction; import net.sourceforge.tuned.ui.LoadingOverlayPane; +import net.sourceforge.tuned.ui.TunedUtil; class FileTreePanel extends JPanel { @@ -39,7 +39,7 @@ class FileTreePanel extends JPanel { buttons.add(Box.createGlue()); // Shortcut DELETE - FileBotUtil.registerActionForKeystroke(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction); + TunedUtil.registerActionForKeystroke(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction); add(new LoadingOverlayPane(new JScrollPane(fileTree), ResourceManager.getIcon("loading")), BorderLayout.CENTER); add(buttons, BorderLayout.SOUTH); diff --git a/source/net/sourceforge/filebot/ui/panel/list/ListPanel.java b/source/net/sourceforge/filebot/ui/panel/list/ListPanel.java index d5d8b38f..5b66aec7 100644 --- a/source/net/sourceforge/filebot/ui/panel/list/ListPanel.java +++ b/source/net/sourceforge/filebot/ui/panel/list/ListPanel.java @@ -21,7 +21,6 @@ import javax.swing.KeyStroke; import javax.swing.SpinnerNumberModel; import javax.swing.border.EmptyBorder; -import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.ui.FileBotList; import net.sourceforge.filebot.ui.FileBotPanel; @@ -30,6 +29,7 @@ import net.sourceforge.filebot.ui.MessageManager; import net.sourceforge.filebot.ui.transfer.LoadAction; import net.sourceforge.filebot.ui.transfer.SaveAction; import net.sourceforge.tuned.MessageBus; +import net.sourceforge.tuned.ui.TunedUtil; public class ListPanel extends FileBotPanel { @@ -88,7 +88,7 @@ public class ListPanel extends FileBotPanel { add(spinners, BorderLayout.NORTH); add(list, BorderLayout.CENTER); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), createAction); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), createAction); MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(getPanelName(), list)); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java b/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java index 9ea7b961..bed48ac3 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/RenamePanel.java @@ -13,11 +13,13 @@ import java.awt.event.MouseEvent; import javax.swing.AbstractAction; import javax.swing.Box; import javax.swing.BoxLayout; +import javax.swing.DefaultListSelectionModel; import javax.swing.JButton; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JViewport; +import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ListDataEvent; @@ -53,7 +55,11 @@ public class RenamePanel extends FileBotPanel { JList list1 = namesList.getListComponent(); JList list2 = filesList.getListComponent(); - new SelectionSynchronizer(list1, list2); + ListSelectionModel selectionModel = new DefaultListSelectionModel(); + selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + namesList.getListComponent().setSelectionModel(selectionModel); + filesList.getListComponent().setSelectionModel(selectionModel); viewPortSynchroniser = new ViewPortSynchronizer((JViewport) list1.getParent(), (JViewport) list2.getParent()); diff --git a/source/net/sourceforge/filebot/ui/panel/rename/SelectionSynchronizer.java b/source/net/sourceforge/filebot/ui/panel/rename/SelectionSynchronizer.java deleted file mode 100644 index ded6eee2..00000000 --- a/source/net/sourceforge/filebot/ui/panel/rename/SelectionSynchronizer.java +++ /dev/null @@ -1,70 +0,0 @@ - -package net.sourceforge.filebot.ui.panel.rename; - - -import javax.swing.JList; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - - -class SelectionSynchronizer { - - private final JList list1; - private final JList list2; - - private final SelectionSynchronizeListener selectionSynchronizeListener1; - private final SelectionSynchronizeListener selectionSynchronizeListener2; - - - public SelectionSynchronizer(JList list1, JList list2) { - this.list1 = list1; - this.list2 = list2; - - selectionSynchronizeListener1 = new SelectionSynchronizeListener(list2); - selectionSynchronizeListener2 = new SelectionSynchronizeListener(list1); - - setEnabled(true); - } - - - public void setEnabled(boolean enabled) { - // remove listeners to avoid adding them multiple times - list1.removeListSelectionListener(selectionSynchronizeListener1); - list2.removeListSelectionListener(selectionSynchronizeListener2); - - // if enabled add them again - if (enabled) { - list1.addListSelectionListener(selectionSynchronizeListener1); - list2.addListSelectionListener(selectionSynchronizeListener2); - } - } - - - private static class SelectionSynchronizeListener implements ListSelectionListener { - - private JList target; - - - public SelectionSynchronizeListener(JList target) { - this.target = target; - } - - - public void valueChanged(ListSelectionEvent e) { - JList source = (JList) e.getSource(); - int index = source.getSelectedIndex(); - - if (target.getModel().getSize() > index) { - if (index != target.getSelectedIndex()) { - target.setSelectedIndex(index); - } - - target.ensureIndexIsVisible(index); - } else { - target.clearSelection(); - } - } - - } - -} diff --git a/source/net/sourceforge/filebot/ui/panel/rename/ValidateNamesDialog.java b/source/net/sourceforge/filebot/ui/panel/rename/ValidateNamesDialog.java index 7fb7d5e3..daa591ef 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/ValidateNamesDialog.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/ValidateNamesDialog.java @@ -30,6 +30,7 @@ import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.ui.panel.rename.entry.ListEntry; import net.sourceforge.tuned.ui.SimpleListModel; +import net.sourceforge.tuned.ui.TunedUtil; public class ValidateNamesDialog extends JDialog { @@ -83,13 +84,12 @@ public class ValidateNamesDialog extends JDialog { c.add(listPanel, BorderLayout.CENTER); c.add(buttonBox, BorderLayout.SOUTH); - setLocation(FileBotUtil.getPreferredLocation(this)); + setLocation(TunedUtil.getPreferredLocation(this)); setPreferredSize(new Dimension(365, 280)); pack(); - // Shortcut Escape - FileBotUtil.registerActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction); + TunedUtil.registerActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction); } diff --git a/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java b/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java index c9101b9f..6f551030 100644 --- a/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java +++ b/source/net/sourceforge/filebot/ui/panel/rename/entry/FileEntry.java @@ -9,19 +9,25 @@ import net.sourceforge.filebot.FileFormat; public class FileEntry extends AbstractFileEntry { + private final long length; + private final String type; + + public FileEntry(File file) { super(FileFormat.getFileName(file), file); + + this.length = file.length(); + this.type = FileFormat.getFileType(file); } @Override public long getLength() { - return getValue().length(); + return length; } public String getType() { - return FileFormat.getFileType(getValue()); + return type; } - } diff --git a/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java b/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java index 2ddc983f..9fc20b5a 100644 --- a/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java +++ b/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java @@ -12,10 +12,11 @@ import net.sourceforge.filebot.web.EpisodeListClient; class FetchEpisodeListTask extends SwingWorker, Object> { - private String showName; - private EpisodeListClient searchEngine; - private int numberOfSeason; - private long duration; + private final String showName; + private final EpisodeListClient searchEngine; + private final int numberOfSeason; + + private long duration = -1; public FetchEpisodeListTask(EpisodeListClient searchEngine, String showname, int numberOfSeason) { diff --git a/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java b/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java index 10645f49..f02d8f3d 100644 --- a/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java +++ b/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java @@ -10,6 +10,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.net.URL; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -45,13 +46,14 @@ import net.sourceforge.tuned.ui.SelectButton; import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter; import net.sourceforge.tuned.ui.TextCompletion; import net.sourceforge.tuned.ui.TextFieldWithSelect; +import net.sourceforge.tuned.ui.TunedUtil; public class SearchPanel extends FileBotPanel { private JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT); - private HistoryPanel historyPanel = new HistoryPanel("Show", "Number of Episodes"); + private HistoryPanel historyPanel = new HistoryPanel(); private SpinnerNumberModel seasonSpinnerModel = new SpinnerNumberModel(SeasonSpinnerEditor.ALL_SEASONS, SeasonSpinnerEditor.ALL_SEASONS, Integer.MAX_VALUE, 1); @@ -77,6 +79,10 @@ public class SearchPanel extends FileBotPanel { searchFieldCompletion.addTerms(Settings.getSettings().getStringList(Settings.SEARCH_HISTORY)); searchFieldCompletion.hook(); + historyPanel.setColumnHeader1("Show"); + historyPanel.setColumnHeader2("Number of Episodes"); + historyPanel.setColumnHeader3("Duration"); + JPanel mainPanel = new JPanel(new BorderLayout(5, 5)); Box searchBox = Box.createHorizontalBox(); @@ -114,11 +120,9 @@ public class SearchPanel extends FileBotPanel { this.add(mainPanel, BorderLayout.CENTER); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("UP"), upAction); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1)); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1)); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("UP"), upAction); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("DOWN"), downAction); } @@ -206,22 +210,6 @@ public class SearchPanel extends FileBotPanel { }; - private class SpinClientAction extends AbstractAction { - - private int spin; - - - public SpinClientAction(int spin) { - this.spin = spin; - } - - - public void actionPerformed(ActionEvent e) { - searchField.getSelectButton().spinValue(spin); - } - } - - private class SearchTask extends SwingWorker, Object> { private String query; @@ -366,7 +354,7 @@ public class SearchPanel extends FileBotPanel { String info = (episodes.size() > 0) ? String.format("%d episodes", episodes.size()) : "No episodes found"; - historyPanel.add(episodeList.getTitle(), url, info, task.getDuration(), episodeList.getIcon()); + historyPanel.add(episodeList.getTitle(), url, episodeList.getIcon(), info, NumberFormat.getInstance().format(task.getDuration()) + " ms"); if (episodes.size() <= 0) tabbedPane.remove(episodeList); diff --git a/source/net/sourceforge/filebot/ui/panel/sfv/SfvPanel.java b/source/net/sourceforge/filebot/ui/panel/sfv/SfvPanel.java index ee01f5fe..4ed412cc 100644 --- a/source/net/sourceforge/filebot/ui/panel/sfv/SfvPanel.java +++ b/source/net/sourceforge/filebot/ui/panel/sfv/SfvPanel.java @@ -17,7 +17,6 @@ import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; -import net.sourceforge.filebot.FileBotUtil; import net.sourceforge.filebot.FileFormat; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.ui.FileBotPanel; @@ -26,6 +25,7 @@ import net.sourceforge.filebot.ui.SelectDialog; import net.sourceforge.filebot.ui.transfer.LoadAction; import net.sourceforge.filebot.ui.transfer.SaveAction; import net.sourceforge.tuned.MessageBus; +import net.sourceforge.tuned.ui.TunedUtil; public class SfvPanel extends FileBotPanel { @@ -61,7 +61,7 @@ public class SfvPanel extends FileBotPanel { add(southPanel, BorderLayout.SOUTH); // Shortcut DELETE - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction); MessageBus.getDefault().addMessageHandler(getPanelName(), new FileTransferableMessageHandler(getPanelName(), sfvTable)); } diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java index 6095ac2b..6a1d40ce 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java @@ -6,6 +6,7 @@ import java.awt.BorderLayout; import java.awt.Window; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; @@ -38,13 +39,14 @@ import net.sourceforge.tuned.ui.SelectButton; import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter; import net.sourceforge.tuned.ui.TextCompletion; import net.sourceforge.tuned.ui.TextFieldWithSelect; +import net.sourceforge.tuned.ui.TunedUtil; public class SubtitlePanel extends FileBotPanel { private JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT); - private HistoryPanel historyPanel = new HistoryPanel("Show / Movie", "Number of Subtitles"); + private HistoryPanel historyPanel = new HistoryPanel(); private TextFieldWithSelect searchField; @@ -67,6 +69,10 @@ public class SubtitlePanel extends FileBotPanel { searchFieldCompletion.addTerms(Settings.getSettings().getStringList(Settings.SUBTITLE_HISTORY)); searchFieldCompletion.hook(); + historyPanel.setColumnHeader1("Show / Movie"); + historyPanel.setColumnHeader2("Number of Subtitles"); + historyPanel.setColumnHeader3("Duration"); + JPanel mainPanel = new JPanel(new BorderLayout(5, 5)); Box searchBox = Box.createHorizontalBox(); @@ -99,25 +105,7 @@ public class SubtitlePanel extends FileBotPanel { this.add(mainPanel, BorderLayout.CENTER); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1)); - FileBotUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1)); - } - - - private class SpinClientAction extends AbstractAction { - - private int spin; - - - public SpinClientAction(int spin) { - this.spin = spin; - } - - - public void actionPerformed(ActionEvent e) { - searchField.getSelectButton().spinValue(spin); - } + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction); } private final AbstractAction searchAction = new AbstractAction("Find", ResourceManager.getIcon("action.find")) { @@ -251,25 +239,6 @@ public class SubtitlePanel extends FileBotPanel { } - private class FetchSubtitleListTask extends SwingWorker, Object> { - - private final SubtitleClient client; - private final MovieDescriptor descriptor; - - - public FetchSubtitleListTask(MovieDescriptor descriptor, SubtitleClient client) { - this.descriptor = descriptor; - this.client = client; - } - - - @Override - protected List doInBackground() throws Exception { - return client.getSubtitleList(descriptor); - } - } - - private class FetchSubtitleListTaskListener extends SwingWorkerPropertyChangeAdapter { private final SubtitleListPanel subtitleSearchResultPanel; @@ -295,14 +264,14 @@ public class SubtitlePanel extends FileBotPanel { String info = (subtitleDescriptors.size() > 0) ? String.format("%d subtitles", subtitleDescriptors.size()) : "No subtitles found"; - historyPanel.add(task.descriptor.toString(), null, info, 0, task.client.getIcon()); + historyPanel.add(task.getDescriptor().toString(), null, task.getClient().getIcon(), info, NumberFormat.getInstance().format(task.getDuration()) + " ms"); if (subtitleDescriptors.isEmpty()) { tabbedPane.remove(subtitleSearchResultPanel); return; } - tabComponent.setIcon(task.client.getIcon()); + tabComponent.setIcon(task.getClient().getIcon()); //TODO icon view //TODO sysout diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java b/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java index 6cfea0a5..c760d6ec 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java @@ -7,15 +7,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import net.sourceforge.filebot.Settings; -import net.sourceforge.filebot.resources.ResourceManager; import redstone.xmlrpc.XmlRpcClient; import redstone.xmlrpc.XmlRpcException; import redstone.xmlrpc.XmlRpcFault; @@ -25,18 +21,7 @@ import redstone.xmlrpc.XmlRpcFault; * Client for the OpenSubtitles XML-RPC API. * */ -public class OpenSubtitlesClient extends SubtitleClient { - - @Override - public List search(String query) throws Exception { - return searchMoviesOnIMDB(query); - } - - - @Override - public List getSubtitleList(MovieDescriptor descriptor) throws Exception { - return searchSubtitles(descriptor.getImdbId()); - } +public class OpenSubtitlesClient { /** * @@ -52,65 +37,57 @@ public class OpenSubtitlesClient extends SubtitleClient { */ private String url = "http://www.opensubtitles.org/xml-rpc"; - private String username = ""; - private String password = ""; - private String language = "en"; - - private String useragent = String.format("%s v%s", Settings.NAME, Settings.VERSION); + private String useragent; private String token = null; - private Timer keepAliveDaemon = null; - /** - * Interval to call NoOperation to keep the session from expiring - */ - private static final int KEEP_ALIVE_INTERVAL = 12 * 60 * 1000; // 12 minutes - - - public OpenSubtitlesClient() { - super("OpenSubtitles", ResourceManager.getIcon("search.opensubtitles")); + public OpenSubtitlesClient(String useragent) { + this.useragent = useragent; } + public void login(String username, String password) throws XmlRpcFault { + login(username, password, "en"); + } + + + /** + * This will login user. This method should be called always when starting talking with + * server. + * + * @param username blank for anonymous user. + * @param password blank for anonymous user. + * @param language ISO639 + * 2 letter codes as language and later communication will be done in this + * language if applicable (error codes and so on). + */ @SuppressWarnings("unchecked") - private synchronized void activate() throws XmlRpcFault { - if (isActive()) - return; + public synchronized void login(String username, String password, String language) throws XmlRpcFault { Map response = (Map) invoke("LogIn", username, password, language, useragent); checkStatus(response.get("status")); token = response.get("token"); - - keepAliveDaemon = new Timer(getClass().getSimpleName() + " Keepalive", true); - keepAliveDaemon.schedule(new KeepAliveTimerTask(), KEEP_ALIVE_INTERVAL, KEEP_ALIVE_INTERVAL); } @SuppressWarnings("unchecked") - private synchronized void deactivate() { - if (!isActive()) - return; + public synchronized void logout() { // anonymous users will always get a 401 Unauthorized when trying to logout - if (!username.isEmpty()) { - try { - Map response = (Map) invoke("LogOut", token); - checkStatus(response.get("status")); - } catch (Exception e) { - Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, "Exception while deactivating connection", e); - } + try { + Map response = (Map) invoke("LogOut", token); + checkStatus(response.get("status")); + } catch (Exception e) { + Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, "Exception while deactivating session", e); } token = null; - - keepAliveDaemon.cancel(); - keepAliveDaemon = null; } - private boolean isActive() { + public synchronized boolean isLoggedOn() { return token != null; } @@ -151,15 +128,12 @@ public class OpenSubtitlesClient extends SubtitleClient { */ @SuppressWarnings("unchecked") public Map getServerInfo() throws XmlRpcFault { - activate(); - return (Map) invoke("ServerInfo", token); } @SuppressWarnings("unchecked") - public List searchSubtitles(int... imdbidArray) throws XmlRpcFault { - activate(); + public List searchSubtitles(int... imdbidArray) throws XmlRpcFault { List> imdbidList = new ArrayList>(imdbidArray.length); @@ -174,14 +148,14 @@ public class OpenSubtitlesClient extends SubtitleClient { Map>> response = (Map>>) invoke("SearchSubtitles", token, imdbidList); - ArrayList subs = new ArrayList(); + ArrayList subs = new ArrayList(); if (!(response.get("data") instanceof List)) throw new XmlRpcException("Illegal response: " + response.toString()); // if there was an error data may not be a list for (Map subtitle : response.get("data")) { - subs.add(new OpenSubtitleDescriptor(subtitle)); + subs.add(new OpenSubtitlesSubtitleDescriptor(subtitle)); } return subs; @@ -190,7 +164,6 @@ public class OpenSubtitlesClient extends SubtitleClient { @SuppressWarnings("unchecked") public List searchMoviesOnIMDB(String query) throws XmlRpcFault { - activate(); Map>> response = (Map>>) invoke("SearchMoviesOnIMDB", token, query); @@ -207,30 +180,13 @@ public class OpenSubtitlesClient extends SubtitleClient { @SuppressWarnings("unchecked") public boolean noOperation() { try { - activate(); - Map response = (Map) invoke("NoOperation", token); checkStatus(response.get("status")); return true; } catch (Exception e) { - deactivate(); return false; } } - - private class KeepAliveTimerTask extends TimerTask { - - @Override - public void run() { - if (noOperation()) { - Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.INFO, "Connection is OK"); - } else { - Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.INFO, "Connection lost"); - deactivate(); - } - }; - }; - } diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java b/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java index 14534295..d1c2cfdb 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesHasher.java @@ -5,7 +5,8 @@ package net.sourceforge.filebot.web; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.math.BigInteger; +import java.nio.ByteOrder; +import java.nio.LongBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; @@ -23,11 +24,6 @@ public class OpenSubtitlesHasher { */ private static final int HASH_CHUNK_SIZE = 64 * 1024; - /** - * Size of the checksum in bytes (64 Bit) - */ - private static final int HASH_SIZE = 8; - public static String computeHash(File file) throws IOException { long size = file.length(); @@ -35,63 +31,26 @@ public class OpenSubtitlesHasher { FileChannel fileChannel = new FileInputStream(file).getChannel(); - BigInteger head = computeHashForChunk(fileChannel, 0, chunkSizeForFile); - BigInteger tail = computeHashForChunk(fileChannel, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile); + long head = computeHashForChunk(fileChannel, 0, chunkSizeForFile); + long tail = computeHashForChunk(fileChannel, Math.max(size - HASH_CHUNK_SIZE, 0), chunkSizeForFile); fileChannel.close(); - // size + head + tail - BigInteger bigHash = BigInteger.valueOf(size).add(head.add(tail)); - - byte[] hash = getTrailingBytes(bigHash.toByteArray(), HASH_SIZE); - - return String.format("%0" + HASH_SIZE * 2 + "x", new BigInteger(1, hash)); + return String.format("%016x", size + head + tail); } - private static BigInteger computeHashForChunk(FileChannel fileChannel, long start, long size) throws IOException { - MappedByteBuffer buffer = fileChannel.map(MapMode.READ_ONLY, start, size); + private static long computeHashForChunk(FileChannel fileChannel, long start, long size) throws IOException { + MappedByteBuffer byteBuffer = fileChannel.map(MapMode.READ_ONLY, start, size); - BigInteger bigHash = BigInteger.ZERO; - byte[] bytes = new byte[HASH_SIZE]; + LongBuffer longBuffer = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer(); + long hash = 0; - while (buffer.hasRemaining()) { - buffer.get(bytes, 0, Math.min(HASH_SIZE, buffer.remaining())); - - // BigInteger expects a big-endian byte-order, so we reverse the byte array - bigHash = bigHash.add(new BigInteger(1, reverse(bytes))); + while (longBuffer.hasRemaining()) { + hash += longBuffer.get(); } - return bigHash; - } - - - /** - * copy the last n bytes to a new array - * - * @param bytes original array - * @param n number of trailing bytes - * @return new array - */ - private static byte[] getTrailingBytes(byte[] src, int n) { - int length = Math.min(src.length, n); - - byte[] dest = new byte[length]; - - int offsetSrc = Math.max(src.length - n, 0); - System.arraycopy(src, offsetSrc, dest, 0, length); - - return dest; - } - - - private static byte[] reverse(byte[] bytes) { - byte[] reverseBytes = new byte[bytes.length]; - - for (int forward = 0, backward = bytes.length; forward < bytes.length; ++forward) - reverseBytes[forward] = bytes[--backward]; - - return reverseBytes; + return hash; } } diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java new file mode 100644 index 00000000..2bd02861 --- /dev/null +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java @@ -0,0 +1,117 @@ + +package net.sourceforge.filebot.web; + + +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.sourceforge.filebot.Settings; +import net.sourceforge.filebot.resources.ResourceManager; + + +/** + * Client for the OpenSubtitles XML-RPC API. + * + */ +public class OpenSubtitlesSubtitleClient extends SubtitleClient { + + private final OpenSubtitlesClient client = new OpenSubtitlesClient(String.format("%s v%s", Settings.NAME, Settings.VERSION)); + + private final LogoutTimer logoutTimer = new LogoutTimer(); + + + public OpenSubtitlesSubtitleClient() { + super("OpenSubtitles", ResourceManager.getIcon("search.opensubtitles")); + + Runtime.getRuntime().addShutdownHook(new Thread(doLogout)); + } + + + @Override + public List search(String query) throws Exception { + activate(); + + return client.searchMoviesOnIMDB(query); + } + + + @Override + public List getSubtitleList(MovieDescriptor descriptor) throws Exception { + activate(); + + return client.searchSubtitles(descriptor.getImdbId()); + } + + + private synchronized void activate() { + try { + if (!client.isLoggedOn()) { + client.login("", ""); + } + } catch (Exception e) { + Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e); + } + + logoutTimer.restart(); + } + + private final Runnable doLogout = new Runnable() { + + public void run() { + logoutTimer.stop(); + + if (client.isLoggedOn()) { + client.logout(); + } + } + }; + + + private class LogoutTimer { + + private static final int LOGOUT_DELAY = 15000; // 12 minutes + + private Timer daemon = null; + private LogoutTimerTask currentTimerTask = null; + + + public synchronized void restart() { + if (daemon == null) { + daemon = new Timer(getClass().getName(), true); + } + + if (currentTimerTask != null) { + currentTimerTask.cancel(); + daemon.purge(); + } + + currentTimerTask = new LogoutTimerTask(); + daemon.schedule(currentTimerTask, LOGOUT_DELAY); + } + + + public synchronized void stop() { + if (daemon == null) + return; + + currentTimerTask.cancel(); + currentTimerTask = null; + + daemon.cancel(); + daemon = null; + } + + + private class LogoutTimerTask extends TimerTask { + + @Override + public void run() { + doLogout.run(); + }; + }; + } + +} diff --git a/source/net/sourceforge/filebot/web/OpenSubtitleDescriptor.java b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java similarity index 92% rename from source/net/sourceforge/filebot/web/OpenSubtitleDescriptor.java rename to source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java index ac6a709d..d1cd823f 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitleDescriptor.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleDescriptor.java @@ -16,7 +16,7 @@ import net.sourceforge.tuned.DownloadTask; * * @see OpenSubtitlesClient */ -public class OpenSubtitleDescriptor implements SubtitleDescriptor { +public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor { private final Map properties; @@ -57,7 +57,7 @@ public class OpenSubtitleDescriptor implements SubtitleDescriptor { } - public OpenSubtitleDescriptor(Map properties) { + public OpenSubtitlesSubtitleDescriptor(Map properties) { this.properties = properties; } diff --git a/source/net/sourceforge/filebot/web/SubsceneClient.java b/source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java similarity index 97% rename from source/net/sourceforge/filebot/web/SubsceneClient.java rename to source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java index e451db8b..7fe3f291 100644 --- a/source/net/sourceforge/filebot/web/SubsceneClient.java +++ b/source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java @@ -25,14 +25,14 @@ import org.w3c.dom.Node; import org.xml.sax.SAXException; -public class SubsceneClient extends SubtitleClient { +public class SubsceneSubtitleClient extends SubtitleClient { private final Map cache = Collections.synchronizedMap(new HashMap()); private final String host = "subscene.com"; - public SubsceneClient() { + public SubsceneSubtitleClient() { super("Subscene", ResourceManager.getIcon("search.subscene")); } diff --git a/source/net/sourceforge/filebot/web/SubtitleClient.java b/source/net/sourceforge/filebot/web/SubtitleClient.java index 06121e4e..e4836982 100644 --- a/source/net/sourceforge/filebot/web/SubtitleClient.java +++ b/source/net/sourceforge/filebot/web/SubtitleClient.java @@ -14,8 +14,8 @@ public abstract class SubtitleClient { private static final List registry = new ArrayList(); static { - registry.add(new OpenSubtitlesClient()); - registry.add(new SubsceneClient()); + registry.add(new OpenSubtitlesSubtitleClient()); + registry.add(new SubsceneSubtitleClient()); } diff --git a/source/net/sourceforge/tuned/ui/TextFieldWithSelect.java b/source/net/sourceforge/tuned/ui/TextFieldWithSelect.java index d9952093..fe973e89 100644 --- a/source/net/sourceforge/tuned/ui/TextFieldWithSelect.java +++ b/source/net/sourceforge/tuned/ui/TextFieldWithSelect.java @@ -8,9 +8,11 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; +import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.KeyStroke; import javax.swing.border.Border; import net.sourceforge.tuned.ui.SelectButton.Entry; @@ -40,6 +42,9 @@ public class TextFieldWithSelect extends JPanel { textfield.setColumns(20); add(textfield, BorderLayout.CENTER); add(selectButton, BorderLayout.WEST); + + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinClientAction(-1)); + TunedUtil.registerActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinClientAction(1)); } @@ -71,4 +76,20 @@ public class TextFieldWithSelect extends JPanel { }; + + private class SpinClientAction extends AbstractAction { + + private int spin; + + + public SpinClientAction(int spin) { + this.spin = spin; + } + + + public void actionPerformed(ActionEvent e) { + selectButton.spinValue(spin); + } + } + } diff --git a/source/net/sourceforge/tuned/ui/TunedUtil.java b/source/net/sourceforge/tuned/ui/TunedUtil.java new file mode 100644 index 00000000..462feef3 --- /dev/null +++ b/source/net/sourceforge/tuned/ui/TunedUtil.java @@ -0,0 +1,35 @@ + +package net.sourceforge.tuned.ui; + + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Window; + +import javax.swing.Action; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.KeyStroke; + + +public class TunedUtil { + + public static void registerActionForKeystroke(JComponent component, KeyStroke keystroke, Action action) { + Integer key = action.hashCode(); + component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keystroke, key); + component.getActionMap().put(key, action); + } + + + public static Point getPreferredLocation(JDialog dialog) { + Window owner = dialog.getOwner(); + + if (owner == null) + return new Point(120, 80); + + Point p = owner.getLocation(); + Dimension d = owner.getSize(); + + return new Point(p.x + d.width / 4, p.y + d.height / 7); + } +}