/********************************************************************************
* *
* (c) Copyright 2010 Verizon Communications USA and The Open University UK *
* *
* This software is freely distributed in accordance with *
* the GNU Lesser General Public (LGPL) license, version 3 or later *
* as published by the Free Software Foundation. *
* For details see LGPL: http://www.fsf.org/licensing/licenses/lgpl.html *
* and GPL: http://www.fsf.org/licensing/licenses/gpl-3.0.html *
* *
* 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. *
* *
********************************************************************************/
package com.compendium.ui.menus;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import javax.swing.ButtonModel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.MouseInputListener;
import com.compendium.ui.IUIConstants;
import com.compendium.ui.UIImageButton;
import com.compendium.ui.UIImages;
public class UIControllerMenuItem extends JPanel implements MenuElement{
private Color savedBackground = null;
private static MenuElement NO_SUB_ELEMENTS[] = new MenuElement[0];
/** The string that identifies if the menu is extended.*/
public final static String EXTEND_MENU = "editextend";
/** The string that identifies if the menu is contracted.*/
public final static String COLLAPSE_MENU = "editcollapse";
/** The item with the extender arrow.*/
private UIImageButton button = null;
public UIControllerMenuItem() {
JMenuItem test = new JMenuItem();
setLayout(new BorderLayout());
setBorder(new EmptyBorder(4,4,4,4));
button = new UIImageButton(UIImages.get(IUIConstants.DOWN_ARROW_ICON));
button.setName(EXTEND_MENU);
button.setHorizontalAlignment(SwingConstants.CENTER);
add(button,BorderLayout.CENTER);
button.setBackground((Color)UIManager.get("MenuItem.background"));
this.setBackground((Color)UIManager.get("MenuItem.background"));
init();
}
private void init() {
setRequestFocusEnabled(true);
// Borrows heavily from BasicMenuUI
MouseInputListener mouseInputListener = new MouseInputListener() {
// If mouse released over this menu item, activate it
public void mouseReleased(MouseEvent mouseEvent) {
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
Point point = mouseEvent.getPoint();
if ((point.x >= 0) && (point.x < getWidth()) && (point.y >= 0)
&& (point.y < getHeight())) {
//menuSelectionManager.clearSelectedPath();
// component automatically handles "selection" at this point
// doClick(0); // not necessary
} else {
menuSelectionManager.processMouseEvent(mouseEvent);
}
}
// If mouse moves over menu item, add to selection path, so it
// becomes armed
public void mouseEntered(MouseEvent mouseEvent) {
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
menuSelectionManager.setSelectedPath(getPath());
}
// When mouse moves away from menu item, dissarm it and select
// something else
public void mouseExited(MouseEvent mouseEvent) {
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
MenuElement path[] = menuSelectionManager.getSelectedPath();
if (path.length > 1) {
MenuElement newPath[] = new MenuElement[path.length - 1];
for (int i = 0, c = path.length - 1; i < c; i++) {
newPath[i] = path[i];
}
menuSelectionManager.setSelectedPath(newPath);
}
}
// Pass along drag events
public void mouseDragged(MouseEvent mouseEvent) {
MenuSelectionManager.defaultManager().processMouseEvent(mouseEvent);
}
public void mouseClicked(MouseEvent mouseEvent) {}
public void mousePressed(MouseEvent mouseEvent) {}
public void mouseMoved(MouseEvent mouseEvent) {}
};
button.addMouseListener(mouseInputListener);
button.addMouseMotionListener(mouseInputListener);
}
public void pointUp() {
button.setIcon(UIImages.get(IUIConstants.UP_ARROW_ICON));
button.setName(COLLAPSE_MENU);
}
public void pointDown() {
button.setIcon(UIImages.get(IUIConstants.DOWN_ARROW_ICON));
button.setName(EXTEND_MENU);
}
public boolean isDown() {
return (button.getName().equals(EXTEND_MENU));
}
public void addActionListener(ActionListener a) {
button.addActionListener(a);
}
/**
* Process a key event.
*/
public void processKeyEvent(KeyEvent keyEvent, MenuElement path[], MenuSelectionManager manager) {
// If user presses space while menu item armed, select it
if (button.getModel().isArmed()) {
int keyChar = keyEvent.getKeyChar();
if (keyChar == KeyEvent.VK_SPACE) {
//manager.clearSelectedPath();
button.doClick(0); // inherited from AbstractButton
}
}
}
/**
* Processes a mouse event. <code>event</code> is a <code>MouseEvent</code>
* with source being the receiving element's component.
* <code>path</code> is the path of the receiving element in the menu
* hierarchy including the receiving element itself.
* <code>manager</code> is the <code>MenuSelectionManager</code>
* for the menu hierarchy.
* This method should process the <code>MouseEvent</code> and change
* the menu selection if necessary
* by using <code>MenuSelectionManager</code>'s API
* Note: you do not have to forward the event to sub-components.
* This is done automatically by the <code>MenuSelectionManager</code>.
*/
public void processMouseEvent(MouseEvent mouseEvent, MenuElement path[],MenuSelectionManager manager) {
// For when mouse dragged over menu and button released
if (mouseEvent.getID() == MouseEvent.MOUSE_RELEASED) {
//manager.clearSelectedPath();
button.doClick(0); // inherited from AbstractButton
}
}
public void setFocus() {
button.requestFocus();
}
/**
* Call by the <code>MenuSelectionManager</code> when the
* <code>MenuElement</code> is added or remove from
* the menu selection.
*/
public void menuSelectionChanged(boolean isIncluded) {
ButtonModel model = button.getModel();
// only change armed state if different
if (model.isArmed() != isIncluded) {
model.setArmed(isIncluded);
}
if (isIncluded) {
button.setSelected(true);
button.setBackground((Color)UIManager.get("MenuItem.selectionBackground"));
this.setBackground((Color)UIManager.get("MenuItem.selectionBackground"));
} else {
button.setSelected(false);
button.setBackground((Color)UIManager.get("MenuItem.background"));
this.setBackground((Color)UIManager.get("MenuItem.background"));
}
}
/**
* This method should return an array containing the sub-elements for the receiving menu element
*
* @return an array of MenuElements
*/
public MenuElement[] getSubElements() {
// no subelements
return NO_SUB_ELEMENTS;
}
/**
* This method should return the java.awt.Component used to paint the receiving element.
* The returned component will be used to convert events and detect if an event is inside
* a MenuElement's component.
*
* @return the Component value
*/
public Component getComponent() {
return this;
}
// Borrows heavily from BasicMenuItemUI.getPath()
private MenuElement[] getPath() {
MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
MenuElement oldPath[] = menuSelectionManager.getSelectedPath();
MenuElement newPath[];
int oldPathLength = oldPath.length;
if (oldPathLength == 0) {
return new MenuElement[0];
}
Component parent = getParent();
if (oldPath[oldPathLength - 1].getComponent() == parent) {
// Going deeper under the parent menu
newPath = new MenuElement[oldPathLength + 1];
System.arraycopy(oldPath, 0, newPath, 0, oldPathLength);
newPath[oldPathLength] = this;
} else {
// Sibling/child menu item currently selected
int newPathPosition;
for (newPathPosition = oldPath.length - 1; newPathPosition >= 0; newPathPosition--) {
if (oldPath[newPathPosition].getComponent() == parent) {
break;
}
}
newPath = new MenuElement[newPathPosition + 2];
System.arraycopy(oldPath, 0, newPath, 0, newPathPosition + 1);
newPath[newPathPosition + 1] = this;
}
return newPath;
}
}