Package DisplayProject.controls

Source Code of DisplayProject.controls.MenuList$Model

/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
 
o 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.
   
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "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 DisplayProject.controls;

import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.List;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.apache.log4j.Logger;

import DisplayProject.ListField;
import DisplayProject.UIutils;
import DisplayProject.actions.ActionMgr;
import DisplayProject.actions.PendingAction;
import DisplayProject.binding.TypeAwareValueModel;
import DisplayProject.binding.list.SelectionInList;
import DisplayProject.binding.value.ValueModel;
import DisplayProject.events.ChildEventHelper;
import DisplayProject.events.ClientEventManager;
import Framework.Array_Of_ListElement;
import Framework.CloneHelper;
import Framework.DeepCloneable;
import Framework.IntegerNullable;
import Framework.ListElement;
import Framework.TextData;
import Framework.TextNullable;
/**
* this is an implementation of the Forte MenuList. It is a collection of
* ListElements in JList presented as a MenuElement.
* @author Peter & Craig
*
*/
@SuppressWarnings("serial")
public class MenuList extends JList implements MenuElement, DeepCloneable {
    private static MenuElement NO_SUB_ELEMENTS[] = new MenuElement[0];
    // TF:08/11/2009:There is duplication of this list between the control and the model. The model should hold the values.
//    protected Array_Of_ListElement<ListElement> elementsList;
    protected static Logger _log = Logger.getLogger(MenuList.class);
    /**
     * A list of event listeners for this component.
     */
    protected EventListenerList listenerList = new EventListenerList();
    private int armedIndex; // the index to which the item is highlighted.  CraigM 22/10/2007
    private boolean isMenuListSelected; // are the currently selected.  CraigM 22/10/2007
    private MenuElement previousMenuSelected; // CraigM 22/10/2007
    /**
     * In some testing with Forte it appears that if a menu list is mapped to a nullable type like an
     * IntegerNullable that re-selecting the same item causes the item to be unselected and become NIL.
     * However, this testing is not consistent and it seems that most of the time this toggling doesn't
     * happen. This flag can use used to control whether the MenuList toggles or not.
     */
  private static final boolean allowToggleOnNullableSelection = false;
   
    public MenuList(){
        super();
        // TF:20/10/2009:DET-119:Do not have the menu centre aligned (the default) but left aligned.
        this.setAlignmentX(0.0f);
        armedIndex = 0;
        isMenuListSelected = false;
        setCellRenderer(new ListCellRenderer(){
            public Component getListCellRendererComponent(
                    JList list,
                    Object value,
                    int index,
                    boolean isSelected,
                    boolean cellHasFocus) {
             
              // CraigM:19/11/2008 - Forte would ignore null values.  JIRA: DET-51.
              if (value == null) return new JLabel();
             
              // TF:20/10/2009:DET-119:Forte displayed a tick box for the menu item instead of a circle, so
              // mirror this behaviour despite being inconsistent with Java
//                JRadioButtonMenuItem comp = new JRadioButtonMenuItem();
                JCheckBoxMenuItem comp = new JCheckBoxMenuItem();
                comp.setSelected(isSelected);
                comp.setText(value.toString());
                comp.setArmed(isMenuListSelected && index == armedIndex);
                return comp;
            }
        });
        setSelectionModel(createSelectionModel());

        this.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                armedIndex = getUI().locationToIndex(MenuList.this, new Point(e.getX(), e.getY()));
                isMenuListSelected = true;
                repaint();
            }
        });

        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                isMenuListSelected = false;
                armedIndex = 0;
                repaint();
            }
            @Override
            public void mousePressed(MouseEvent e) {
              super.mousePressed(e);
              isMenuListSelected = false;
            }
        });
    }

    public Component getComponent() {
        return this;
    }

    public MenuElement[] getSubElements() {
        return NO_SUB_ELEMENTS;
    }

    public void menuSelectionChanged(boolean isIncluded) {
    }

    /* We need to simulate the key events that would normally be handled by the menu.
     * This includes setting the armedIndex.  CraigM 22/10/2007.
     * @see javax.swing.MenuElement#processKeyEvent(java.awt.event.KeyEvent, javax.swing.MenuElement[], javax.swing.MenuSelectionManager)
     */
    public void processKeyEvent(KeyEvent event, MenuElement[] path, MenuSelectionManager manager) {
        MenuElement[] thePath = manager.getSelectedPath();

        // Check if the menu wants us to be the active row
        if (thePath.length > 0 && thePath[thePath.length-1] == this) {
            this.isMenuListSelected = true;
            int numElements = this.getModel().getSize();

            // Are we moving from a different menu item to this menu list
            if (previousMenuSelected.getComponent() != this) {
                if (previousMenuSelected.getComponent().getY() < this.getComponent().getY()) {
                    this.armedIndex = 0;
                }
                else {
                    this.armedIndex = numElements-1;
                }
            }

            if (event.getID() == KeyEvent.KEY_PRESSED) {

                // Select the list item on enter
                if (event.getKeyCode() == KeyEvent.VK_ENTER) {
                    this.setSelectedIndex(this.armedIndex);
                    fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, this.getName()));
                    manager.setSelectedPath(null);
                    this.isMenuListSelected = false;
                    this.armedIndex = 0;
                    event.consume();
                }

                // Override the up and down arrow keys while moving through our list
                else if ((event.getKeyCode() == KeyEvent.VK_DOWN && this.armedIndex < numElements-1) ||
                        (event.getKeyCode() == KeyEvent.VK_UP && this.armedIndex > 0)) {
                    event.consume();

                    if (event.getKeyCode() == KeyEvent.VK_DOWN) {
                        this.armedIndex++;
                    }
                    else if (event.getKeyCode() == KeyEvent.VK_UP) {
                        this.armedIndex--;
                    }
                }
            }
        }
        else {
            this.isMenuListSelected = false;
        }
        this.repaint();

        if (thePath.length > 0) {
            previousMenuSelected = thePath[thePath.length-1];
        }
    }

    public void processMouseEvent(MouseEvent event, MenuElement[] path,
            MenuSelectionManager manager) {
        if (event.isConsumed()) {
            return;
        }
        super.processMouseEvent(event);
        if (event.getID() == MouseEvent.MOUSE_RELEASED){
            fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, this.getName()));
            event.consume();

            // Close the menu after selection.  CraigM 22/10/2007
            manager.setSelectedPath(null);
        }
    }

    public Array_Of_ListElement<ListElement> getElementList(){
      // TF:08/11/2009:Changed this to always get the elements from the model
//        return (Array_Of_ListElement<ListElement>)CloneHelper.clone(this.elementsList, false);
      return CloneHelper.clone(getMenuListModel().getElementList(), false);
    }

    public void initialiseSelectedElement() {
        // CraigM:19/11/2008 - Forte would always select something.
      // TF:08/11/2009:DET-127:This only applies to non-null types.
        if (MenuList.this.getSelectedIndex() == -1 && !getMenuListModel().isNullable) {
          MenuList.this.setSelectedIndex(0);
        }
    }

    @Override
    public void setSelectionInterval(int anchor, int lead) {
      if (allowToggleOnNullableSelection && this.getSelectedIndex() == lead) {
        if (getMenuListModel().isNullable) {
          this.clearSelection();
        }
      }
      else {
        super.setSelectionInterval(anchor, lead);
      }
    }
   
    public void setElementList(Array_Of_ListElement<ListElement> elements){
        final Array_Of_ListElement<ListElement> data = CloneHelper.clone(elements, false);
        ActionMgr.addAction(new PendingAction(null) {
            @Override
            public String toString() {
                return "MenuList.setElementList(" + data + ")";
            }
            @Override
            public void performAction() {
                synchronized(MenuList.this) {
                  // TF:08/11/2009:Changed this code to use the model
//                    if (data == null) {
//                        MenuList.this.elementsList = null;
//                    }
//                    else {
//                        MenuList.this.elementsList = data;
//                       
//                        // CraigM:19/11/2008 - Set the list in the model to reflect the new data.  JIRA: DET-51.
//                        ((MenuList.Model)MenuList.this.getModel()).list.setList(data);
//   
//                        initialiseSelectedElement();
//                    }
                  getMenuListModel().setElementList(data);
                    invalidate();
                }
            }
        });
    }

    public MenuList.Model getMenuListModel() {
        return (MenuList.Model)this.getModel();
    }

    /**
     * Get the index of the selected item, or 0 if no item is selected. The return value is 0-based.
     */
    public int getIndexValue() {
      // TF:23/11/2009:Changed this to be 0 based not 1-based, and adjusted IndexValue accordingly
        return super.getSelectedIndex();
    }

    /**
     * Set the selected index for this control. The passed index is 0-based.
     * @param index
     */
    public void setIndexValue(int index) {
      // TF:23/11/2009:Changed this to be 0 based not 1-based, and adjusted IndexValue accordingly
        if (index < 0) {
            return;
        }
        super.setSelectedIndex(index);
    }

    public int getIntegerValue() {
      // TF:08/11/2009:DET-127:Delegated to model
//      ListElement selectedValue = (ListElement)this.getSelectedValue();
//        return selectedValue != null ? selectedValue.getIntegerValue() : Integer.MIN_VALUE;
      return getMenuListModel().getIntegerValue();
    }

    public void setIntegerValue(int value) {
      MenuList.Model model = getMenuListModel();
        for (int i = 0; i < model.getSize(); i++) {
            ListElement le = ((ListElement)model.getElementAt(i));
            if (le.equals(value)) {
                this.setSelectedIndex(i);
                break;
            }
        }
    }

    public Object getObjectValue() {
      // TF:08/11/2009:DET-127:Delegated to model
//      ListElement selectedValue = (ListElement)this.getSelectedValue();
//        return selectedValue == null ? null : selectedValue.getObjectValue();
      return getMenuListModel().getObjectValue();
    }

    public void setObjectValue(Object value) {
        for (int i = 0; i < this.getMenuListModel().getSize(); i++) {
            ListElement le = ((ListElement)this.getMenuListModel().getElementAt(i));
            if (le.getObjectValue() == null)
                continue;
            if (le.getObjectValue().equals(value)){
                this.setSelectedIndex(i);
                break;
            }
        }
    }

    public TextData getTextValue() {
      // TF:08/11/2009:DET-127:Delegated to model
//      ListElement selectedValue = (ListElement)this.getSelectedValue();
//        return selectedValue == null ? new TextData("") : selectedValue.getTextValue();
      return getMenuListModel().getTextValue();
    }

    public void setTextValue(TextData value) {
        this.setTextValue(value.toString());
    }

    public void setTextValue(String value) {
        for (int i = 0; i < this.getMenuListModel().getSize(); i++) {
            ListElement le = ((ListElement)this.getMenuListModel().getElementAt(i));
            if (le.equals(value)){
                this.setSelectedIndex(i);
                break;
            }
        }
    }

    public ListElement extractListElementByIndex(int index) {
        ListElement le = null;
        List<ListElement> elementsList = this.getMenuListModel().getElementList();
        if (elementsList != null && (index > 0) && (index <= elementsList.size())) {
            le = elementsList.get(index - 1);
        }
        return le;
    }

    public ListElement extractListElement(int value) {
      for (ListElement le : this.getMenuListModel().getElementList()) {
            if (le.getIntegerValue() == value) {
                return le;
            }
        }
        return null;
    }

    public ListElement extractListElement(TextData value) {
        return extractListElement(value.toString());
    }

    public ListElement extractListElement(String value) {
      for (ListElement le : this.getMenuListModel().getElementList()) {
            if (le.getTextValue().toString().equals(value)) {
                return le;
            }
        }
        return null;
    }

    public ListElement extractListElement(Object value) {
      for (ListElement le : this.getMenuListModel().getElementList()) {
            if (le.getObjectValue().equals(value)) {
                return le;
            }
        }
        return null;
    }


    public static class Model implements ListModel, ListSelectionListener, ListField {
        protected SelectionInList list;
        protected MenuList ml;
        // TF:08/11/2009:DET-127:Added in catering for nullable value model types
        protected Class<?> valueClass;
        protected boolean isNullable;

        public Model(SelectionInList pModel, MenuList pList) {
            super();
            this.list = pModel;
            this.ml = pList;
            ValueModel holder = this.list.getSelectionHolder();
            if (holder instanceof TypeAwareValueModel) {
              valueClass = ((TypeAwareValueModel)holder).getValueType();
              isNullable = IntegerNullable.class.isAssignableFrom(this.valueClass) || TextNullable.class.isAssignableFrom(valueClass);
            }
        }

        public MenuList getMenuList() {
            return this.ml;
        }

//        public void setRadioList(MenuList ml) {
//            this.ml = ml;
//        }

        public Object getElementAt(int index) {
            return this.list.getElementAt(index);
        }
        public int getSize() {
            return this.list.getSize();
        }

        public void addListDataListener(ListDataListener l) {
            this.list.addListDataListener(l);
        }

        public void removeListDataListener(ListDataListener l) {
            this.list.removeListDataListener(l);
        }

        public void valueChanged(ListSelectionEvent ev) {
            if (!ev.getValueIsAdjusting()) {
                ClientEventManager.postEvent( ev.getSource(), "AfterValueChange" );
                UIutils.setDataChangedFlag((JComponent)ev.getSource());
                ChildEventHelper.postEventToAllParents((Component)ev.getSource(), "ChildAfterValueChange");
            }
        }

        public int getIntegerValue() {
          // TF:08/11/2009:Changed this to get the value directly from the model
//            if (this.ml != null)
//                return this.ml.getIntegerValue();
//            else
//                return -1;
          int index = list.getSelectionIndex();
          List<ListElement> items = this.getElementList();
          if (index >= 0 && index < items.size() && items.get(index) != null) {
            return items.get(index).getIntegerValue();
          }
          return Integer.MIN_VALUE;
        }

        public Object getObjectValue() {
          // TF:08/11/2009:Changed this to get the value directly from the model
//            if (this.ml != null)
//                return this.ml.getObjectValue();
//            else
//                return null;
          int index = list.getSelectionIndex();
          List<ListElement> items = this.getElementList();
          if (index >= 0 && index < items.size() && items.get(index) != null) {
            return items.get(index).getObjectValue();
          }
          return null;
        }

        public TextData getTextValue() {
          // TF:08/11/2009:Changed this to get the value directly from the model
//            if (this.ml != null)
//                return this.ml.getTextValue();
//            else
//                return null;
          int index = list.getSelectionIndex();
          List<ListElement> items = this.getElementList();
          if (index >= 0 && index < items.size() && items.get(index) != null) {
            return items.get(index).getTextValue();
          }
          return new TextData("");
        }

        public void setIntegerValue(int value) {
            if (this.ml != null)
                this.ml.setIntegerValue(value);
        }

        public void setObjectValue(Object value) {
            if (this.ml != null)
                this.ml.setObjectValue(value);
        }

        public void setTextValue(TextData value) {
            if (this.ml != null)
                this.ml.setTextValue(value);
        }

        @SuppressWarnings("unchecked")
    public Array_Of_ListElement<ListElement> getElementList() {
          // TF:08/11/2009:Changed this so that the model is the source of truth for the data
//            return this.ml.getElementList();
          return (Array_Of_ListElement)this.list.getListHolder().getValue();
        }

        public void setElementList(Array_Of_ListElement<ListElement> les) {
            Object currentValue = this.list.getValue();
            this.list.setList(les);
//            this.ml.setElementList(les);
            this.list.setValue(currentValue);

            // TF:08/11/2009:Based on testing with Forte, we need to do this even if
            // the passed value is nullable.
            if (this.list.getValue() == null && les.size() > 0 && !isNullable) {
                // Always default the first one in the list if needed
                this.list.setValue(les.get(0));
                this.ml.setSelectedIndex(0);
            }
            this.ml.invalidate();
        }
        public int getSelectedIndex() {
          // TF:08/11/2009:DET-127:Returned the value directly
//            return this.ml.getSelectedIndex();
          return list.getSelectionIndex();
        }

        public void setSelectedIndex(int index) {
            this.ml.setSelectedIndex(index);
        }
       
        /* (non-Javadoc)
         * @see ListField#setElementSelected(int, boolean)
         * @author AD:26/5/2008
         */
    public void setElementSelected(int index, boolean isSelected) {
      if (isSelected) {
        this.setSelectedIndex(index);
      } else {
        // Set no item to be selected
        this.setSelectedIndex(-1);
      }
     
    }
    }
    /**
     * Adds an <code>ActionListener</code> to the button.
     * @param l the <code>ActionListener</code> to be added
     */
    public void addActionListener(ActionListener l) {
        listenerList.add(ActionListener.class, l);
    }

    /**
     * Removes an <code>ActionListener</code> from the button.
     * If the listener is the currently set <code>Action</code>
     * for the button, then the <code>Action</code>
     * is set to <code>null</code>.
     *
     * @param l the listener to be removed
     */
    public void removeActionListener(ActionListener l) {
        listenerList.remove(ActionListener.class, l);
    }

    /**
     * Returns an array of all the <code>ActionListener</code>s added
     * to this AbstractButton with addActionListener().
     *
     * @return all of the <code>ActionListener</code>s added or an empty
     *         array if no listeners have been added
     */
    public ActionListener[] getActionListeners() {
        return (ActionListener[])(listenerList.getListeners(
                ActionListener.class));
    }
    protected void fireActionPerformed(ActionEvent event) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        ActionEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==ActionListener.class) {
                // Lazily create the event:
                if (e == null) {
                    String actionCommand = event.getActionCommand();
                    e = new ActionEvent(this,
                            ActionEvent.ACTION_PERFORMED,
                            actionCommand,
                            event.getWhen(),
                            event.getModifiers());
                }
                ((ActionListener)listeners[i+1]).actionPerformed(e);
            }         
        }
    }

    public Object clone(boolean deep) {
        MenuList result = new MenuList();
        result.setName(this.getName());
        if (this.isPreferredSizeSet()) {
            result.setPreferredSize(this.getPreferredSize());
        }
        else {
            result.setPreferredSize(null);
        }
        if (this.isMinimumSizeSet()) {
            result.setMinimumSize(this.getMinimumSize());
        }
        else {
            result.setMinimumSize(null);
        }
        result.setSize(this.getSize());
        result.setElementList(this.getElementList());
        CloneHelper.cloneClientProperties(this, result);

        return result;
    }
}
TOP

Related Classes of DisplayProject.controls.MenuList$Model

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.