/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* IntellicutPanelBase.java
* Creation date: (16/04/01 2:03:41 PM)
* By: Michael Cheng
*/
package org.openquark.gems.client;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.text.MessageFormat;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import org.openquark.gems.client.IntellicutListModel.FilterLevel;
import org.openquark.gems.client.IntellicutManager.IntellicutMode;
import org.openquark.gems.client.utilities.MouseClickDragAdapter;
import org.openquark.gems.client.utilities.SmoothHighlightBorder;
/**
* A Panel listing the gems that are able to be connected to the intellicut part.
* Confirmation (double-click/enter key press) will drop the selected gem down onto
* the table top, and connected to the intellicut part.
* Cancel (Esc) will close this panel.
* Creation date: (16/04/01 2:03:41 PM)
* @author Michael Cheng
*/
public class IntellicutPanel extends JPanel {
private static final long serialVersionUID = -8327460694085077388L;
/** A completely transparent background color. */
private static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0);
/** A slightly tinted background color used for the panel background. */
private static final Color BACKGROUND_TINT_COLOR = new Color(200, 200, 200, 150);
/** The icon used by the show all gems button. */
private static final ImageIcon showAllGemsIcon = new ImageIcon(GemCutter.class.getResource("/Resources/showAllGems.gif"));
/** The icon used by the show likely gems button */
private static final ImageIcon showLikelyGemsIcon = new ImageIcon(GemCutter.class.getResource("/Resources/showingGoodGems.gif"));
/** The icon used by the show best gems button */
private static final ImageIcon showBestGemsIcon = new ImageIcon(GemCutter.class.getResource("/Resources/Gem_Red.gif"));
/** The icon to display next to the title label. */
private static final ImageIcon intellicutIcon = new ImageIcon(GemCutter.class.getResource("/Resources/intellicut.gif"));
/** The mouse listener for moving the panel around. */
private final MovePanelMouseListener movePanelMouseListener = new MovePanelMouseListener();
/** The adapter class that owns this intellicut panel. */
private final IntellicutPanelOwner adapter;
/** The scrollpane that contains the intellicut list. */
private JScrollPane listScrollPane = null;
/** The intellicut list instance. */
private final IntellicutList intellicutList;
/** The button used to pick the "all" level of gem filtering */
private JToggleButton showAllGemsButton = null;
/** The button used to pick the "likely" level of gem filtering */
private JToggleButton showLikelyGemsButton = null;
/** The button used to pick the "best" level of gem filtering */
private JToggleButton showBestGemsButton = null;
/** The toolbar that contains the showGemsButton. */
private JToolBar showGemsButtonToolBar = null;
/** The button group that manages exclusion among the filter buttons */
private ButtonGroup filterButtonGroup;
/** The label that shows the status message text. */
private JLabel statusLabel = null;
/** The label that displayed the intellicut title. */
private JLabel titleLabel = null;
/** The top panel that contains the buttons and status label. */
private JPanel topPanel = null;
/** The input the user has typed. This is used to refresh the intellicut list. */
private String userInput = null;
/** The color that the type color manager recommends for the part we are trying to connect. */
private Color typeColor = null;
/** The original background color that was saved when we entered drag mode. */
private Color savedBackgroundColor = null;
/** Whether the panel is currently being dragged around by the user. */
private boolean isDragging = false;
/** Whether the current filtering setting should be saved on close */
private boolean saveFilterPreference = true;
/** Whether the filter buttons are clickable */
private boolean filtersEnabled = true;
/**
* The listener that updates the IntellicutList as the user types.
* It does so by keeping track of the String the user has typed in so far and
* and it shrinks the visible list of matching gems accordingly.
* Also closes the list if the user hits ESC or ENTER.
*/
private class IntellicutKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
int selectedIndex = intellicutList.getSelectedIndex();
IntellicutListModel listModel = (IntellicutListModel) intellicutList.getModel();
// Toggles between showing all or best gems
if (keyCode == KeyEvent.VK_T && e.isAltDown()) {
if (getShowAllGemsButton().isSelected()) {
getShowLikelyGemsButton().doClick();
} else if (getShowLikelyGemsButton().isSelected()) {
getShowBestGemsButton().doClick();
} else {
getShowAllGemsButton().doClick();
}
selectedIndex = intellicutList.getSelectedIndex();
// Moves the selection upwards and downwards
} else if (keyCode == KeyEvent.VK_UP) {
selectedIndex--;
} else if (keyCode == KeyEvent.VK_DOWN) {
selectedIndex++;
} else if (keyCode == KeyEvent.VK_PAGE_UP) {
selectedIndex -= Math.min(getNumVisibleRows() - 1, selectedIndex);
} else if (keyCode == KeyEvent.VK_PAGE_DOWN) {
int nextRow = intellicutList.getModel().getSize() - selectedIndex - 1;
selectedIndex += Math.min(getNumVisibleRows() - 1, nextRow);
} else if (keyCode == KeyEvent.VK_HOME) {
selectedIndex = 0;
} else if (keyCode == KeyEvent.VK_END) {
selectedIndex = intellicutList.getModel().getSize() - 1;
// Commits or cancels the intellicut selection
} else if (keyCode == KeyEvent.VK_ENTER) {
adapter.connectSelectedGem();
} else if (keyCode == KeyEvent.VK_ESCAPE) {
adapter.stopIntellicutPanel();
// Deletes the last character
} else if (keyCode == KeyEvent.VK_BACK_SPACE) {
// First delete previous character
if (userInput.length() > 0) {
userInput = userInput.substring(0, userInput.length() - 1);
intellicutList.refreshList(userInput);
selectedIndex = intellicutList.getSelectedIndex();
}
// Now check if we need to re-enable the filter buttons
if (userInput.length() == 0) {
setFiltersEnabled(true);
}
} else if (keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT ||
keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_META ||
keyCode == KeyEvent.VK_CAPS_LOCK || e.isActionKey() || e.getKeyChar() == ' ') {
// Do nothing.
} else {
// Adds the newly typed character to the string if necessary
String newUserInput = userInput + e.getKeyChar();
setFiltersEnabled(false);
if (listModel.hasAnyGemsFor(newUserInput)) {
userInput = newUserInput;
intellicutList.refreshList(userInput);
selectedIndex = intellicutList.getSelectedIndex();
} else {
Toolkit.getDefaultToolkit().beep();
if (userInput.length() == 0) {
setFiltersEnabled(true);
}
}
}
// Select the correct item and make it visible
if (selectedIndex >= 0 && selectedIndex < intellicutList.getModel().getSize()) {
intellicutList.setSelectedIndex(selectedIndex);
intellicutList.ensureIndexIsVisible(selectedIndex);
updateStatusLabel();
// Hide the currently displayed tooltip if we move the list selection.
// Easiest way to do this is to temporarily disable the tooltip manager.
ToolTipManager.sharedInstance().setEnabled(false);
ToolTipManager.sharedInstance().setEnabled(true);
}
e.consume();
}
}
/**
* Mouse listener that listens for double left clicks to close the list and right
* clicks to display the list popup menu.
*/
private class DoubleClickMouseListener extends MouseClickDragAdapter {
@Override
public boolean mouseReallyClicked(MouseEvent e){
// double left-click?
boolean doubleClicked = super.mouseReallyClicked(e);
// If it is the popup trigger, show the popup.
if (e.isPopupTrigger()) {
JList matchingGemsList = getIntellicutList();
int index = matchingGemsList.locationToIndex(e.getPoint());
if (index >= 0) {
matchingGemsList.setSelectedIndex(index);
JPopupMenu popupMenu = adapter.getIntellicutPopupMenu();
if (popupMenu != null) {
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
if (doubleClicked && SwingUtilities.isLeftMouseButton(e)) {
adapter.connectSelectedGem();
}
return doubleClicked;
}
}
/**
* This listener class is responsible for moving the intellicut panel if the user clicks
* on it and moves the mouse.
* @author Frank Worsley
*/
private class MovePanelMouseListener extends MouseAdapter implements MouseMotionListener {
/** The point at which the mouse was first pressed and in whose relation we are dragging. */
private Point dragPoint = null;
public void mouseDragged(MouseEvent e) {
if (dragPoint == null) {
// This shouldn't happen.
return;
}
int newX = IntellicutPanel.this.getX() + e.getX() - dragPoint.x;
int newY = IntellicutPanel.this.getY() + e.getY() - dragPoint.y;
setDragMode(true);
setLocation(newX, newY);
}
@Override
public void mousePressed(MouseEvent e) {
dragPoint = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e) {
if (isDragging) {
setDragMode(false);
intellicutList.requestFocusInWindow();
}
}
public void mouseMoved(MouseEvent e) {
}
}
/**
* IntellicutPanel constructor.
*/
public IntellicutPanel(IntellicutPanelOwner adapter,
IntellicutListModelAdapter modelAdapter,
Color typeColor, IntellicutMode mode) {
this.adapter = adapter;
this.typeColor = typeColor;
this.userInput = "";
IntellicutListModel listModel = new IntellicutListModel(modelAdapter);
intellicutList = new IntellicutList(mode);
intellicutList.setModel(listModel);
intellicutList.setCursor(Cursor.getDefaultCursor());
setLayout(new BorderLayout());
setBorder(BorderFactory.createEtchedBorder());
setMoveable(true);
if (typeColor != null) {
setBackground(typeColor);
}
listScrollPane = new JScrollPane();
listScrollPane.setViewportView(getIntellicutList());
listScrollPane.getHorizontalScrollBar().setCursor(Cursor.getDefaultCursor());
listScrollPane.getVerticalScrollBar().setCursor(Cursor.getDefaultCursor());
add(listScrollPane, BorderLayout.CENTER);
// Remove the default list key listeners. These are added by Swing to enable list
// navigation, but they screw up our own intellicut searching and navigation.
KeyListener[] keyListeners = getIntellicutList().getKeyListeners();
for (final KeyListener listenerToRemove : keyListeners) {
intellicutList.removeKeyListener(listenerToRemove);
}
// Make sure double clicks are handled by the list.
intellicutList.addMouseListener(new DoubleClickMouseListener());
// The key listener that updates the list as the user types.
KeyListener keyListener = new IntellicutKeyListener();
addKeyListener(keyListener);
intellicutList.addKeyListener(keyListener);
}
/**
* Whether or not the user should be able to move the panel around by dragging the title bar area.
* @param moveable true if panel should be movable, false otherwise
*/
public void setMoveable(boolean moveable) {
if (moveable) {
addMouseListener(movePanelMouseListener);
addMouseMotionListener(movePanelMouseListener);
} else {
removeMouseListener(movePanelMouseListener);
removeMouseMotionListener(movePanelMouseListener);
}
}
/**
* Removes the panel from its parent's display.
*/
public void close() {
if (saveFilterPreference) {
GemCutter.getPreferences().put(IntellicutManager.INTELLICUT_GEM_FILTER_LEVEL_PREF_KEY,
getIntellicutListModel().getFilterLevel().toString());
}
// Remove ourselves from our parent and repaint it.
Container parent = getParent();
if (parent != null) {
parent.remove(this);
if (parent instanceof JPopupMenu) {
JPopupMenu popupMenu = (JPopupMenu) parent;
popupMenu.setVisible(false);
}
if (parent instanceof JComponent) {
((JComponent) parent).repaint(getBounds());
} else {
parent.validate();
}
}
}
/**
* @return the IntellicutList for this panel.
*/
public IntellicutList getIntellicutList() {
return intellicutList;
}
/**
* This method modifies the preferred size of the list's scroll pane to show the desired
* number of rows. This method only works if the list model has at least one item in it. If
* called with when the list model is empty, then nothing is done.
* @param numRows the number of rows that should be visible
*/
public void setPreferredVisibleRows(int numRows) {
if (getIntellicutListModel().isEmpty()) {
return;
}
Dimension prefSize = listScrollPane.getPreferredSize();
int cellHeight = getIntellicutList().getCellBounds(0, 0).height;
int borders = listScrollPane.getInsets().top + listScrollPane.getInsets().bottom;
listScrollPane.setPreferredSize(new Dimension(prefSize.width, numRows * cellHeight + borders));
}
/**
* @return the number of rows currently visible in the Intellicut list.
*/
private int getNumVisibleRows() {
if (getIntellicutListModel().isEmpty()) {
return 0;
}
int rowHeight = intellicutList.getCellBounds(0, 0).height;
int listHeight = listScrollPane.getSize().height;
return listHeight / rowHeight;
}
/**
* @return the list model used by the intellicut list.
*/
public IntellicutListModel getIntellicutListModel() {
return (IntellicutListModel) getIntellicutList().getModel();
}
/**
* Sets the title of the intellicut panel.
* @param newTitle the new title for the list
*/
public void setTitle(String newTitle) {
getTitleLabel().setText(newTitle);
}
/**
* Initially loads the list model. This should be called after users of the panel
* have added any additional gems they want to be loaded. This is a separate call
* to make loading gems and displaying the list more efficient.
*/
public void loadListModel() {
IntellicutListModel listModel = getIntellicutListModel();
listModel.load();
FilterLevel filterLevel = FilterLevel.fromString(GemCutter.getPreferences().get(IntellicutManager.INTELLICUT_GEM_FILTER_LEVEL_PREF_KEY, IntellicutManager.INTELLICUT_GEM_FILTER_LEVEL_DEFAULT.toString()));
boolean hasBestGems = listModel.hasFilteredGemsFor("", filterLevel);
if (!hasBestGems) {
filterLevel = FilterLevel.SHOW_ALL;
}
// Processing to eliminate redundant buttons (ie, those that add no filtering)
int numEntries = listModel.numFilteredGems(FilterLevel.SHOW_ALL);
int numLikelyEntries = listModel.numFilteredGems(FilterLevel.SHOW_LIKELY);
int numBestEntries = listModel.numFilteredGems(FilterLevel.SHOW_BEST);
if ((numEntries - numLikelyEntries) < 20 || (numLikelyEntries - numBestEntries) < 20) {
getShowGemsButtonToolBar().remove(getShowLikelyGemsButton());
if (filterLevel == FilterLevel.SHOW_LIKELY) {
filterLevel = FilterLevel.SHOW_BEST;
saveFilterPreference = false; // Don't save automatically adjusted filter settings
}
}
if ((numEntries - numBestEntries) < 20 || numBestEntries == 0) {
getShowGemsButtonToolBar().remove(getShowBestGemsButton());
if (filterLevel == FilterLevel.SHOW_BEST) {
filterLevel = FilterLevel.SHOW_ALL;
saveFilterPreference = false; // Don't save automatically adjusted filter settings
}
}
listModel.setFilterLevel(filterLevel);
listModel.refreshList("");
// If there are no matching gems, display an error message and return.
if (listModel.isEmpty()) {
JLabel message = new JLabel(adapter.getMessages().getString("ICL_NoGemsFound"));
message.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
message.setIcon(intellicutIcon);
remove(listScrollPane);
add(message, BorderLayout.CENTER);
return;
}
// Add the top panel only now so that the status message and button state
// are synced up with the show all gems state of the model.
add(getTopPanel(), BorderLayout.NORTH);
if (listModel.getFilterLevel() == FilterLevel.SHOW_ALL) {
getShowAllGemsButton().getModel().setSelected(true);
} else if(listModel.getFilterLevel() == FilterLevel.SHOW_LIKELY) {
getShowLikelyGemsButton().getModel().setSelected(true);
} else if(listModel.getFilterLevel() == FilterLevel.SHOW_BEST) {
getShowBestGemsButton().getModel().setSelected(true);
}
getIntellicutList().setSelectedIndex(0);
setPreferredVisibleRows(20);
}
/**
* Enables transparency for the intellicut panel and components within it.
* If you enable transparency the panel and list will be coloured in a light tint,
* allowing you to see the components below it. Once transparency is enabled you
* can't disabled it anymore. You have to recreate the panel if you don't want
* transparency anymore.
*/
public void makeTransparent() {
// Components can not be opaque or transparency will not work. We have to
// manually draw in the background since Java screws it up for some reason.
setOpaque(false);
setBackground(BACKGROUND_TINT_COLOR);
setBorder(new SmoothHighlightBorder(typeColor != null ? typeColor : getBackground(), false));
getIntellicutList().setBackground(TRANSPARENT_COLOR);
getIntellicutList().setOpaque(false);
getIntellicutList().setTransparent(true);
listScrollPane.setBackground(TRANSPARENT_COLOR);
listScrollPane.setOpaque(false);
listScrollPane.getViewport().setBackground(TRANSPARENT_COLOR);
listScrollPane.getViewport().setOpaque(false);
getTopPanel().setBackground(TRANSPARENT_COLOR);
getTopPanel().setOpaque(false);
getStatusLabel().setBackground(TRANSPARENT_COLOR);
getStatusLabel().setOpaque(false);
getShowAllGemsButton().setBackground(TRANSPARENT_COLOR);
getShowAllGemsButton().setOpaque(false);
getShowLikelyGemsButton().setBackground(TRANSPARENT_COLOR);
getShowLikelyGemsButton().setOpaque(false);
getShowBestGemsButton().setBackground(TRANSPARENT_COLOR);
getShowBestGemsButton().setOpaque(false);
getShowGemsButtonToolBar().setBackground(TRANSPARENT_COLOR);
getShowGemsButtonToolBar().setOpaque(false);
// Here we have to again remove the list's default key listeners that are added
// by Swing. These listeners are re-added when the list updates its UI when the
// transparency is enabled. The listeners need to be removed since they screw up
// our own key navigation and intellicut searching.
KeyListener[] keyListeners = getIntellicutList().getKeyListeners();
for (final KeyListener listenerToRemove : keyListeners) {
getIntellicutList().removeKeyListener(listenerToRemove);
}
// Add back our own listener
getIntellicutList().addKeyListener(new IntellicutKeyListener());
}
/**
* Makes the entire panel except for its border invisible. This is used to draw the outline
* of the panel while it is being moved around the screen.
* @param dragMode true to make everything invisible but the border, false otherwise
*/
private void setDragMode(boolean dragMode) {
if (dragMode == isDragging) {
return;
}
isDragging = dragMode;
if (dragMode) {
savedBackgroundColor = getBackground();
setBackground(TRANSPARENT_COLOR);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
listScrollPane.setVisible(false);
getTopPanel().setVisible(false);
} else {
setBackground(savedBackgroundColor);
if (intellicutList.isTransparent()) {
setBorder(new SmoothHighlightBorder(typeColor != null ? typeColor : getBackground(), false));
} else {
setBorder(BorderFactory.createEtchedBorder());
}
getTopPanel().setVisible(true);
listScrollPane.setVisible(true);
}
}
/**
* We draw in our background manually. This is necessary since Java screws up the background
* drawing if the panel is transparent.
*/
@Override
public void paintComponent(Graphics g) {
Insets insets = getInsets();
g.setColor(getBackground());
g.fillRect(insets.left, insets.top, getWidth() - insets.left - insets.right, getHeight() - insets.top - insets.bottom);
}
/**
* Returns the panel at the top of the intellicut list that contains the switch buttons
* and title labels.
* @return JPanel
*/
private JPanel getTopPanel() {
if (topPanel == null) {
topPanel = new JPanel();
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
topPanel.add(getTitleLabel());
topPanel.add(Box.createHorizontalGlue());
topPanel.add(getStatusLabel());
topPanel.add(Box.createHorizontalStrut(5));
topPanel.add(getShowGemsButtonToolBar());
// we don't want a visible border for the top panel, just use this to create margins
topPanel.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
// set the size to be large enough to display long status messages
Dimension prefSize = getTopPanel().getPreferredSize();
topPanel.setPreferredSize(new Dimension(prefSize.width + 25, prefSize.height));
topPanel.setCursor(Cursor.getDefaultCursor());
}
return topPanel;
}
/**
* Returns the title label for the title of the intellicut list.
* @return JLabel
*/
private JLabel getTitleLabel() {
if (titleLabel == null) {
titleLabel = new JLabel(adapter.getMessages().getString("ICL_IntellicutTitle"));
titleLabel.setIcon(intellicutIcon);
Font labelFont = getFont().deriveFont(Font.BOLD, getFont().getSize() + 4);
titleLabel.setFont(labelFont);
titleLabel.setCursor(Cursor.getDefaultCursor());
}
return titleLabel;
}
/**
* Returns the status label for the status of the intellicut list.
* @return JLabel
*/
private JLabel getStatusLabel() {
if (statusLabel == null) {
statusLabel = new JLabel();
statusLabel.setCursor(Cursor.getDefaultCursor());
updateStatusLabel();
}
return statusLabel;
}
private static class TransparentToggleButton extends JToggleButton {
private static final long serialVersionUID = -7591214478387598044L;
/**
* This overrides paintComponent to make transparency work correctly.
* We have to draw in our own background, otherwise Java will screw it up.
* @param g the Graphics object to draw with
*/
@Override
public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
}
/** @return JToggleButton the button for the show all gems level of filtering */
private JToggleButton getShowAllGemsButton() {
if (showAllGemsButton == null) {
showAllGemsButton = new TransparentToggleButton();
showAllGemsButton.setAction(getGemFilterButtonAction(showAllGemsButton, showAllGemsIcon, "ICL_ShowAllGemsToolTip", FilterLevel.SHOW_ALL));
showAllGemsButton.setText(null);
showAllGemsButton.setMargin(new Insets(0, 0, 0, 0));
showAllGemsButton.setCursor(Cursor.getDefaultCursor());
}
return showAllGemsButton;
}
/** @return JToggleButton the button for the show likely gems level of filtering */
private JToggleButton getShowLikelyGemsButton() {
if (showLikelyGemsButton == null) {
showLikelyGemsButton = new TransparentToggleButton();
showLikelyGemsButton.setAction(getGemFilterButtonAction(showLikelyGemsButton, showLikelyGemsIcon, "ICL_ShowLikelyGemsToolTip", FilterLevel.SHOW_LIKELY));
showLikelyGemsButton.setText(null);
showLikelyGemsButton.setMargin(new Insets(0, 0, 0, 0));
showLikelyGemsButton.setCursor(Cursor.getDefaultCursor());
}
return showLikelyGemsButton;
}
/** @return JToggleButton the button for the show best gems level of filtering */
private JToggleButton getShowBestGemsButton() {
if (showBestGemsButton == null) {
showBestGemsButton = new TransparentToggleButton();
showBestGemsButton.setAction(getGemFilterButtonAction(showBestGemsButton, showBestGemsIcon, "ICL_ShowBestGemsToolTip", FilterLevel.SHOW_BEST));
showBestGemsButton.setText(null);
showBestGemsButton.setMargin(new Insets(0, 0, 0, 0));
showBestGemsButton.setCursor(Cursor.getDefaultCursor());
}
return showBestGemsButton;
}
/**
* We cheat and place the show gems button inside a toolbar.
* Toolbars can automatically give buttons the nice mouse-rollover effect,
* without us having to install custom mouse listeners to do it.
* @return the toolbar the show gems button is placed in.
*/
private JToolBar getShowGemsButtonToolBar() {
if (showGemsButtonToolBar == null) {
showGemsButtonToolBar = new JToolBar() {
private static final long serialVersionUID = -4840586584969771381L;
/**
* This overrides paintComponent to make transparency work correctly.
* We have to draw in our own background, otherwise Java will screw it up.
* @param g the Graphics object to draw with
*/
@Override
public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
showGemsButtonToolBar.setOpaque(true);
showGemsButtonToolBar.setRollover(true);
showGemsButtonToolBar.setFloatable(false);
showGemsButtonToolBar.setCursor(Cursor.getDefaultCursor());
showGemsButtonToolBar.add(getShowBestGemsButton());
showGemsButtonToolBar.add(getShowLikelyGemsButton());
showGemsButtonToolBar.add(getShowAllGemsButton());
getFilterButtonGroup();
}
return showGemsButtonToolBar;
}
private ButtonGroup getFilterButtonGroup() {
if (filterButtonGroup == null) {
filterButtonGroup = new ButtonGroup();
filterButtonGroup.add(getShowAllGemsButton());
filterButtonGroup.add(getShowLikelyGemsButton());
filterButtonGroup.add(getShowBestGemsButton());
}
return filterButtonGroup;
}
/**
* Returns an action for the three filter-level buttons
* @param button The button that this action is for
* @param icon Icon to display on the button
* @param toolTipId String id of the tooltip for this button
* @param filterLevel Filter level that this button sets
* @return Action
*/
private Action getGemFilterButtonAction(JToggleButton button, ImageIcon icon, String toolTipId, final FilterLevel filterLevel) {
Action filterButtonAction = new AbstractAction("filterButtonAction", icon) {
private static final long serialVersionUID = -196510266687548115L;
public void actionPerformed(ActionEvent evt) {
getIntellicutList().setFilterLevel(filterLevel);
getIntellicutList().requestFocus();
updateStatusLabel();
saveFilterPreference = true;
}
};
filterButtonAction.putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_T));
filterButtonAction.putValue(Action.SHORT_DESCRIPTION, adapter.getMessages().getString(toolTipId));
return filterButtonAction;
}
/**
* Updates the status label of the list to show the correct information.
*/
private void updateStatusLabel() {
FilterLevel filterLevel = getIntellicutListModel().getFilterLevel();
int numGems = getIntellicutListModel().getSize();
String message = null;
String messageId = (filtersEnabled == false) ? (numGems > 1 ? "ICL_ShowingMatchingGems" : "ICL_ShowingOneMatchingGem") :
(filterLevel == FilterLevel.SHOW_ALL) ? (numGems > 1 ? "ICL_ShowingAllGems" : "ICL_ShowingAllOneGem") :
(filterLevel == FilterLevel.SHOW_LIKELY) ? (numGems > 1 ? "ICL_ShowingLikelyGems" : "ICL_ShowingLikelyOneGem") :
/* FilterLevel.SHOW_BEST */ (numGems > 1 ? "ICL_ShowingBestGems" : "ICL_ShowingBestOneGem");
if (numGems > 1) {
Object[] arguments = { Integer.valueOf(numGems) };
message = MessageFormat.format(adapter.getMessages().getString(messageId), arguments);
} else {
message = adapter.getMessages().getString(messageId);
}
getStatusLabel().setText(message);
}
private void setFiltersEnabled(boolean enableFilters) {
filtersEnabled = enableFilters;
if (enableFilters) {
getShowAllGemsButton().setVisible(true);
getShowLikelyGemsButton().setVisible(true);
getShowBestGemsButton().setVisible(true);
} else {
getShowAllGemsButton().setVisible(false);
getShowLikelyGemsButton().setVisible(false);
getShowBestGemsButton().setVisible(false);
}
updateStatusLabel();
}
}