package org.limewire.ui.swing.options; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.limewire.collection.CollectionUtils; import org.limewire.core.api.Category; import org.limewire.core.api.library.LibraryData; import org.limewire.core.api.library.LibraryManager; import org.limewire.core.settings.LibrarySettings; import org.limewire.setting.evt.SettingEvent; import org.limewire.setting.evt.SettingListener; import org.limewire.ui.swing.action.AbstractAction; import org.limewire.ui.swing.components.CheckBoxList; import org.limewire.ui.swing.components.Disposable; import org.limewire.ui.swing.components.CheckBoxList.CheckBoxListCheckChangeEvent; import org.limewire.ui.swing.components.CheckBoxList.CheckBoxListCheckChangeListener; import org.limewire.ui.swing.components.CheckBoxList.CheckBoxListSelectionEvent; import org.limewire.ui.swing.components.CheckBoxList.CheckBoxListSelectionListener; import org.limewire.ui.swing.util.CategoryIconManager; import org.limewire.ui.swing.util.CategoryUtils; import org.limewire.ui.swing.util.I18n; import org.limewire.ui.swing.util.IconManager; import org.limewire.util.MediaType; import com.google.inject.Inject; import com.google.inject.Provider; /** * Constructs the file type sharing panel to be used in the options * menu and setup manager. Includes external interface for saving * and reloading settings. */ public final class FileTypeOptionPanelManager implements Disposable { private static final int MAX_EXT_LENGTH = 7; private JPanel mainContainer; private CardLayout mediaLayout; private JPanel currentPanel; private CheckBoxList<Category> sidePanel; private Map<Category,CheckBoxList<String>> panels; private final ExtensionProvider extensionProvider = new ExtensionProvider(); private final ExtensionsExtrasProvider extensionExtrasProvider = new ExtensionsExtrasProvider(); private Set<Category> mediaKeys; private Set<Category> mediaUnchecked; private Category currentKey; private final Collection<String> originalExtensions; private final CategoryIconManager categoryIconManager; private final Provider<IconManager> iconManager; private final LibraryData libraryData; private JButton addButton; private JTextField extTextField; private Set<String> removableExts; private Action addAction = new AbstractAction(I18n.tr("Add New Extension")) { @Override public void actionPerformed(ActionEvent arg0) { addNewExt(); } }; private final PanelsCheckChangeListener refreshListener; private SettingListener programsListener; @Inject public FileTypeOptionPanelManager(CategoryIconManager categoryIconManager, Provider<IconManager> iconManager, LibraryManager libraryManager) { this.categoryIconManager = categoryIconManager; this.iconManager = iconManager; this.libraryData = libraryManager.getLibraryData(); this.originalExtensions = CollectionUtils.flatten(libraryData.getExtensionsPerCategory().values()); refreshListener = new PanelsCheckChangeListener(this); } @Inject public void register() { programsListener = new SettingListener() { @Override public void settingChanged(SettingEvent evt) { SwingUtilities.invokeLater(new Runnable(){ public void run() { if (sidePanel == null) { return; } if (LibrarySettings.ALLOW_PROGRAMS.getValue()) { sidePanel.removeItem(Category.PROGRAM); } else { sidePanel.addItem(Category.PROGRAM); } } }); } }; LibrarySettings.ALLOW_PROGRAMS.addSettingListener(programsListener); } @Override public void dispose() { LibrarySettings.ALLOW_PROGRAMS.removeSettingListener(programsListener); } /** * Switches the active media panel to the one of the given key. */ private void switchPanel(Category mediaKey) { this.currentKey = mediaKey; this.mediaLayout.show(currentPanel, mediaKey.toString()); this.sidePanel.setItemSelected(mediaKey); } /** * Repaints the side panel (to update comment text). */ private void refreshSidePanel() { this.sidePanel.update(); } /** * Sets the enabled setting of a panel of a given key. */ private void setPanelEnabled(Category mediaKey, boolean enabled) { this.panels.get(mediaKey).setEnabled(enabled); } /** * Returns the panel that this class is used to produce. */ public Container getContainer() { return this.mainContainer; } void initCore() { Collection<String> selectedExts = CollectionUtils.flatten(libraryData.getExtensionsPerCategory().values()); Collection<String> allExts = new TreeSet<String>(); removableExts = new HashSet<String>(); for ( MediaType type : MediaType.getDefaultMediaTypes() ) { allExts.addAll(type.getExtensions()); } allExts.addAll(libraryData.getDefaultExtensions()); allExts.addAll(selectedExts); Map<Category, List<String>> extensionsByType = createExtensionsMap(allExts); this.mediaKeys = new TreeSet<Category>(); Set<Category> s; if ((s = extensionsByType.keySet()) != null) { this.mediaKeys.addAll(s); } this.panels = new LinkedHashMap<Category,CheckBoxList<String>>(); this.mediaUnchecked = new HashSet<Category>(); this.currentKey = null; for (Category key : mediaKeys) { if (this.currentKey == null) { this.currentKey = key; } Collection<String> extensionsInCategory = extensionsByType.get(key); Collection<String> notSelectedInCategory = new HashSet<String>(extensionsInCategory); notSelectedInCategory.removeAll(selectedExts); CheckBoxList<String> newPanel = new CheckBoxList<String>(extensionsInCategory, notSelectedInCategory, extensionProvider, extensionExtrasProvider, CheckBoxList.SELECT_FIRST_OFF); newPanel.setCheckChangeListener(refreshListener); if (extensionsInCategory.equals(notSelectedInCategory)) { newPanel.setEnabled(false); this.mediaUnchecked.add(key); } this.panels.put(key, newPanel); } CheckBoxList<String> otherPanel = panels.get(Category.OTHER); for ( String item : removableExts ) { otherPanel.setRemovable(item, true); } } public void buildUI() { if (this.panels.isEmpty()) { return; } this.mainContainer = new JPanel(new BorderLayout()); this.mainContainer.setOpaque(false); this.mediaLayout = new CardLayout(); this.currentPanel = new JPanel(mediaLayout); for (Category key : mediaKeys) { this.currentPanel.add(this.panels.get(key), key.toString()); } this.sidePanel = new CheckBoxList<Category>(this.mediaKeys, this.mediaUnchecked, new MediaProvider(), new MediaExtrasProvider(), CheckBoxList.SELECT_FIRST_ON); if (!LibrarySettings.ALLOW_PROGRAMS.getValue()) { sidePanel.removeItem(Category.PROGRAM); } this.sidePanel.setPreferredSize(new Dimension(150, 0)); this.sidePanel.setSelectionListener(new SideSelectListener(this)); this.sidePanel.setCheckChangeListener(new CheckChangeListener(this)); this.sidePanel.setItemSelected(this.currentKey); this.sidePanel.setCheckBoxesVisible(false); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this.sidePanel, this.currentPanel); splitPane.setOneTouchExpandable(true); splitPane.setDividerLocation(180); splitPane.setEnabled(false); this.mainContainer.add(splitPane, BorderLayout.CENTER); JPanel addExtPanel = new JPanel(new MigLayout("insets 5, gap 10, alignx right")); addExtPanel.setOpaque(false); addExtPanel.add(new JLabel(I18n.tr("File Extension:"))); extTextField = new JTextField(6); addExtPanel.add(extTextField); addButton = new JButton(addAction); addExtPanel.add(addButton); mainContainer.add(addExtPanel, BorderLayout.SOUTH); this.mainContainer.validate(); } private void addNewExt() { String text = extTextField.getText(); if (text == null || text.isEmpty()) { return; } extTextField.setText(""); if (!checkExt(text)) { return; } CheckBoxList<String> otherPanel = panels.get(Category.OTHER); otherPanel.addItem(text); otherPanel.setItemChecked(text); otherPanel.setRemovable(text, true); otherPanel.setItemSelected(text); switchPanel(Category.OTHER); } private boolean checkExt(String text) { if (text == null) { return false; } CheckBoxList<String> otherPanel = panels.get(Category.OTHER); String malformedMsg = I18n.tr("The extension name was not valid, could not add."); if ( text.length() == 0 || text.length() > MAX_EXT_LENGTH || text.indexOf('.') > -1 ) { JOptionPane.showMessageDialog(null, malformedMsg); return false; } if (contains(libraryData.getDefaultExtensions(), text)) { Category type = CategoryUtils.getCategory(MediaType.getMediaTypeForExtension(text)); if (type == null) { type = Category.OTHER; } CheckBoxList<String> panel = this.panels.get(type); if (panel == null) { JOptionPane.showMessageDialog(null, malformedMsg); return false; } this.switchPanel(type); panel.setItemChecked(text); this.sidePanel.setItemSelected(type); return false; } if (otherPanel.getElements().contains(text)) { this.switchPanel(Category.OTHER); otherPanel.setItemChecked(text); this.sidePanel.setItemSelected(Category.OTHER); return false; } return true; } private static boolean contains(Collection<String> list, String value) { for ( Object item : list ) { if (item.equals(value)) { return true; } } return false; } private Map<Category, List<String>> createExtensionsMap(Collection<String> extensions) { Map<Category, List<String>> extensionsByType = new LinkedHashMap<Category, List<String>>(); for (String extension : extensions) { Category category = CategoryUtils.getCategory(MediaType.getMediaTypeForExtension(extension)); if (category == null) { category = CategoryUtils.getCategory(MediaType.getOtherMediaType()); } if (!extensionsByType.containsKey(category)) { extensionsByType.put(category, new ArrayList<String>(8)); } List<String> typeExtension = extensionsByType.get(category); if (!typeExtension.contains(extension)) { typeExtension.add(extension); if (category == Category.OTHER) { if (!contains(libraryData.getDefaultExtensions(), extension)) { removableExts.add(extension); } } } } return extensionsByType; } private Collection<String> getExtensions() { Set<String> elements = new HashSet<String>(); for ( CheckBoxList<String> panel : this.panels.values() ) { elements.addAll(panel.getCheckedElements()); } return elements; } // Methods to integrate with PaneItem public void initOptions() { this.initCore(); } public boolean applyOptions() { libraryData.setManagedExtensions(getExtensions()); return false; } public boolean hasChanged() { return !this.originalExtensions.equals(this.getExtensions()); } // Listener Classes private static class SideSelectListener implements CheckBoxListSelectionListener { private FileTypeOptionPanelManager parent; public SideSelectListener(FileTypeOptionPanelManager parent) { this.parent = parent; } public void valueChanged(CheckBoxListSelectionEvent e) { parent.switchPanel((Category)e.getSelected()); } } private static class CheckChangeListener implements CheckBoxListCheckChangeListener<Category> { private FileTypeOptionPanelManager parent; public CheckChangeListener(FileTypeOptionPanelManager parent) { this.parent = parent; } public void valueChanged(CheckBoxListCheckChangeEvent<Category> e) { this.parent.setPanelEnabled(e.getSelected(), e.getChecked()); this.parent.refreshSidePanel(); } } private static class PanelsCheckChangeListener implements CheckBoxListCheckChangeListener<MediaType> { private FileTypeOptionPanelManager parent; public PanelsCheckChangeListener(FileTypeOptionPanelManager parent) { this.parent = parent; } public void valueChanged(CheckBoxListCheckChangeEvent<MediaType> e) { this.parent.refreshSidePanel(); } } // Providers private class ExtensionProvider implements CheckBoxList.TextProvider<String> { public String getText(String obj) { if (obj == null) { new NullPointerException("Null object passed to text lookup."); } return obj; } public String getToolTipText(String obj) { return iconManager.get().getMIMEDescription(obj); } public Icon getIcon(String obj) { if (obj == null) { throw new NullPointerException("Null object passed to icon lookup."); } Icon icon = iconManager.get().getIconForExtension(obj); return icon != null ? icon : iconManager.get().getBlankIcon(); } } private class MediaProvider implements CheckBoxList.TextProvider<Category> { public String getText(Category obj) { return obj.toString(); } public String getToolTipText(Category obj) { return null; } public Icon getIcon(Category obj) { return categoryIconManager.getIcon(obj); } } private class MediaExtrasProvider implements CheckBoxList.ExtrasProvider<Category> { public MediaExtrasProvider() { } @Override public boolean isSeparated(Category obj) { return false; } @Override public String getComment(Category obj) { CheckBoxList<String> panel = panels.get(obj); if (panel == null) { return "(0)"; } return "(" + panel.getCheckedElements().size() + ")"; } @Override public int getCommentFieldSize() { return 0; } } private class ExtensionsExtrasProvider implements CheckBoxList.ExtrasProvider<String> { public ExtensionsExtrasProvider() { } @Override public boolean isSeparated(String obj) { return false; } @Override public String getComment(String obj) { return iconManager.get().getMIMEDescription(obj); } @Override public int getCommentFieldSize() { return 70; } } }