* lots of stuff for subtitle support
This commit is contained in:
parent
b59e5dc714
commit
12d453eff4
|
@ -22,9 +22,9 @@ public class Settings {
|
|||
public static final String ROOT = NAME.toLowerCase();
|
||||
|
||||
public static final String SELECTED_PANEL = "panel";
|
||||
public static final String SEARCH_HISTORY = "history/search";
|
||||
public static final String SUBTITLE_HISTORY = "history/subtitle";
|
||||
public static final String LANGUAGE_HISTORY = "history/language";
|
||||
public static final String SEARCH_HISTORY = "search/history";
|
||||
public static final String SUBTITLE_HISTORY = "subtitle/history";
|
||||
public static final String SUBTITLE_LANGUAGE = "subtitle/language";
|
||||
|
||||
private static Settings settings = new Settings();
|
||||
|
||||
|
@ -133,7 +133,7 @@ public class Settings {
|
|||
|
||||
for (Entry<String, String> entry : entries.entrySet()) {
|
||||
try {
|
||||
map.put(entry.getKey(), new Integer(entry.getValue()));
|
||||
map.put(entry.getKey(), Integer.valueOf(entry.getValue()));
|
||||
} catch (NumberFormatException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
|
@ -154,6 +154,35 @@ public class Settings {
|
|||
}
|
||||
|
||||
|
||||
public Map<String, Boolean> getBooleanMap(String key) {
|
||||
Map<String, String> entries = getStringMap(key);
|
||||
|
||||
Map<String, Boolean> map = new HashMap<String, Boolean>(entries.size());
|
||||
|
||||
for (Entry<String, String> entry : entries.entrySet()) {
|
||||
map.put(entry.getKey(), Boolean.valueOf(entry.getValue()));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
public void putBooleanMap(String key, Map<String, Boolean> map) {
|
||||
Map<String, String> entries = new HashMap<String, String>();
|
||||
|
||||
for (Entry<String, Boolean> entry : map.entrySet()) {
|
||||
entries.put(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
|
||||
putStringMap(key, entries);
|
||||
}
|
||||
|
||||
|
||||
public void putBooleanMapEntry(String nodeKey, String mapKey, Boolean value) {
|
||||
prefs.node(nodeKey).put(mapKey, value.toString());
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
try {
|
||||
prefs.removeNode();
|
||||
|
|
|
@ -5,7 +5,10 @@ package net.sourceforge.filebot.resources;
|
|||
import java.awt.Image;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -15,49 +18,71 @@ import javax.swing.ImageIcon;
|
|||
|
||||
public class ResourceManager {
|
||||
|
||||
private static HashMap<String, String> aliasMap = new HashMap<String, String>();
|
||||
private ResourceManager() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
private static final Map<String, String> aliasMap = new HashMap<String, String>();
|
||||
|
||||
static {
|
||||
aliasMap.put("tab.loading", "tab.loading.gif");
|
||||
aliasMap.put("tab.history", "action.find.png");
|
||||
|
||||
aliasMap.put("loading", "loading.gif");
|
||||
}
|
||||
|
||||
private static final Map<String, Image> cache = Collections.synchronizedMap(new WeakHashMap<String, Image>());
|
||||
|
||||
public static Image getImage(String name) {
|
||||
try {
|
||||
return ImageIO.read(getResource(name));
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static ImageIcon getIcon(String name) {
|
||||
return new ImageIcon(getResource(name));
|
||||
return new ImageIcon(getImage(name));
|
||||
}
|
||||
|
||||
|
||||
public static ImageIcon getFlagIcon(String languageCode) {
|
||||
URL url = ResourceManager.class.getResource(String.format("flags/%s.png", languageCode));
|
||||
if (languageCode == null)
|
||||
languageCode = "default";
|
||||
|
||||
if (url == null)
|
||||
url = ResourceManager.class.getResource(String.format("flags/default.png", languageCode));
|
||||
|
||||
return new ImageIcon(url);
|
||||
return new ImageIcon(getImage(String.format("flags/%s", languageCode.toLowerCase()), "flags/default"));
|
||||
}
|
||||
|
||||
|
||||
public static ImageIcon getArchiveIcon(String type) {
|
||||
URL url = ResourceManager.class.getResource(String.format("archives/%s.png", type.toLowerCase()));
|
||||
if (type == null)
|
||||
type = "default";
|
||||
|
||||
if (url == null)
|
||||
url = ResourceManager.class.getResource(String.format("archives/default.png"));
|
||||
return new ImageIcon(getImage(String.format("archives/%s", type.toLowerCase()), "archives/default"));
|
||||
}
|
||||
|
||||
|
||||
public static Image getImage(String name) {
|
||||
Image image = cache.get(name);
|
||||
|
||||
return new ImageIcon(url);
|
||||
if (image == null) {
|
||||
try {
|
||||
// load image if not in cache
|
||||
URL resource = getResource(name);
|
||||
|
||||
if (resource != null) {
|
||||
image = ImageIO.read(resource);
|
||||
cache.put(name, image);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
private static Image getImage(String name, String def) {
|
||||
Image image = getImage(name);
|
||||
|
||||
// image not found, use default
|
||||
if (image == null)
|
||||
image = getImage(def);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,4 +96,5 @@ public class ResourceManager {
|
|||
|
||||
return ResourceManager.class.getResource(resource);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter;
|
|||
|
||||
public class Checksum {
|
||||
|
||||
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
|
||||
public static final String STATE_PROPERTY = "STATE_PROPERTY";
|
||||
public static final String PROGRESS_PROPERTY = "PROGRESS_PROPERTY";
|
||||
public static final String STATE_PROPERTY = "DOWNLOAD_STATE";
|
||||
public static final String PROGRESS_PROPERTY = "DOWNLOAD_PROGRESS";
|
||||
|
||||
private Long checksum = null;
|
||||
private State state = State.PENDING;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
public enum ArchiveType {
|
||||
ZIP,
|
||||
RAR,
|
||||
UNKNOWN;
|
||||
|
||||
public static ArchiveType forName(String name) {
|
||||
if (name == null)
|
||||
return UNKNOWN;
|
||||
|
||||
if (name.equalsIgnoreCase("zip"))
|
||||
return ZIP;
|
||||
|
||||
if (name.equalsIgnoreCase("rar"))
|
||||
return RAR;
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import net.sourceforge.filebot.web.MovieDescriptor;
|
||||
import net.sourceforge.filebot.web.SubtitleClient;
|
||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||
|
||||
|
||||
class FetchSubtitleListTask extends SwingWorker<List<? extends SubtitleDescriptor>, Object> {
|
||||
|
||||
private final SubtitleClient client;
|
||||
private final MovieDescriptor descriptor;
|
||||
|
||||
private long duration = -1;
|
||||
|
||||
|
||||
public FetchSubtitleListTask(MovieDescriptor descriptor, SubtitleClient client) {
|
||||
this.descriptor = descriptor;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<? extends SubtitleDescriptor> doInBackground() throws Exception {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
List<? extends SubtitleDescriptor> list = client.getSubtitleList(descriptor);
|
||||
|
||||
duration = System.currentTimeMillis() - start;
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public SubtitleClient getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
public MovieDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class LanguageResolver {
|
||||
|
||||
private static final LanguageResolver defaultInstance = new LanguageResolver();
|
||||
|
||||
|
||||
public static LanguageResolver getDefault() {
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
private final Map<String, Locale> localeMap = new HashMap<String, Locale>();
|
||||
|
||||
|
||||
/**
|
||||
* Get the locale for a language.
|
||||
*
|
||||
* @param languageName english name of the language
|
||||
* @return the locale for this language or null if no locale for this language exists
|
||||
*/
|
||||
public synchronized Locale getLocale(String languageName) {
|
||||
languageName = languageName.toLowerCase();
|
||||
|
||||
Locale locale = localeMap.get(languageName);
|
||||
|
||||
if (locale == null) {
|
||||
locale = findLocale(languageName);
|
||||
localeMap.put(languageName, locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the ISO 639 language code for a language.
|
||||
*
|
||||
* @param languageName english name of the language
|
||||
* @return lowercase ISO 639 language code
|
||||
* @see Locale#getLanguage()
|
||||
*/
|
||||
public String getLanguageCode(String languageName) {
|
||||
Locale locale = getLocale(languageName);
|
||||
|
||||
if (locale != null)
|
||||
return locale.getLanguage();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private Locale findLocale(String languageName) {
|
||||
for (Locale locale : Locale.getAvailableLocales()) {
|
||||
if (locale.getDisplayLanguage(Locale.ENGLISH).toLowerCase().equals(languageName))
|
||||
return locale;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||
import net.sourceforge.tuned.ui.ColorTintImageFilter;
|
||||
import net.sourceforge.tuned.ui.IconViewCellRenderer;
|
||||
|
||||
|
||||
public class SubtitleCellRenderer extends IconViewCellRenderer {
|
||||
|
||||
//TODO rename info to e.g. language
|
||||
private final JLabel info1 = new JLabel();
|
||||
private final JLabel info2 = new JLabel();
|
||||
|
||||
private Color infoForegroundDeselected = new Color(0x808080);
|
||||
|
||||
// TODO gscheid machn
|
||||
private Icon icon;
|
||||
|
||||
|
||||
public SubtitleCellRenderer() {
|
||||
info1.setBorder(null);
|
||||
info2.setBorder(null);
|
||||
|
||||
info1.setHorizontalTextPosition(SwingConstants.LEFT);
|
||||
|
||||
getContentPane().add(info1);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
|
||||
SubtitleDescriptor subtitle = (SubtitleDescriptor) value;
|
||||
|
||||
setText(subtitle.getName());
|
||||
|
||||
info1.setText(subtitle.getLanguageName());
|
||||
info2.setText(subtitle.getAuthor());
|
||||
|
||||
icon = (ResourceManager.getFlagIcon(LanguageResolver.getDefault().getLocale(subtitle.getLanguageName()).getLanguage()));
|
||||
|
||||
info1.setIcon(icon);
|
||||
|
||||
ImageIcon icon = ResourceManager.getArchiveIcon(subtitle.getArchiveType());
|
||||
|
||||
if (isSelected) {
|
||||
setIcon(new ImageIcon(createImage(new FilteredImageSource(icon.getImage().getSource(), new ColorTintImageFilter(list.getSelectionBackground(), 0.5f)))));
|
||||
|
||||
info1.setForeground(list.getSelectionForeground());
|
||||
info2.setForeground(list.getSelectionForeground());
|
||||
} else {
|
||||
setIcon(icon);
|
||||
|
||||
info1.setForeground(infoForegroundDeselected);
|
||||
info2.setForeground(infoForegroundDeselected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
//TODO gscheid machn
|
||||
g.translate(36, 43);
|
||||
// icon.paintIcon(this, g, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||
import net.sourceforge.tuned.DownloadTask;
|
||||
|
||||
|
||||
public class SubtitlePackage {
|
||||
|
||||
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
|
||||
|
||||
private DownloadTask downloadTask = null;
|
||||
|
||||
private final SubtitleDescriptor subtitleDescriptor;
|
||||
|
||||
|
||||
public SubtitlePackage(SubtitleDescriptor subtitleDescriptor) {
|
||||
this.subtitleDescriptor = subtitleDescriptor;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return subtitleDescriptor.getName();
|
||||
}
|
||||
|
||||
|
||||
public ArchiveType getArchiveType() {
|
||||
return ArchiveType.forName(subtitleDescriptor.getArchiveType());
|
||||
}
|
||||
|
||||
|
||||
public Icon getArchiveIcon() {
|
||||
return ResourceManager.getArchiveIcon(getArchiveType().toString());
|
||||
}
|
||||
|
||||
|
||||
public String getLanguageName() {
|
||||
return subtitleDescriptor.getLanguageName();
|
||||
}
|
||||
|
||||
|
||||
public Icon getLanguageIcon() {
|
||||
return ResourceManager.getFlagIcon(LanguageResolver.getDefault().getLanguageCode(getLanguageName()));
|
||||
}
|
||||
|
||||
|
||||
public synchronized void startDownload() {
|
||||
if (downloadTask != null)
|
||||
throw new IllegalStateException("Download has been started already");
|
||||
|
||||
downloadTask = subtitleDescriptor.createDownloadTask();
|
||||
downloadTask.addPropertyChangeListener(new DownloadTaskPropertyChangeRelay());
|
||||
|
||||
downloadTask.execute();
|
||||
}
|
||||
|
||||
|
||||
public DownloadTask getDownloadTask() {
|
||||
if (downloadTask == null)
|
||||
throw new IllegalStateException("Download has not been started");
|
||||
|
||||
return downloadTask;
|
||||
}
|
||||
|
||||
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
propertyChangeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
propertyChangeSupport.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
|
||||
private class DownloadTaskPropertyChangeRelay implements PropertyChangeListener {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
propertyChangeSupport.firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -155,7 +155,7 @@ public class SubtitlePanel extends FileBotPanel {
|
|||
|
||||
private class SearchTaskListener extends SwingWorkerPropertyChangeAdapter {
|
||||
|
||||
private SubtitleListPanel subtitleSearchResultPanel;
|
||||
private SubtitleViewPanel subtitleSearchResultPanel;
|
||||
private FileBotTabComponent tabComponent;
|
||||
|
||||
|
||||
|
@ -163,7 +163,7 @@ public class SubtitlePanel extends FileBotPanel {
|
|||
public void started(PropertyChangeEvent evt) {
|
||||
SearchTask task = (SearchTask) evt.getSource();
|
||||
|
||||
subtitleSearchResultPanel = new SubtitleListPanel();
|
||||
subtitleSearchResultPanel = new SubtitleViewPanel();
|
||||
tabComponent = new FileBotTabComponent(task.query, ResourceManager.getIcon("tab.loading"));
|
||||
|
||||
tabbedPane.addTab(task.query, subtitleSearchResultPanel);
|
||||
|
@ -246,11 +246,11 @@ public class SubtitlePanel extends FileBotPanel {
|
|||
|
||||
private class FetchSubtitleListTaskListener extends SwingWorkerPropertyChangeAdapter {
|
||||
|
||||
private final SubtitleListPanel subtitleSearchResultPanel;
|
||||
private final SubtitleViewPanel subtitleSearchResultPanel;
|
||||
private final FileBotTabComponent tabComponent;
|
||||
|
||||
|
||||
public FetchSubtitleListTaskListener(SubtitleListPanel subtitleSearchResultPanel, FileBotTabComponent tabComponent) {
|
||||
public FetchSubtitleListTaskListener(SubtitleViewPanel subtitleSearchResultPanel, FileBotTabComponent tabComponent) {
|
||||
this.subtitleSearchResultPanel = subtitleSearchResultPanel;
|
||||
this.tabComponent = tabComponent;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.ListModel;
|
||||
|
||||
import net.sourceforge.filebot.Settings;
|
||||
import net.sourceforge.filebot.resources.ResourceManager;
|
||||
import net.sourceforge.filebot.web.SubtitleDescriptor;
|
||||
import net.sourceforge.tuned.ui.IconViewPanel;
|
||||
import net.sourceforge.tuned.ui.SimpleListModel;
|
||||
|
||||
|
||||
public class SubtitleViewPanel extends IconViewPanel {
|
||||
|
||||
private ListModel unfilteredModel = new SimpleListModel();
|
||||
private JPanel languageFilterPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 1));
|
||||
|
||||
private Map<String, Boolean> languageFilterSelection = new TreeMap<String, Boolean>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
|
||||
public SubtitleViewPanel() {
|
||||
setCellRenderer(new SubtitleCellRenderer());
|
||||
|
||||
languageFilterPanel.setOpaque(false);
|
||||
|
||||
getHeaderPanel().add(languageFilterPanel, BorderLayout.EAST);
|
||||
|
||||
languageFilterSelection.putAll(Settings.getSettings().getBooleanMap(Settings.SUBTITLE_LANGUAGE));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setModel(ListModel model) {
|
||||
unfilteredModel = model;
|
||||
|
||||
updateLanguageFilterButtonPanel();
|
||||
|
||||
updateFilteredModel();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ListModel getModel() {
|
||||
return unfilteredModel;
|
||||
}
|
||||
|
||||
|
||||
private void updateLanguageFilterButtonPanel() {
|
||||
|
||||
SortedSet<String> languages = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
for (int i = 0; i < unfilteredModel.getSize(); i++) {
|
||||
SubtitleDescriptor subtitle = (SubtitleDescriptor) unfilteredModel.getElementAt(i);
|
||||
languages.add(subtitle.getLanguageName());
|
||||
}
|
||||
|
||||
languageFilterPanel.removeAll();
|
||||
|
||||
for (String language : languages) {
|
||||
LanguageFilterButton languageFilterButton = createLanguageFilterButton(language);
|
||||
languageFilterButton.addItemListener(new LanguageFilterItemListener(language));
|
||||
|
||||
languageFilterPanel.add(languageFilterButton);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateFilteredModel() {
|
||||
SimpleListModel model = new SimpleListModel();
|
||||
|
||||
for (int i = 0; i < unfilteredModel.getSize(); i++) {
|
||||
SubtitleDescriptor subtitle = (SubtitleDescriptor) unfilteredModel.getElementAt(i);
|
||||
|
||||
if (isLanguageSelected(subtitle.getLanguageName())) {
|
||||
model.add(subtitle);
|
||||
}
|
||||
}
|
||||
|
||||
super.setModel(model);
|
||||
}
|
||||
|
||||
|
||||
public boolean isLanguageSelected(String language) {
|
||||
return !languageFilterSelection.containsKey(language) || languageFilterSelection.get(language);
|
||||
}
|
||||
|
||||
|
||||
private LanguageFilterButton createLanguageFilterButton(String language) {
|
||||
Locale locale = LanguageResolver.getDefault().getLocale(language);
|
||||
|
||||
boolean selected = isLanguageSelected(language);
|
||||
|
||||
if (locale != null)
|
||||
return new LanguageFilterButton(locale, selected);
|
||||
else
|
||||
return new LanguageFilterButton(language, selected);
|
||||
}
|
||||
|
||||
|
||||
private class LanguageFilterItemListener implements ItemListener {
|
||||
|
||||
private final String language;
|
||||
|
||||
|
||||
public LanguageFilterItemListener(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
boolean selected = (e.getStateChange() == ItemEvent.SELECTED);
|
||||
|
||||
languageFilterSelection.put(language, selected);
|
||||
Settings.getSettings().putBooleanMapEntry(Settings.SUBTITLE_LANGUAGE, language, selected);
|
||||
|
||||
updateFilteredModel();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
private class LanguageFilterButton extends JToggleButton {
|
||||
|
||||
public LanguageFilterButton(Locale locale, boolean selected) {
|
||||
this(locale.getDisplayLanguage(Locale.ENGLISH), ResourceManager.getFlagIcon(locale.getLanguage()), selected);
|
||||
}
|
||||
|
||||
|
||||
public LanguageFilterButton(String language, boolean selected) {
|
||||
this(language, ResourceManager.getFlagIcon(null), selected);
|
||||
}
|
||||
|
||||
|
||||
public LanguageFilterButton(String language, Icon icon, boolean selected) {
|
||||
super(icon, selected);
|
||||
|
||||
setToolTipText(language);
|
||||
setContentAreaFilled(false);
|
||||
setFocusPainted(false);
|
||||
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
|
||||
setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
AlphaComposite composite = AlphaComposite.SrcOver.derive(isSelected() ? 1.0f : 0.2f);
|
||||
g2d.setComposite(composite);
|
||||
|
||||
super.paintComponent(g2d);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JToolTip createToolTip() {
|
||||
System.out.println("SubtitleViewPanel.createToolTip()");
|
||||
return super.createToolTip();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
|
||||
package net.sourceforge.filebot.ui.panel.subtitle;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sourceforge.filebot.FileBotUtil;
|
||||
|
||||
|
||||
public class Unrar {
|
||||
|
||||
private static final Command command = getCommand();
|
||||
|
||||
private static final int timeout = 5000;
|
||||
private static final int sleepInterval = 50;
|
||||
|
||||
|
||||
public static void extractFiles(File archive, File destination) throws Exception {
|
||||
if (command == null) {
|
||||
throw new IllegalStateException("Unrar could not be initialized");
|
||||
}
|
||||
|
||||
Process process = command.execute(archive, destination);
|
||||
|
||||
int counter = 0;
|
||||
|
||||
while (isRunning(process)) {
|
||||
Thread.sleep(sleepInterval);
|
||||
counter += sleepInterval;
|
||||
|
||||
if (counter > timeout) {
|
||||
process.destroy();
|
||||
throw new TimeoutException(String.format("%s timed out", command.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
if (process.exitValue() != 0) {
|
||||
throw new Exception(String.format("%s returned with exit value %d", command.getName(), process.exitValue()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean isRunning(Process process) {
|
||||
try {
|
||||
// will throw exception if process is still running
|
||||
process.exitValue();
|
||||
|
||||
// process has terminated
|
||||
return false;
|
||||
} catch (IllegalThreadStateException e) {
|
||||
// process is still running
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Command getCommand() {
|
||||
try {
|
||||
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
File programFiles = new File(System.getenv("PROGRAMFILES"));
|
||||
|
||||
for (File folder : programFiles.listFiles(FileBotUtil.FOLDERS_ONLY)) {
|
||||
String name = folder.getName().toLowerCase();
|
||||
|
||||
if (name.contains("rar") || name.contains("zip")) {
|
||||
for (File file : folder.listFiles(FileBotUtil.FILES_ONLY)) {
|
||||
String filename = file.getName();
|
||||
|
||||
if (filename.equalsIgnoreCase("unrar.exe") || filename.equalsIgnoreCase("7z.exe")) {
|
||||
return new Command(filename, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("External program not found");
|
||||
} else {
|
||||
String command = "unrar";
|
||||
|
||||
// will throw an exception if command cannot be executed
|
||||
Runtime.getRuntime().exec(command);
|
||||
|
||||
return new Command(command);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Cannot initialize unrar facility: " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static class Command {
|
||||
|
||||
private final String name;
|
||||
private final String executable;
|
||||
|
||||
|
||||
public Command(String command) {
|
||||
this.name = command;
|
||||
this.executable = command;
|
||||
}
|
||||
|
||||
|
||||
public Command(String name, File executable) {
|
||||
this.name = name;
|
||||
this.executable = executable.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
public Process execute(File archive, File workingDirectory) throws IOException {
|
||||
ProcessBuilder builder = new ProcessBuilder(executable, "x", "-y", archive.getAbsolutePath());
|
||||
builder.directory(workingDirectory);
|
||||
|
||||
return builder.start();
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -73,11 +73,18 @@ public class OpenSubtitlesSubtitleDescriptor implements SubtitleDescriptor {
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getLanguageName() {
|
||||
return getProperty(Properties.LanguageName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return getProperty(Properties.UserNickName);
|
||||
}
|
||||
|
||||
|
||||
public long getSize() {
|
||||
return Long.parseLong(getProperty(Properties.SubSize));
|
||||
}
|
||||
|
|
|
@ -84,10 +84,11 @@ public class SubsceneSubtitleClient extends SubtitleClient {
|
|||
|
||||
String href = XPathUtil.selectString("@href", linkNode);
|
||||
|
||||
String name = XPathUtil.selectString("./SPAN[2]", linkNode);
|
||||
String lang = XPathUtil.selectString("./SPAN[1]", linkNode);
|
||||
String name = XPathUtil.selectString("./SPAN[2]", linkNode);
|
||||
|
||||
int numberOfCDs = Integer.parseInt(XPathUtil.selectString("./TD[2]", node));
|
||||
boolean hearingImpaired = XPathUtil.selectFirstNode("./TD[3]/*[@id='imgEar']", node) != null;
|
||||
String author = XPathUtil.selectString("./TD[4]", node);
|
||||
|
||||
URL downloadUrl = new URL("http", host, downloadPath);
|
||||
|
@ -95,7 +96,7 @@ public class SubsceneSubtitleClient extends SubtitleClient {
|
|||
Map<String, String> downloadParameters = parseParameters(href);
|
||||
downloadParameters.put("__VIEWSTATE", viewstate);
|
||||
|
||||
list.add(new SubsceneSubtitleDescriptor(name, lang, numberOfCDs, author, downloadUrl, downloadParameters));
|
||||
list.add(new SubsceneSubtitleDescriptor(name, lang, numberOfCDs, author, hearingImpaired, downloadUrl, downloadParameters));
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Cannot parse subtitle node", e);
|
||||
}
|
||||
|
|
|
@ -14,22 +14,25 @@ public class SubsceneSubtitleDescriptor implements SubtitleDescriptor {
|
|||
private final String language;
|
||||
private final int numberOfCDs;
|
||||
private final String author;
|
||||
private final boolean hearingImpaired;
|
||||
|
||||
private final Map<String, String> downloadParameters;
|
||||
private final URL downloadUrl;
|
||||
|
||||
|
||||
public SubsceneSubtitleDescriptor(String title, String language, int numberOfCDs, String author, URL downloadUrl, Map<String, String> downloadParameters) {
|
||||
public SubsceneSubtitleDescriptor(String title, String language, int numberOfCDs, String author, boolean hearingImpaired, URL downloadUrl, Map<String, String> downloadParameters) {
|
||||
this.title = title;
|
||||
this.language = language;
|
||||
this.numberOfCDs = numberOfCDs;
|
||||
this.author = author;
|
||||
this.hearingImpaired = hearingImpaired;
|
||||
|
||||
this.downloadUrl = downloadUrl;
|
||||
this.downloadParameters = downloadParameters;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return title;
|
||||
}
|
||||
|
@ -50,11 +53,18 @@ public class SubsceneSubtitleDescriptor implements SubtitleDescriptor {
|
|||
}
|
||||
|
||||
|
||||
public boolean getHearingImpaired() {
|
||||
return hearingImpaired;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DownloadTask createDownloadTask() {
|
||||
return new DownloadTask(downloadUrl, downloadParameters);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getArchiveType() {
|
||||
return downloadParameters.get("typeId");
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ public interface SubtitleDescriptor {
|
|||
public String getLanguageName();
|
||||
|
||||
|
||||
public String getAuthor();
|
||||
|
||||
|
||||
public String getArchiveType();
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import javax.swing.SwingWorker;
|
|||
public class DownloadTask extends SwingWorker<ByteBuffer, Object> {
|
||||
|
||||
public static final String DOWNLOAD_STATE = "download state";
|
||||
public static final String BYTES_READ = "bytes read";
|
||||
public static final String DOWNLOAD_PROGRESS = "download progress";
|
||||
|
||||
|
||||
public static enum DownloadState {
|
||||
|
@ -84,11 +84,11 @@ public class DownloadTask extends SwingWorker<ByteBuffer, Object> {
|
|||
int len = 0;
|
||||
|
||||
try {
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
while (((len = in.read(buffer)) > 0) && !isCancelled()) {
|
||||
out.write(buffer, 0, len);
|
||||
|
||||
bytesRead += len;
|
||||
getPropertyChangeSupport().firePropertyChange(BYTES_READ, null, bytesRead);
|
||||
getPropertyChangeSupport().firePropertyChange(DOWNLOAD_PROGRESS, null, bytesRead);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// IOException (Premature EOF) is always thrown when the size of
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.RGBImageFilter;
|
||||
|
||||
|
||||
public class ColorTintImageFilter extends RGBImageFilter {
|
||||
|
||||
private Color color;
|
||||
private float intensity;
|
||||
|
||||
|
||||
public ColorTintImageFilter(Color color, float intensity) {
|
||||
this.color = color;
|
||||
this.intensity = intensity;
|
||||
|
||||
canFilterIndexColorModel = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int filterRGB(int x, int y, int rgb) {
|
||||
Color c = new Color(rgb, true);
|
||||
|
||||
int red = (int) ((c.getRed() * (1 - intensity)) + color.getRed() * intensity);
|
||||
int green = (int) ((c.getGreen() * (1 - intensity)) + color.getGreen() * intensity);
|
||||
int blue = (int) ((c.getBlue() * (1 - intensity)) + color.getBlue() * intensity);
|
||||
|
||||
return new Color(red, green, blue, c.getAlpha()).getRGB();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.RectangularShape;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
|
||||
public class IconViewCellRenderer extends AbstractFancyListCellRenderer {
|
||||
|
||||
private final JLabel iconLabel = new JLabel();
|
||||
private final JLabel titleLabel = new JLabel();
|
||||
|
||||
private final ContentPane contentPane = new ContentPane();
|
||||
|
||||
|
||||
public IconViewCellRenderer() {
|
||||
super(new Insets(3, 3, 3, 3), new Insets(3, 3, 3, 3));
|
||||
|
||||
setHighlightingEnabled(false);
|
||||
|
||||
contentPane.add(titleLabel);
|
||||
contentPane.setBorder(new EmptyBorder(4, 4, 4, 4));
|
||||
|
||||
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
iconLabel.setVerticalAlignment(SwingConstants.CENTER);
|
||||
|
||||
JPanel contentPanel = new JPanel(new BorderLayout());
|
||||
contentPanel.setOpaque(false);
|
||||
|
||||
Box contentPaneContainer = new Box(BoxLayout.X_AXIS);
|
||||
contentPaneContainer.add(contentPane);
|
||||
|
||||
contentPanel.add(contentPaneContainer, BorderLayout.WEST);
|
||||
|
||||
add(iconLabel, BorderLayout.WEST);
|
||||
add(contentPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void configureListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
super.configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
|
||||
setGradientPainted(false);
|
||||
|
||||
setText(value.toString());
|
||||
contentPane.setGradientPainted(isSelected);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setForeground(Color fg) {
|
||||
super.setForeground(fg);
|
||||
|
||||
// label is null while in super constructor
|
||||
if (titleLabel != null) {
|
||||
titleLabel.setForeground(fg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setBackground(Color bg) {
|
||||
super.setBackground(bg);
|
||||
|
||||
// label is null while in super constructor
|
||||
if (titleLabel != null) {
|
||||
titleLabel.setBackground(bg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setIcon(Icon icon) {
|
||||
iconLabel.setIcon(icon);
|
||||
}
|
||||
|
||||
|
||||
public void setText(String title) {
|
||||
titleLabel.setText(title);
|
||||
}
|
||||
|
||||
|
||||
protected JComponent getContentPane() {
|
||||
return contentPane;
|
||||
}
|
||||
|
||||
|
||||
private class ContentPane extends Box {
|
||||
|
||||
private boolean gradientPainted;
|
||||
|
||||
|
||||
public ContentPane() {
|
||||
super(BoxLayout.Y_AXIS);
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
RectangularShape shape = new RoundRectangle2D.Float(0, 0, getWidth(), getHeight(), 16, 16);
|
||||
|
||||
if (gradientPainted) {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setPaint(getGradientStyle().getGradientPaint(shape, getGradientBeginColor(), getGradientEndColor()));
|
||||
g2d.fill(shape);
|
||||
}
|
||||
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
|
||||
public void setGradientPainted(boolean gradientPainted) {
|
||||
this.gradientPainted = gradientPainted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void validate() {
|
||||
// validate children, yet avoid flickering of the mouse cursor
|
||||
validateTree();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void repaint() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void repaint(long tm, int x, int y, int width, int height) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void repaint(Rectangle r) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, char oldValue, char newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, short oldValue, short newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, int oldValue, int newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, long oldValue, long newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, float oldValue, float newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, double oldValue, double newValue) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden for performance reasons.
|
||||
*/
|
||||
@Override
|
||||
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Paint;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.ListModel;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
|
||||
public class IconViewPanel extends JPanel {
|
||||
|
||||
private final JList list = new JList(new SimpleListModel());
|
||||
private final JLabel title = new JLabel();
|
||||
private final JPanel headerPanel = new JPanel(new BorderLayout());
|
||||
|
||||
|
||||
public IconViewPanel() {
|
||||
super(new BorderLayout());
|
||||
|
||||
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
|
||||
list.setVisibleRowCount(-1);
|
||||
|
||||
title.setFont(title.getFont().deriveFont(Font.BOLD));
|
||||
|
||||
headerPanel.setOpaque(false);
|
||||
headerPanel.add(title, BorderLayout.WEST);
|
||||
|
||||
setBackground(list.getBackground());
|
||||
|
||||
headerPanel.setBorder(new CompoundBorder(new GradientLineBorder(290), new EmptyBorder(2, 10, 1, 5)));
|
||||
list.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
|
||||
JScrollPane listScrollPane = new JScrollPane(list);
|
||||
listScrollPane.setBorder(null);
|
||||
|
||||
add(headerPanel, BorderLayout.NORTH);
|
||||
add(listScrollPane, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
|
||||
public JPanel getHeaderPanel() {
|
||||
return headerPanel;
|
||||
}
|
||||
|
||||
|
||||
public void setTitle(String text) {
|
||||
title.setText(text);
|
||||
}
|
||||
|
||||
|
||||
public ListCellRenderer getCellRenderer() {
|
||||
return list.getCellRenderer();
|
||||
}
|
||||
|
||||
|
||||
public void setCellRenderer(ListCellRenderer cellRenderer) {
|
||||
list.setCellRenderer(cellRenderer);
|
||||
}
|
||||
|
||||
|
||||
public ListModel getModel() {
|
||||
return list.getModel();
|
||||
}
|
||||
|
||||
|
||||
public void setModel(ListModel model) {
|
||||
list.setModel(model);
|
||||
}
|
||||
|
||||
|
||||
public void expand() {
|
||||
// TODO expand
|
||||
}
|
||||
|
||||
|
||||
public void collapse() {
|
||||
// TODO collapse
|
||||
}
|
||||
|
||||
|
||||
private class GradientLineBorder implements Border {
|
||||
|
||||
private int gradientLineWidth;
|
||||
|
||||
|
||||
public GradientLineBorder(int width) {
|
||||
this.gradientLineWidth = width;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Insets getBorderInsets(Component c) {
|
||||
return new Insets(0, 0, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
Color beginColor = list.getSelectionBackground().brighter();
|
||||
Color endColor = list.getBackground();
|
||||
|
||||
Rectangle2D shape = new Rectangle2D.Float(x, y + height - 1, gradientLineWidth, 1);
|
||||
|
||||
Paint paint = GradientStyle.LEFT_TO_RIGHT.getGradientPaint(shape, beginColor, endColor);
|
||||
g2d.setPaint(paint);
|
||||
|
||||
g2d.setComposite(AlphaComposite.SrcOver.derive(0.9f));
|
||||
|
||||
g2d.fill(shape);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
package net.sourceforge.tuned.ui;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.swing.BoundedRangeModel;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
|
||||
public class ProgressIndicator extends JComponent {
|
||||
|
||||
private BoundedRangeModel model = null;
|
||||
|
||||
private boolean indeterminate = false;
|
||||
|
||||
private float indeterminateRadius = 4.0f;
|
||||
private int indeterminateShapeCount = 1;
|
||||
|
||||
private float progressStrokeWidth = 4.5f;
|
||||
private float remainingStrokeWidth = 2.5f;
|
||||
|
||||
private Stroke progressStroke = new BasicStroke(progressStrokeWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
|
||||
private Stroke remainingStroke = new BasicStroke(remainingStrokeWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
|
||||
|
||||
private Color progressColor = Color.orange;
|
||||
private Color remainingColor = new Color(0f, 0f, 0f, 0.25f);
|
||||
private Color textColor = new Color(42, 42, 42);
|
||||
|
||||
private boolean paintText = true;
|
||||
private boolean paintBackground = false;
|
||||
|
||||
private final Rectangle2D frame = new Rectangle2D.Double();
|
||||
private final Arc2D arc = new Arc2D.Double();
|
||||
private final Ellipse2D circle = new Ellipse2D.Double();
|
||||
|
||||
|
||||
public ProgressIndicator() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
|
||||
public ProgressIndicator(BoundedRangeModel model) {
|
||||
this.model = model;
|
||||
|
||||
indeterminate = (model == null);
|
||||
|
||||
setFont(new Font(Font.DIALOG, Font.PLAIN, 8));
|
||||
}
|
||||
|
||||
|
||||
public double getProgress() {
|
||||
if (model == null)
|
||||
return 0;
|
||||
|
||||
double total = model.getMaximum() - model.getMinimum();
|
||||
double current = model.getValue() - model.getMinimum();
|
||||
|
||||
return current / total;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
if (paintBackground) {
|
||||
frame.setFrame(0, 0, getWidth(), getHeight());
|
||||
|
||||
g2d.setPaint(getBackground());
|
||||
circle.setFrame(frame);
|
||||
g2d.fill(circle);
|
||||
}
|
||||
|
||||
frame.setFrame(progressStrokeWidth, progressStrokeWidth, getWidth() - progressStrokeWidth * 2 - 1, getHeight() - progressStrokeWidth * 2 - 1);
|
||||
|
||||
if (!indeterminate) {
|
||||
paintProgress(g2d);
|
||||
} else {
|
||||
paintIndeterminate(g2d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void paintProgress(Graphics2D g2d) {
|
||||
|
||||
double progress = getProgress();
|
||||
|
||||
// remaining circle
|
||||
circle.setFrame(frame);
|
||||
|
||||
g2d.setStroke(remainingStroke);
|
||||
g2d.setPaint(remainingColor);
|
||||
|
||||
g2d.draw(circle);
|
||||
|
||||
// progress circle
|
||||
arc.setArc(frame, 90, progress * 360 * -1, Arc2D.OPEN);
|
||||
|
||||
g2d.setStroke(progressStroke);
|
||||
g2d.setPaint(progressColor);
|
||||
|
||||
g2d.draw(arc);
|
||||
|
||||
if (paintText) {
|
||||
// text
|
||||
g2d.setFont(getFont());
|
||||
g2d.setPaint(textColor);
|
||||
|
||||
String text = String.format("%d%%", (int) (100 * progress));
|
||||
Rectangle2D textBounds = g2d.getFontMetrics().getStringBounds(text, g2d);
|
||||
|
||||
g2d.drawString(text, (float) (frame.getCenterX() - textBounds.getX() - (textBounds.getWidth() / 2f) + 0.5f), (float) (frame.getCenterY() - textBounds.getY() - (textBounds.getHeight() / 2)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void paintIndeterminate(Graphics2D g2d) {
|
||||
circle.setFrame(frame);
|
||||
|
||||
g2d.setStroke(remainingStroke);
|
||||
g2d.setPaint(remainingColor);
|
||||
|
||||
g2d.draw(circle);
|
||||
|
||||
Point2D center = new Point2D.Double(frame.getCenterX(), frame.getMinY());
|
||||
|
||||
circle.setFrameFromCenter(center, new Point2D.Double(center.getX() + indeterminateRadius, center.getY() + indeterminateRadius));
|
||||
|
||||
g2d.setStroke(progressStroke);
|
||||
g2d.setPaint(progressColor);
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
|
||||
double theta = getTheta(now.get(Calendar.MILLISECOND), now.getMaximum(Calendar.MILLISECOND));
|
||||
g2d.rotate(theta, frame.getCenterX(), frame.getCenterY());
|
||||
|
||||
theta = getTheta(1, indeterminateShapeCount);
|
||||
|
||||
for (int i = 0; i < indeterminateShapeCount; i++) {
|
||||
g2d.rotate(theta, frame.getCenterX(), frame.getCenterY());
|
||||
g2d.fill(circle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private double getTheta(int value, int max) {
|
||||
return ((double) value / max) * 2 * Math.PI;
|
||||
}
|
||||
|
||||
|
||||
public BoundedRangeModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
public void setModel(BoundedRangeModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
|
||||
public boolean isIndeterminate() {
|
||||
return indeterminate;
|
||||
}
|
||||
|
||||
|
||||
public void setIndeterminate(boolean indeterminate) {
|
||||
this.indeterminate = indeterminate;
|
||||
}
|
||||
|
||||
|
||||
public void setIndeterminateRadius(float indeterminateRadius) {
|
||||
this.indeterminateRadius = indeterminateRadius;
|
||||
}
|
||||
|
||||
|
||||
public void setIndeterminateShapeCount(int indeterminateShapeCount) {
|
||||
this.indeterminateShapeCount = indeterminateShapeCount;
|
||||
}
|
||||
|
||||
|
||||
public void setProgressColor(Color progressColor) {
|
||||
this.progressColor = progressColor;
|
||||
}
|
||||
|
||||
|
||||
public void setRemainingColor(Color remainingColor) {
|
||||
this.remainingColor = remainingColor;
|
||||
}
|
||||
|
||||
|
||||
public void setTextColor(Color textColor) {
|
||||
this.textColor = textColor;
|
||||
}
|
||||
|
||||
|
||||
public void setPaintBackground(boolean paintBackground) {
|
||||
this.paintBackground = paintBackground;
|
||||
}
|
||||
|
||||
|
||||
public void setPaintText(boolean paintString) {
|
||||
this.paintText = paintString;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
package net.sourceforge.tuned.ui;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Window;
|
||||
|
@ -17,6 +18,11 @@ import javax.swing.Timer;
|
|||
|
||||
public class TunedUtil {
|
||||
|
||||
private TunedUtil() {
|
||||
// hide constructor
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue