Implement #4 Set ComboBox AutoReducible - Thanks to Yan and Derek
http://hg.idempiere.com/idempiere/issue/4/set-combobox-autoreducible http://www.red1.org/adempiere/viewtopic.php?f=31&t=1203
This commit is contained in:
parent
98464c0934
commit
8d447eebe1
|
@ -39,7 +39,7 @@ public class VComboBox extends CComboBox
|
|||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 2024662772161020317L;
|
||||
private static final long serialVersionUID = 7632613004262943867L;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -156,7 +156,7 @@ public class VComboBox extends CComboBox
|
|||
*/
|
||||
public String getDisplay()
|
||||
{
|
||||
if (getSelectedIndex() == -1)
|
||||
if (getSelectedItem() == null)
|
||||
return "";
|
||||
//
|
||||
NamePair p = (NamePair)getSelectedItem();
|
||||
|
@ -165,4 +165,12 @@ public class VComboBox extends CComboBox
|
|||
return p.getName();
|
||||
} // getDisplay
|
||||
|
||||
@Override
|
||||
protected boolean isMatchingFilter(Object element)
|
||||
{
|
||||
if (element instanceof NamePair)
|
||||
element = ((NamePair)element).getName();
|
||||
return super.isMatchingFilter(element);
|
||||
}
|
||||
|
||||
} // VComboBox
|
||||
|
|
|
@ -274,7 +274,7 @@ public class VLookup extends JComponent
|
|||
m_lookup.fillComboBox (isMandatory(), true, true, false);
|
||||
m_combo.setModel(m_lookup);
|
||||
//
|
||||
AutoCompletion.enable(m_combo);
|
||||
// AutoCompletion.enable(m_combo);
|
||||
m_combo.addActionListener(this); // Selection
|
||||
m_combo.getEditor().getEditorComponent().addMouseListener(mouseAdapter); // popup
|
||||
// FocusListener to refresh selection before opening
|
||||
|
|
|
@ -17,16 +17,32 @@
|
|||
package org.compiere.swing;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.FocusManager;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.MutableComboBoxModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.EventListenerList;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.plaf.ComboBoxUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import org.adempiere.plaf.AdempierePLAF;
|
||||
import org.compiere.plaf.CompiereComboBoxUI;
|
||||
|
@ -45,7 +61,7 @@ public class CComboBox extends JComboBox
|
|||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 4605625077881909766L;
|
||||
private static final long serialVersionUID = 5918151626085721856L;
|
||||
|
||||
/**
|
||||
* Creates a <code>JComboBox</code> that takes it's items from an
|
||||
|
@ -141,12 +157,88 @@ public class CComboBox extends JComboBox
|
|||
/** Field Height */
|
||||
public static int FIELD_HIGHT = 0;
|
||||
|
||||
/** Property key for auto-reduction. */
|
||||
public static final String AUTO_REDUCIBLE_PROPERTY = "autoReducible";
|
||||
|
||||
/** Property key for case sensitive auto-reduction. */
|
||||
public static final String CASE_SENSITIVE_PROPERTY = "caseSensitive";
|
||||
|
||||
/** View model for hiding showing only filtered data */
|
||||
ReducibleModel m_reducibleModel;
|
||||
|
||||
/** Key listener for triggering an update the filtering model . */
|
||||
private ReducibleKeyListener reducibleKeyListener = new ReducibleKeyListener();
|
||||
|
||||
/** Reference Field */
|
||||
private static JTextField s_text = new JTextField(15);
|
||||
|
||||
/**
|
||||
* Common Init
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
FIELD_HIGHT = getPreferredSize().height;
|
||||
|
||||
setEditable(true);
|
||||
setAutoReducible(true);
|
||||
|
||||
addMouseListener(new MouseAdapter()
|
||||
{
|
||||
public void mousePressed(MouseEvent me) {
|
||||
if (SwingUtilities.isLeftMouseButton(me) && isAutoReducible())
|
||||
updateReducibleModel(false);
|
||||
}
|
||||
});
|
||||
|
||||
// when auto-reducing, the focus listener will ensure all data choices
|
||||
// are shown on initial focus, and that a valid selection is in place
|
||||
// when focus is lost
|
||||
final JTextComponent textComponent =
|
||||
(JTextComponent)getEditor().getEditorComponent();
|
||||
textComponent.addFocusListener(new FocusListener()
|
||||
{
|
||||
public void focusGained(FocusEvent fe)
|
||||
{
|
||||
if (isEditable())
|
||||
textComponent.selectAll();
|
||||
textComponent.repaint();
|
||||
}
|
||||
|
||||
public void focusLost(FocusEvent fe)
|
||||
{
|
||||
if (isAutoReducible())
|
||||
{
|
||||
Object item = m_reducibleModel.getSelectedItem();
|
||||
item = (item == null && m_reducibleModel.getSize() != 0) ?
|
||||
m_reducibleModel.getElementAt(0) : item;
|
||||
if (item == null)
|
||||
{
|
||||
updateReducibleModel(false);
|
||||
if (m_reducibleModel.getSize() != 0)
|
||||
item = m_reducibleModel.getElementAt(0);
|
||||
else
|
||||
return;
|
||||
}
|
||||
m_reducibleModel.setSelectedItem(item);
|
||||
}
|
||||
textComponent.setCaretPosition(0);
|
||||
hidePopup();
|
||||
textComponent.repaint();
|
||||
}
|
||||
});
|
||||
|
||||
textComponent.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
public void mouseClicked(MouseEvent me) {
|
||||
if (SwingUtilities.isLeftMouseButton(me) &&
|
||||
isAutoReducible() &&
|
||||
!isPopupVisible())
|
||||
{
|
||||
updateReducibleModel(false);
|
||||
showPopup();
|
||||
}
|
||||
}
|
||||
});
|
||||
} // init
|
||||
|
||||
|
||||
|
@ -166,6 +258,23 @@ public class CComboBox extends JComboBox
|
|||
m_icon = defaultIcon;
|
||||
} // setIcon
|
||||
|
||||
|
||||
public ComboBoxModel getCompleteComboBoxModel()
|
||||
{
|
||||
return m_reducibleModel.getModel();
|
||||
} // getCompleteComboBoxModel
|
||||
|
||||
/**
|
||||
* @see javax.swing.JComboBox#setModel(javax.swing.ComboBoxModel)
|
||||
*/
|
||||
public void setModel(ComboBoxModel aModel)
|
||||
{
|
||||
m_reducibleModel = (m_reducibleModel == null) ? new ReducibleModel() : m_reducibleModel;
|
||||
m_reducibleModel.setModel(aModel);
|
||||
|
||||
super.setModel(m_reducibleModel);
|
||||
} // setModel
|
||||
|
||||
/**
|
||||
* Set UI and re-set Icon for arrow button
|
||||
* @param ui
|
||||
|
@ -345,4 +454,535 @@ public class CComboBox extends JComboBox
|
|||
setName(actionCommand);
|
||||
} // setActionCommand
|
||||
|
||||
/**
|
||||
* Called only when auto-reducing. By default, does a case insensitive
|
||||
* string search for a match in the string representation of the given
|
||||
* element.
|
||||
*
|
||||
* @param element an element in the combo box model
|
||||
*
|
||||
* @return true if the choice is to be displayed in the popup menu
|
||||
*/
|
||||
protected boolean isMatchingFilter(Object element)
|
||||
{
|
||||
String str = (element != null) ? element.toString().trim() : "";
|
||||
str = isCaseSensitive() ? str : str.toLowerCase();
|
||||
|
||||
return str.indexOf(m_reducibleModel.getMatchingFilter()) > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the combo box auto-reducible?
|
||||
*
|
||||
* @return true if isAutoReducible()
|
||||
*/
|
||||
public boolean isAutoReducible()
|
||||
{
|
||||
Boolean b = (Boolean)getClientProperty(AUTO_REDUCIBLE_PROPERTY);
|
||||
return (b != null) && b.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the combo box is auto-reducible. The combo box must also be editable
|
||||
* for auto-reduction to fully functional. Auto-reduction of data will preclude
|
||||
* the ability for users to enter in their own choices.
|
||||
*
|
||||
* @param autoreducible true will activate auto-reduction of choices when user enters text
|
||||
*/
|
||||
public void setAutoReducible(boolean autoreducible)
|
||||
{
|
||||
if (isAutoReducible() != autoreducible)
|
||||
{
|
||||
putClientProperty(AUTO_REDUCIBLE_PROPERTY, Boolean.valueOf(autoreducible));
|
||||
updateReducibleModel(false);
|
||||
|
||||
JTextComponent textComponent =
|
||||
(JTextComponent)getEditor().getEditorComponent();
|
||||
if (autoreducible)
|
||||
textComponent.addKeyListener(reducibleKeyListener);
|
||||
else
|
||||
textComponent.removeKeyListener(reducibleKeyListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the auto-reduction case sensitive?
|
||||
*
|
||||
* @return true if case sensitive
|
||||
*/
|
||||
public boolean isCaseSensitive()
|
||||
{
|
||||
Boolean b = (Boolean)getClientProperty(CASE_SENSITIVE_PROPERTY);
|
||||
return (b != null) && b.booleanValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.JComboBox#removeAllItems()
|
||||
*/
|
||||
public void removeAllItems()
|
||||
{
|
||||
m_reducibleModel.removeAllElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether auto-reduction is case sensitive.
|
||||
*
|
||||
* @param caseSensitive true will make auto-reduction is case sensitive
|
||||
*/
|
||||
public void setCaseSensitive(boolean caseSensitive)
|
||||
{
|
||||
putClientProperty(CASE_SENSITIVE_PROPERTY, Boolean.valueOf(caseSensitive));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the auto-reduction model.
|
||||
*
|
||||
* @param filtering true if the underlying data model should be filtered
|
||||
*/
|
||||
void updateReducibleModel(boolean filtering)
|
||||
{
|
||||
if (filtering ||
|
||||
m_reducibleModel.getSize() != m_reducibleModel.getModel().getSize())
|
||||
{
|
||||
if (getParent() != null)
|
||||
hidePopup();
|
||||
|
||||
// remember to caret position
|
||||
JTextComponent textComponent =
|
||||
(JTextComponent)getEditor().getEditorComponent();
|
||||
int pos = textComponent.getCaretPosition();
|
||||
m_reducibleModel.setFilter(textComponent.getText());
|
||||
|
||||
// update the model
|
||||
m_reducibleModel.updateModel(filtering);
|
||||
|
||||
// reset the caret
|
||||
textComponent.setText(m_reducibleModel.getFilter());
|
||||
textComponent.setCaretPosition(pos);
|
||||
|
||||
// ensure the combo box is resized to match the popup, if necessary
|
||||
if (getParent() != null)
|
||||
{
|
||||
getParent().validate();
|
||||
getParent().repaint();
|
||||
|
||||
if (isShowing() && m_reducibleModel.getSize() > 0) {
|
||||
// only show the popup if there is something to show
|
||||
showPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A view adapter model to hide filtered choices in the underlying combo box model.
|
||||
*/
|
||||
private class ReducibleModel implements MutableComboBoxModel, ListDataListener
|
||||
{
|
||||
/**
|
||||
* Default constructor. Creates a ReducibleModel.
|
||||
*/
|
||||
public ReducibleModel()
|
||||
{
|
||||
}
|
||||
|
||||
/** The wrapped data model. */
|
||||
private ComboBoxModel m_model;
|
||||
|
||||
/** The wrapped data model. */
|
||||
private EventListenerList m_listenerList = new EventListenerList();
|
||||
|
||||
/** The filtered data. */
|
||||
private ArrayList<Object> m_visibleData = new ArrayList<Object>();
|
||||
|
||||
/** The filtered data. */
|
||||
private ArrayList<Object> m_modelData = new ArrayList<Object>();
|
||||
|
||||
/** The current filter. */
|
||||
private String m_filter = "";
|
||||
|
||||
/** The cached filter for case insensitive filtering. */
|
||||
private String m_lcFilter = "";
|
||||
|
||||
/**
|
||||
* Pass through to the wrapped model if underlying model is MutableComboBoxModel.
|
||||
*
|
||||
* @see javax.swing.DefaultComboBoxModel#addElement(java.lang.Object)
|
||||
*/
|
||||
public void addElement(Object anObject)
|
||||
{
|
||||
checkMutableComboBoxModel();
|
||||
m_modelData.add(anObject);
|
||||
((MutableComboBoxModel)m_model).addElement(anObject);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.ListModel#addListDataListener(javax.swing.event.ListDataListener)
|
||||
*/
|
||||
public void addListDataListener(ListDataListener ldl)
|
||||
{
|
||||
m_listenerList.remove(ListDataListener.class, ldl);
|
||||
m_listenerList.add(ListDataListener.class, ldl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the <code>dataModel</code> is an instance of
|
||||
* <code>MutableComboBoxModel</code>. If not, it throws an exception.
|
||||
*
|
||||
* @exception RuntimeException if <code>dataModel</code> is not an
|
||||
* instance of <code>MutableComboBoxModel</code>.
|
||||
*/
|
||||
void checkMutableComboBoxModel()
|
||||
{
|
||||
if ( !(m_model instanceof MutableComboBoxModel) )
|
||||
throw new RuntimeException("Cannot use this method with a non-Mutable data model.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.event.ListDataListener#contentsChanged(javax.swing.event.ListDataEvent)
|
||||
*/
|
||||
public void contentsChanged(ListDataEvent lde)
|
||||
{
|
||||
updateDataModel();
|
||||
updateModel(false);
|
||||
|
||||
if (isPopupVisible())
|
||||
{
|
||||
hidePopup();
|
||||
showPopup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void fireContentsChanged()
|
||||
{
|
||||
ListDataEvent lde = null;
|
||||
for (ListDataListener ldl : getListDataListeners())
|
||||
{
|
||||
lde = (lde == null) ?
|
||||
new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize()) : lde;
|
||||
ldl.contentsChanged(lde);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.ListModel#getElementAt(int)
|
||||
*/
|
||||
public Object getElementAt(int index)
|
||||
{
|
||||
return m_visibleData.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current filter.
|
||||
*
|
||||
* @return the filter
|
||||
*/
|
||||
public String getFilter()
|
||||
{
|
||||
return m_filter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ListDataListener[] getListDataListeners()
|
||||
{
|
||||
return (ListDataListener[])m_listenerList.getListeners(ListDataListener.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the filter to use for matching; hecks case sensistivity
|
||||
*/
|
||||
protected String getMatchingFilter()
|
||||
{
|
||||
return isCaseSensitive() ? m_filter : m_lcFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the wrapped model
|
||||
*/
|
||||
public ComboBoxModel getModel()
|
||||
{
|
||||
return m_model;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the selected item in the wrapped model
|
||||
*
|
||||
* @see javax.swing.DefaultComboBoxModel#getSelectedItem()
|
||||
*/
|
||||
public Object getSelectedItem()
|
||||
{
|
||||
return m_model.getSelectedItem();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.ListModel#getSize()
|
||||
*/
|
||||
public int getSize()
|
||||
{
|
||||
return m_visibleData.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through to the wrapped model if underlying model is MutableComboBoxModel.
|
||||
*
|
||||
* @see javax.swing.DefaultComboBoxModel#insertElementAt(java.lang.Object, int)
|
||||
*/
|
||||
public void insertElementAt(Object anObject, int index)
|
||||
{
|
||||
checkMutableComboBoxModel();
|
||||
m_modelData.add(index, anObject);
|
||||
((MutableComboBoxModel)m_model).insertElementAt(anObject, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through to the wrapped model if underlying model is MutableComboBoxModel.
|
||||
*
|
||||
* @see javax.swing.event.ListDataListener#intervalAdded(javax.swing.event.ListDataEvent)
|
||||
*/
|
||||
public void intervalAdded(ListDataEvent lde)
|
||||
{
|
||||
updateDataModel();
|
||||
updateModel(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through to the wrapped model if underlying model is MutableComboBoxModel.
|
||||
*
|
||||
* @see javax.swing.event.ListDataListener#intervalRemoved(javax.swing.event.ListDataEvent)
|
||||
*/
|
||||
public void intervalRemoved(ListDataEvent lde)
|
||||
{
|
||||
updateDataModel();
|
||||
updateModel(false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void removeAllElements()
|
||||
{
|
||||
checkMutableComboBoxModel();
|
||||
|
||||
ListDataListener[] listeners = getListDataListeners();
|
||||
for (int i = 0; i < listeners.length; i++)
|
||||
removeListDataListener(listeners[i]);
|
||||
m_model.removeListDataListener(this);
|
||||
|
||||
m_modelData.clear();
|
||||
m_visibleData.clear();
|
||||
while (m_model.getSize() > 0)
|
||||
((MutableComboBoxModel)m_model).removeElementAt(0);
|
||||
|
||||
for (ListDataListener ldl : listeners)
|
||||
addListDataListener(ldl);
|
||||
m_model.addListDataListener(this);
|
||||
|
||||
updateModel(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through to the wrapped model if underlying model is MutableComboBoxModel.
|
||||
*
|
||||
* @see javax.swing.DefaultComboBoxModel#removeElement(java.lang.Object)
|
||||
*/
|
||||
public void removeElement(Object anObject)
|
||||
{
|
||||
checkMutableComboBoxModel();
|
||||
m_modelData.remove(anObject);
|
||||
m_visibleData.clear();
|
||||
((MutableComboBoxModel)m_model).removeElement(anObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass through to the wrapped model if underlying model is MutableComboBoxModel.
|
||||
*
|
||||
* @see javax.swing.DefaultComboBoxModel#removeElementAt(int)
|
||||
*/
|
||||
public void removeElementAt(int index)
|
||||
{
|
||||
checkMutableComboBoxModel();
|
||||
m_modelData.remove(index);
|
||||
m_visibleData.clear();
|
||||
((MutableComboBoxModel)m_model).removeElementAt(index);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.swing.ListModel#removeListDataListener(javax.swing.event.ListDataListener)
|
||||
*/
|
||||
public void removeListDataListener(ListDataListener ldl)
|
||||
{
|
||||
m_listenerList.remove(ListDataListener.class, ldl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filter the filter to set
|
||||
*/
|
||||
public void setFilter(String filter)
|
||||
{
|
||||
this.m_filter = (filter != null) ? filter : "";
|
||||
m_lcFilter = filter.trim().toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the wrapped combo box model.
|
||||
*
|
||||
* @param model the model to set
|
||||
*/
|
||||
public void setModel(ComboBoxModel model)
|
||||
{
|
||||
if (this.m_model != null)
|
||||
this.m_model.removeListDataListener(this);
|
||||
|
||||
this.m_model = model;
|
||||
updateDataModel();
|
||||
m_filter = "";
|
||||
|
||||
model.addListDataListener(this);
|
||||
updateModel(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected item in the wrapped model.
|
||||
*
|
||||
* @see javax.swing.DefaultComboBoxModel#setSelectedItem(java.lang.Object)
|
||||
*/
|
||||
public void setSelectedItem(Object anObject)
|
||||
{
|
||||
if (anObject == null || m_modelData.contains(anObject))
|
||||
m_model.setSelectedItem(anObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view model based on whether filtering or not.
|
||||
*
|
||||
* @param filtering true if the underlying model is to be filtered
|
||||
*/
|
||||
public void updateDataModel()
|
||||
{
|
||||
m_modelData.clear();
|
||||
int size = m_model.getSize();
|
||||
for (int i = 0; i < size; i++)
|
||||
m_modelData.add(m_model.getElementAt(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view model based on whether filtering or not.
|
||||
*
|
||||
* @param filtering true if the underlying model is to be filtered
|
||||
*/
|
||||
public void updateModel(boolean filtering)
|
||||
{
|
||||
boolean includeAll = !filtering || !isAutoReducible() || "".equals(m_lcFilter);
|
||||
if (includeAll)
|
||||
{
|
||||
m_visibleData.clear();
|
||||
m_visibleData.addAll(m_modelData);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_visibleData.clear();
|
||||
Object selected = getSelectedItem();
|
||||
ListDataListener[] listeners = getListDataListeners();
|
||||
for (int i = 0; i < listeners.length; i++)
|
||||
removeListDataListener(listeners[i]);
|
||||
m_model.removeListDataListener(this);
|
||||
|
||||
|
||||
int size = m_model.getSize();
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
Object element = m_model.getElementAt(i);
|
||||
if (element == null || isMatchingFilter(element))
|
||||
{
|
||||
m_visibleData.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_visibleData.contains(selected) || selected == null)
|
||||
setSelectedItem(selected);
|
||||
|
||||
for (ListDataListener ldl : listeners)
|
||||
addListDataListener(ldl);
|
||||
m_model.addListDataListener(this);
|
||||
}
|
||||
|
||||
fireContentsChanged();
|
||||
}
|
||||
} // ReducibleModel
|
||||
|
||||
/**
|
||||
* Key listener for editor's text compontent to trigger auto-reduction. Only
|
||||
* used when auto-reduction is enabled.
|
||||
*/
|
||||
class ReducibleKeyListener extends KeyAdapter
|
||||
{
|
||||
/** Invokes autoreduction. */
|
||||
private Runnable m_invoker = new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
updateReducibleModel(true);
|
||||
}
|
||||
};
|
||||
|
||||
/** Visibly updates the popup menu. */
|
||||
private Runnable m_updateMenu = new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
hidePopup();
|
||||
getParent().validate();
|
||||
getParent().repaint();
|
||||
showPopup();
|
||||
}
|
||||
};
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.awt.event.KeyAdapter#keyPressed(java.awt.event.KeyEvent)
|
||||
*/
|
||||
public void keyPressed(KeyEvent ke)
|
||||
{
|
||||
if (ke.getKeyCode() != KeyEvent.VK_CONTROL &&
|
||||
ke.getKeyCode() != KeyEvent.VK_ALT &&
|
||||
ke.getKeyCode() != KeyEvent.VK_SHIFT &&
|
||||
( ke.getModifiersEx() & InputEvent.ALT_DOWN_MASK ) == 0 )
|
||||
{
|
||||
if (ke.getKeyCode() == KeyEvent.VK_ENTER ||
|
||||
ke.getKeyCode() == KeyEvent.VK_TAB)
|
||||
{
|
||||
// enter key pressed, so complete editing and select item
|
||||
Object selObject = getSelectedItem();
|
||||
selObject = (selObject == null && getItemCount() > 0) ? getItemAt(0) : selObject;
|
||||
setSelectedItem(selObject);
|
||||
getEditor().setItem(getSelectedItem());
|
||||
}
|
||||
else if (ke.getKeyCode() == KeyEvent.VK_ESCAPE)
|
||||
{
|
||||
// escape key ends editing and rejects focus of text editor
|
||||
FocusManager.getCurrentManager().upFocusCycle();
|
||||
}
|
||||
else if (ke.getKeyCode() == KeyEvent.VK_UP ||
|
||||
ke.getKeyCode() == KeyEvent.VK_KP_UP ||
|
||||
ke.getKeyCode() == KeyEvent.VK_DOWN ||
|
||||
ke.getKeyCode() == KeyEvent.VK_KP_DOWN)
|
||||
{
|
||||
// up or down selects new value
|
||||
SwingUtilities.invokeLater(m_updateMenu);
|
||||
}
|
||||
else
|
||||
{
|
||||
// key typed, so filter
|
||||
SwingUtilities.invokeLater(m_invoker);
|
||||
setSelectedItem(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // ReducibleKeyListener
|
||||
|
||||
} // CComboBox
|
||||
|
|
Loading…
Reference in New Issue