/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph.swing; import java.awt.Color; import java.awt.Font; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.geom.Point2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import javax.swing.JComboBox; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import org.simantics.scenegraph.utils.DummyComponent; public class ComboBoxNode extends ComponentNode implements ActionListener, FocusListener, PropertyChangeListener, KeyListener { /** * */ private static final long serialVersionUID = 7073028693751719102L; protected boolean editable = true; protected String value = ""; protected String tooltip = ""; protected double borderWidth = 0; protected transient ActionListener actionListener = null; protected Font font = null; protected Color color = null; protected List items = null; @Override public String toString() { return super.toString() + "[editable=" + editable + ", value=" + value + "]"; } @Override public void init() { component = new JComboBox(); component.setLightWeightPopupEnabled(true); component.setEditable(editable); component.setEnabled(editable); component.addActionListener(this); component.addFocusListener(this); component.addKeyListener(this); component.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuCanceled(PopupMenuEvent e) { // TODO Auto-generated method stub } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { // TODO Auto-generated method stub } @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { JComboBox box = (JComboBox) e.getSource(); Object comp = box.getUI().getAccessibleChild(box, 0); if (!(comp instanceof JPopupMenu)) { return; } /** * Relocate the popup under the combobox. This is necessary because scenegraph handles combobox rendering, * thus the real location of the combobox is invalid. */ JPopupMenu popup = (JPopupMenu) comp; Point2D p = ComboBoxNode.this.localToControl(new Point2D.Double()); Point loc = new Point((int)p.getX(), (int)p.getY()+component.getHeight()); SwingUtilities.convertPointToScreen(loc, box.getParent()); popup.setLocation((int)loc.getX(), (int)loc.getY()); } }); super.init(); } @SyncField("items") public void setItems(List items) { this.items = items; component.removeAllItems(); for(String str : items) { component.addItem(str); } } @SyncField("editable") public void setEditable(boolean value) { this.editable = value; if(component != null) { component.setEditable(value); component.setEnabled(value); } } @PropertySetter("Stroke Width") @SyncField("borderWidth") public void setBorderWidth(Float borderWidth) { this.borderWidth = borderWidth; // if(component != null) { // ((TextField)component).setBorder(borderWidth); // } } @SyncField("value") public void setText(String value) { this.value = value; // RemoteViewer does not have component initialized if (component != null) { //System.out.println("MonitorNode.setText(" + value + ")"); component.setSelectedItem(value); component.repaint(); } } @SyncField("tooltip") public void setToolTipText(String tooltip) { this.tooltip = tooltip; if (component != null) { component.setToolTipText(tooltip); } } @PropertySetter("Font") @SyncField("font") public void setFont(Font font) { this.font = font; if (component != null) { setComponentFont(font); } } @PropertySetter("Color") @SyncField("color") public void setColor(Color color) { this.color = color; if (component != null) { component.setForeground(color); } } public String getText() { return value; } public Font getFont() { return font; } @Override public void propertyChange(PropertyChangeEvent evt) { if("value".equals(evt.getPropertyName()) && component != null) { component.setSelectedItem(evt.getNewValue()); component.repaint(); } else if("editable".equals(evt.getPropertyName()) && component != null) { component.setEditable((Boolean)evt.getNewValue()); component.setEnabled((Boolean)evt.getNewValue()); } } public void setActionListener(ActionListener actionListener) { this.actionListener = actionListener; } @Override public void actionPerformed(ActionEvent e) { loseFocus(); } void loseFocus() { if (component != null) if (component.isFocusOwner()) if (container.getParent() != null) container.getParent().requestFocusInWindow(); // Lose focus } @Override public void focusGained(FocusEvent arg0) { } @Override public void focusLost(FocusEvent arg0) { if (component != null) { ActionEvent e = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, (String) component.getSelectedItem()); performAction(e); } } /** * Wrapper method to send event to serverside * * @param e */ @ServerSide public void performAction(ActionEvent e) { if (actionListener != null) { //System.out.println("MonitorNode.performAction(" + e + ")"); actionListener.actionPerformed(e); } } @Override public void keyPressed(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { if (e.getModifiers() == 0 && e.getKeyCode() == KeyEvent.VK_ESCAPE) { // ESC without modifiers == CANCEL edit // TODO: signal about cancellation loseFocus(); } } /** * Quick hack to test widget feature.. * FIXME: Use existing methods or variables.. * * @param input */ public void input(String input) { ActionEvent e = new ActionEvent(new DummyComponent(), ActionEvent.ACTION_PERFORMED, input); performAction(e); } }