org.pentaho.ui.xul.swing.tags.SwingMenuList.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.ui.xul.swing.tags.SwingMenuList.java

Source

/*!
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright (c) 2002-2013 Pentaho Corporation..  All rights reserved.
 */

package org.pentaho.ui.xul.swing.tags;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.Expression;
import java.util.Collection;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.ui.xul.XulComponent;
import org.pentaho.ui.xul.XulDomContainer;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.components.XulMenuList;
import org.pentaho.ui.xul.containers.XulMenupopup;
import org.pentaho.ui.xul.containers.XulRoot;
import org.pentaho.ui.xul.dom.Document;
import org.pentaho.ui.xul.dom.Element;
import org.pentaho.ui.xul.swing.AbstractSwingContainer;

public class SwingMenuList<T> extends AbstractSwingContainer implements XulMenuList<T> {

    private JComboBox combobox;

    private XulDomContainer xulDomContainer;

    private static final Log logger = LogFactory.getLog(SwingMenuList.class);

    private boolean loaded = false;

    private String binding;

    private String previousSelectedItem = null;

    private boolean editable = false;

    public SwingMenuList(Element self, XulComponent parent, XulDomContainer domContainer, String tagName) {
        super("menulist");

        this.xulDomContainer = domContainer;

        combobox = new JComboBox(new DefaultComboBoxModel());
        setManagedObject(combobox);

        combobox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED && !inLayoutProcess && initialized) {
                    fireSelectedEvents();
                }
            }

        });

    }

    private boolean suppressLayout = false;
    private boolean inLayoutProcess = false;

    public void layout() {
        inLayoutProcess = true;
        if (suppressLayout) {
            inLayoutProcess = false;
            return;
        }
        SwingMenupopup popup = getPopupElement();
        DefaultComboBoxModel model = (DefaultComboBoxModel) this.combobox.getModel();
        model.removeAllElements();

        SwingMenuitem selectedItem = null;

        // capture first child as default selection
        boolean firstChild = true;
        for (XulComponent item : popup.getChildNodes()) {
            JMenuItem jmenuItem = (JMenuItem) ((SwingMenuitem) item).getManagedObject();
            SwingMenuitem tempItem = (SwingMenuitem) item;
            model.addElement(tempItem);

            if (tempItem.isSelected() || firstChild) {
                selectedItem = tempItem;
                firstChild = false;
            }
        }

        inLayoutProcess = false;

        if (selectedItem != null) {
            // if first setting it to the currently selected one will not fire event.
            // manually firing here
            if (model.getSelectedItem() == selectedItem) {
                fireSelectedEvents();
            }
            model.setSelectedItem(selectedItem);
        }
        initialized = true;
        loaded = true;
    }

    public void onDomReady() {

        if (combobox.getSelectedItem() != null) {
            fireSelectedEvents();
        }
    }

    private void fireSelectedEvents() {

        SwingMenuList.this.changeSupport.firePropertyChange("selectedItem", previousSelectedItem,
                this.getSelectedItem());
        SwingMenuList.this.changeSupport.firePropertyChange("selectedIndex", null, combobox.getSelectedIndex());
        previousSelectedItem = getSelectedItem();
    }

    public SwingMenupopup getPopupElement() {
        for (Element comp : getChildNodes()) {
            if (SwingMenupopup.class.isAssignableFrom(comp.getClass())) {
                return (SwingMenupopup) comp;
            }
        }
        throw new IllegalStateException("menulist is missing a menupopup child element");
    }

    /*
     * Swaps out the managed list. Effectively replaces the SwingMenupopup child component. (non-Javadoc)
     * 
     * @see org.pentaho.ui.xul.components.XulMenuList#replaceAll(java.util.List)
     */
    @Deprecated
    public void replaceAllItems(Collection<T> tees) {
        setElements(tees);
    }

    public String getSelectedItem() {

        if (editable) {
            return textComp.getText();
        }
        return ((SwingMenuitem) this.combobox.getModel().getSelectedItem()).getLabel();
    }

    public void setSelectedItem(T t) {
        SwingMenupopup popup = getPopupElement();
        for (XulComponent item : popup.getChildNodes()) {
            SwingMenuitem tempItem = (SwingMenuitem) item;
            if (tempItem.getLabel().equals(extractLabel(t))) {
                this.combobox.setSelectedItem(tempItem);
            }
        }
    }

    public void setOncommand(final String command) {
        combobox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {

                /*
                 * This actionlistener is fired at parse time when elements are added. We'll ignore that call by checking a
                 * variable set to true post parse time
                 */
                if (!loaded) {
                    return;
                }
                Document doc = getDocument();
                XulRoot window = (XulRoot) doc.getRootElement();
                final XulDomContainer con = window.getXulDomContainer();

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        try {
                            con.invoke(command, new Object[] {});
                        } catch (XulException e) {
                            logger.error("Error calling oncommand event", e);
                        }
                    }
                });
            }
        });
    }

    public Collection<T> getElements() {
        return (Collection) this.getPopupElement().getChildNodes();
    }

    public String getBinding() {
        return binding;
    }

    public void setBinding(String binding) {
        this.binding = binding;
    }

    private String extractLabel(T t) {
        String attribute = getBinding();
        if (StringUtils.isEmpty(attribute)) {
            return t.toString();
        } else {
            String getter = "get" + (String.valueOf(attribute.charAt(0)).toUpperCase()) + attribute.substring(1);
            try {
                return new Expression(t, getter, null).getValue().toString();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void setElements(Collection<T> tees) {
        this.suppressLayout = true;
        XulMenupopup popup = getPopupElement();
        for (XulComponent menuItem : popup.getChildNodes()) {
            popup.removeChild(menuItem);
        }

        for (T t : tees) {
            SwingMenuitem item = new SwingMenuitem(null, popup, this.xulDomContainer, null);

            String attribute = getBinding();
            item.setLabel(extractLabel(t));

            popup.addChild(item);
        }

        this.suppressLayout = false;
        layout();
    }

    public int getSelectedIndex() {
        return this.combobox.getSelectedIndex();
    }

    public void setSelectedIndex(int idx) {
        this.combobox.setSelectedIndex(idx);
    }

    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        Dimension box = new Dimension();
        box.height = this.combobox.getPreferredSize().height;
        box.width = width;
        this.combobox.setMaximumSize(box);
        this.combobox.setPreferredSize(box);
        this.combobox.setMinimumSize(box);
    }

    private String oldValue = "";
    private JTextComponent textComp;

    public void setEditable(boolean editable) {
        this.editable = editable;
        combobox.setEditable(editable);
        if (editable) {
            textComp = (JTextComponent) combobox.getEditor().getEditorComponent();

            textComp.addKeyListener(new KeyListener() {
                public void keyPressed(KeyEvent e) {
                    oldValue = textComp.getText();
                }

                public void keyReleased(KeyEvent e) {
                    if (oldValue != null && !oldValue.equals(textComp.getText())) {
                        SwingMenuList.this.changeSupport.firePropertyChange("value", oldValue,
                                SwingMenuList.this.getValue());
                        oldValue = textComp.getText();
                    } else if (oldValue == null) {
                        // AWT error where sometimes the keyReleased is fired before keyPressed.
                        oldValue = textComp.getText();
                    } else {
                        logger.debug("Special key pressed, ignoring");
                    }
                }

                public void keyTyped(KeyEvent e) {
                }

            });
        }
    }

    public boolean getEditable() {
        return this.editable;
    }

    public String getValue() {
        return (textComp != null) ? textComp.getText()
                : ((SwingMenuitem) this.combobox.getModel().getSelectedItem()).getLabel();
    }

    public void setValue(String value) {
        if (editable) {
            ((JTextComponent) combobox.getEditor().getEditorComponent()).setText(value);
        }
    }
}