package org.limewire.ui.swing.library; import static org.limewire.ui.swing.util.I18n.tr; import java.awt.Color; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTextField; import net.miginfocom.swing.MigLayout; import org.jdesktop.application.Resource; import org.jdesktop.swingx.painter.RectanglePainter; import org.limewire.core.api.Category; import org.limewire.core.api.library.LocalFileItem; import org.limewire.ui.swing.components.FancyTab; import org.limewire.ui.swing.components.FancyTabList; import org.limewire.ui.swing.components.NoOpAction; import org.limewire.ui.swing.components.PromptTextField; import org.limewire.ui.swing.components.TabActionMap; import org.limewire.ui.swing.components.TextFieldClipboardControl; import org.limewire.ui.swing.components.decorators.TextFieldDecorator; import org.limewire.ui.swing.library.table.AbstractLibraryFormat; import org.limewire.ui.swing.library.table.AllTableFormat; import org.limewire.ui.swing.library.table.AudioTableFormat; import org.limewire.ui.swing.library.table.DocumentTableFormat; import org.limewire.ui.swing.library.table.ImageTableFormat; import org.limewire.ui.swing.library.table.OtherTableFormat; import org.limewire.ui.swing.library.table.ProgramTableFormat; import org.limewire.ui.swing.library.table.TorrentTableFormat; import org.limewire.ui.swing.library.table.VideoTableFormat; import org.limewire.ui.swing.painter.BorderPainter.AccentType; import org.limewire.ui.swing.settings.SwingUiSettings; import org.limewire.ui.swing.util.GuiUtils; import org.limewire.ui.swing.util.I18n; import com.google.inject.Inject; import com.google.inject.Provider; public class LibraryFilterPanel { @Resource Color backgroundColor; @Resource Color borderColor; @Resource Font buttonFont; @Resource Color fontColor; @Resource Color fontSelectedColor; @Resource Color selectionTopGradientColor; @Resource Color selectionBottomGradientColor; @Resource Color selectionBorderTopColor; @Resource Color selectionBorderBottomColor; @Resource Color highlightBackgroundColor; @Resource Color highlightBorderColor; private final JPanel component; private final PromptTextField promptTextField; private final FancyTabList categoryList; private final List<TabActionMap> categoryActionMaps; private final List<LibraryCategoryListener> listeners; private Action allAction; @Inject public LibraryFilterPanel(Provider<AllTableFormat<LocalFileItem>> allFormat, Provider<AudioTableFormat<LocalFileItem>> audioFormat, Provider<VideoTableFormat<LocalFileItem>> videoFormat, Provider<ImageTableFormat<LocalFileItem>> imageFormat, Provider<DocumentTableFormat<LocalFileItem>> documentFormat, Provider<ProgramTableFormat<LocalFileItem>> programFormat, Provider<OtherTableFormat<LocalFileItem>> otherFormat, Provider<TorrentTableFormat<LocalFileItem>> torrentFormat, TextFieldDecorator textFieldDecorator) { GuiUtils.assignResources(this); this.categoryActionMaps = new ArrayList<TabActionMap>(); addCategory(tr("All") + " ", null, allFormat); addCategory(tr("Audio"), Category.AUDIO, audioFormat); addCategory(tr("Videos"), Category.VIDEO, videoFormat); addCategory(tr("Images"), Category.IMAGE, imageFormat); addCategory(tr("Documents"), Category.DOCUMENT, documentFormat); addCategory(tr("Programs"), Category.PROGRAM, programFormat); addCategory(tr("Torrents"), Category.TORRENT, torrentFormat); addCategory(tr("Other"), Category.OTHER, otherFormat); component = new JPanel(new MigLayout("insets 0 5 0 5, gap 0, fill", "", "[28!]")); promptTextField = new PromptTextField(I18n.tr("Filter")); categoryList = new FancyTabList(categoryActionMaps); categoryList.setSelectionPainter(new CategoryTabPainter(selectionTopGradientColor, selectionBottomGradientColor, selectionBorderTopColor, selectionBorderBottomColor)); categoryList.setHighlightPainter(new CategoryTabPainter(highlightBackgroundColor, highlightBackgroundColor, highlightBorderColor, highlightBorderColor)); this.listeners = new CopyOnWriteArrayList<LibraryCategoryListener>(); init(textFieldDecorator); component.setVisible(SwingUiSettings.SHOW_LIBRARY_FILTERS.getValue()); } private void init(TextFieldDecorator textFieldDecorator) { component.setBackground(backgroundColor); component.setBorder(BorderFactory.createMatteBorder(0,0,1,0, borderColor)); TextFieldClipboardControl.install(promptTextField); textFieldDecorator.decorateClearablePromptField(promptTextField, AccentType.NONE); categoryList.setTabTextColor(fontColor); categoryList.setTextFont(buttonFont); categoryList.setTabTextSelectedColor(fontSelectedColor); categoryList.setUnderlineEnabled(false); component.add(categoryList, "growy"); component.add(promptTextField, "alignx right"); // track usage of library text filter TextFilterUsageTracker usageTracker = new TextFilterUsageTracker(); promptTextField.addFocusListener(usageTracker); promptTextField.addKeyListener(usageTracker); } public JComponent getComponent() { return component; } void addSearchTabListener(LibraryCategoryListener listener) { listeners.add(listener); } public AbstractLibraryFormat<LocalFileItem> getSelectedTableFormat() { return ((LibraryCategoryAction)categoryList.getSelectedTab().getTabActionMap().getMainAction()).getTableFormat(); } public void clearFilters() { promptTextField.setText(""); allAction.putValue(Action.SELECTED_KEY, true); allAction.actionPerformed(null); } public JTextField getFilterField() { return promptTextField; } /** * Sets the selected category and the filter text on the current table. Note this * does not fire an action changed event. It simply updates the state of this * component. */ public void setSelectedCategory(Category category, String filterText) { if(category == null) { allAction.putValue(Action.SELECTED_KEY, true); } else { for(TabActionMap action : categoryActionMaps) { if(action.getMainAction() instanceof LibraryCategoryAction) { LibraryCategoryAction categoryAction = (LibraryCategoryAction) action.getMainAction(); if(categoryAction.getCategory() == category) { categoryAction.putValue(Action.SELECTED_KEY, true); break; } } } } promptTextField.setText(filterText == null ? "" : filterText); } public Category getSelectedCategory() { return ((LibraryCategoryAction)categoryList.getSelectedTab().getTabActionMap().getMainAction()).getCategory(); } private void addCategory(String title, Category category, Provider<? extends AbstractLibraryFormat<LocalFileItem>> tableFormat) { LibraryCategoryAction action = new LibraryCategoryAction(title, category, tableFormat); if(category == null) { action.putValue(Action.SELECTED_KEY, true); allAction = action; } TabActionMap map = newTabActionMap(action); categoryActionMaps.add(map); } private TabActionMap newTabActionMap(LibraryCategoryAction action) { Action moreText = new NoOpAction(); moreText.putValue(Action.NAME, ""); return new TabActionMap(action, null, moreText, null); } private class LibraryCategoryAction extends AbstractAction { private final Category category; private final Provider<? extends AbstractLibraryFormat<LocalFileItem>> tableFormat; public LibraryCategoryAction(String name, Category category, Provider<? extends AbstractLibraryFormat<LocalFileItem>> tableFormat) { super(name); this.category = category; this.tableFormat = tableFormat; } Category getCategory() { return category; } public AbstractLibraryFormat<LocalFileItem> getTableFormat() { return tableFormat.get(); } @Override public void actionPerformed(ActionEvent e) { for(LibraryCategoryListener listener : listeners) { listener.categorySelected(category); } } } static interface LibraryCategoryListener { void categorySelected(Category category); } /** * Creates a Painter used to render the selected category tab. */ private static class CategoryTabPainter extends RectanglePainter<FancyTab> { public CategoryTabPainter(Color topGradient, Color bottomGradient, Color topBorder, Color bottomBorder) { setFillPaint(new GradientPaint(0, 0, topGradient, 0, 1, bottomGradient)); setBorderPaint(new GradientPaint(0, 0, topBorder, 0, 1, bottomBorder)); setRoundHeight(10); setRoundWidth(10); setRounded(true); setPaintStretched(true); setInsets(new Insets(2,0,1,0)); setAntialiasing(true); setCacheable(true); } } private static class TextFilterUsageTracker extends KeyAdapter implements KeyListener, FocusListener { private boolean canCountUsageIfKeyIsPressed; @Override public void keyTyped(KeyEvent e) { if (canCountUsageIfKeyIsPressed) { canCountUsageIfKeyIsPressed = false; } } @Override public void focusGained(FocusEvent e) { canCountUsageIfKeyIsPressed = true; } @Override public void focusLost(FocusEvent e) { canCountUsageIfKeyIsPressed = false; } } }