remove third party GenericJComboBox

master
melvin 2013-09-12 11:49:58 +08:00
parent 65b68dc6d3
commit 23f8dbdf3b
8 changed files with 0 additions and 758 deletions

View File

@ -1,24 +0,0 @@
package support.ui;
/**
* Provides a textual description for an item of type {@code T}.
*
* @author jak2
* @param <T>
*/
public interface DescriptionProvider<T>
{
/**
* The text displayed to represent the item. May not be {@code null}.
*
* @return
*/
public String getDisplayText(T item);
/**
* The text displayed as a tool tip for the item. May be {@code null}.
*
* @return
*/
public String getToolTipText(T item);
}

View File

@ -1,126 +0,0 @@
package support.ui;
import java.awt.Component;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
/**
* Uses a {@link DescriptionProvider} to determine what is rendered for each cell. Delegates the actual rendering.
*
* @param <T> The type of the data being rendered to a cell.
*
* @author jak2
*/
class DescriptionProviderCellRenderer<T> implements ListCellRenderer
{
interface ItemInfoProvider<T>
{
public T getElementDisplayedAt(int i);
}
private final DescriptionProvider<T> _descriptionProvider;
private final ListCellRenderer _delegateRenderer;
private final Map<T, String> _cachedDisplayText, _cachedTooltips;
private final ItemInfoProvider<T> _infoProvider;
/**
* A ListCellRenderer that uses the {@code descriptionProvider} to determine what is actually rendered by the
* {@code delegateRenderer}. The {@code delegateRenderer} should be the renderer that would normally
* be used if this renderer was not used.
*
* @param delegateRenderer
* @param infoProvider
* @param descriptionProvider
*/
public DescriptionProviderCellRenderer(ListCellRenderer delegateRenderer, ItemInfoProvider<T> infoProvider,
DescriptionProvider<T> descriptionProvider)
{
_delegateRenderer = delegateRenderer;
_infoProvider = infoProvider;
_descriptionProvider = descriptionProvider;
_cachedDisplayText = new HashMap<T, String>();
_cachedTooltips = new HashMap<T, String>();
}
/**
* Clears the cached Strings built using the supplied {@link StringConverter}. The cache is used to increase
* performance, but the cache will need to be cleared when updated conversions are desired.
*/
public void clearCache()
{
_cachedDisplayText.clear();
_cachedTooltips.clear();
}
/**
* Renders the cell using the {@code #_delegateRenderer} provided to the constructor. Intercepts the object that the
* {@code #_delegateRenderer} would normally have rendered and instead has it render the String supplied by the
* {@code #_descriptionProvider} provided to the constructor.
*
* @param list
* @param value
* @param index
* @param isSelected
* @param cellHasFocus
* @return
*/
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus)
{
T valueInModel = _infoProvider.getElementDisplayedAt(index);
if(!_cachedDisplayText.containsKey(valueInModel))
{
_cachedDisplayText.put(valueInModel, _descriptionProvider.getDisplayText(valueInModel));
}
String displayText = _cachedDisplayText.get(valueInModel);
Component comp = _delegateRenderer.getListCellRendererComponent(list, displayText, index, isSelected,
cellHasFocus);
//JComponent has a setToolTipText(String) method but Component does not
if(comp instanceof JComponent)
{
if(!_cachedTooltips.containsKey(valueInModel))
{
String tooltip = _descriptionProvider.getToolTipText(valueInModel);
final int wrapLength = 80;
if(tooltip != null && tooltip.length() > wrapLength)
{
StringBuilder wrappedTooltip = new StringBuilder("<html>");
int lineCounter = 0;
for(char c : tooltip.toCharArray())
{
lineCounter++;
if(lineCounter > wrapLength && c == ' ')
{
wrappedTooltip.append("<br/>");
lineCounter = 0;
}
else
{
wrappedTooltip.append(c);
}
}
wrappedTooltip.append("</html>");
tooltip = wrappedTooltip.toString();
}
_cachedTooltips.put(valueInModel, tooltip);
}
String tooltip = _cachedTooltips.get(valueInModel);
((JComponent) comp).setToolTipText(tooltip);
}
return comp;
}
}

View File

@ -1,41 +0,0 @@
package support.ui;
import javax.swing.AbstractListModel;
/**
* The generic abstract definition for the data model that provides a list with its contents.
*
* @author jak2
*/
public abstract class GenericAbstractListModel<T> extends AbstractListModel implements GenericListModel<T>
{
@Override
public boolean hasElements()
{
return !getElements().isEmpty();
}
@Override
public T getElementAt(int i)
{
T elem = null;
if(i >= 0 && i < getElements().size())
{
elem = getElements().get(i);
}
return elem;
}
@Override
public int getSize()
{
return getElements().size();
}
@Override
public void notifyRefresh()
{
fireContentsChanged(this, 0, this.getSize() - 1);
}
}

View File

@ -1,159 +0,0 @@
package support.ui;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.ComboBoxModel;
import support.ui.SelectionListener.SelectionAction;
/**
* A generic data storage used by {@link GenericJComboBox}. By having this class be generic, it allows for accessing the
* data with type safety and no need to cast.
*
* @author jak2
*/
public class GenericComboBoxModel<T> extends GenericImmutableListModel<T> implements ComboBoxModel
{
private static final long serialVersionUID = 1L;
private T _selectedItem;
private boolean _isSelectionInProgress;
public GenericComboBoxModel(Iterable<T> data)
{
super(data);
_selectedItem = this.hasElements() ? this.getElementAt(0) : null;
_isSelectionInProgress = false;
}
public GenericComboBoxModel(Iterable<T> data, T initialSelection)
{
super(data);
_selectedItem = findMatchingObject(initialSelection) != null ? initialSelection : null;
_isSelectionInProgress = false;
}
public GenericComboBoxModel()
{
this(Collections.<T>emptyList());
}
@Override
public void setSelectedItem(Object item)
{
//If item is not the same as _selectedItem
if((_selectedItem != null && !_selectedItem.equals(item)) || (_selectedItem == null && item != null))
{
if(item == null)
{
this.setSelectedItemInternal(null);
}
else
{
//If item is in the model, then it will be returned in a typesafe manner, if it is not then null will be
//returned and no selection should be made
T itemInModel = findMatchingObject(item);
if(itemInModel != null)
{
this.setSelectedItemInternal(itemInModel);
}
}
}
}
public void setGenericSelectedItem(T item)
{
//If item is not the same as _selectedItem
if((_selectedItem != null && !_selectedItem.equals(item)) || (_selectedItem == null && item != null))
{
if(item == null)
{
this.setSelectedItemInternal(null);
}
//If the selection is contained in the data
else if(this.getElements().contains(item))
{
this.setSelectedItemInternal(item);
}
}
}
private void setSelectedItemInternal(T item)
{
boolean cancelled = notifySelectionListeners(_selectedItem, item, true);
if(!cancelled)
{
_selectedItem = item;
//Matches behavior of javax.swing.DefaultComboBoxModel
fireContentsChanged(this, -1, -1);
}
}
private final List<SelectionListener<T>> _listeners = new CopyOnWriteArrayList<SelectionListener<T>>();
void addSelectionListener(SelectionListener<T> listener)
{
_listeners.add(listener);
}
void removeSelectionListener(SelectionListener<T> listener)
{
_listeners.remove(listener);
}
void transferSelectionListeners(GenericComboBoxModel<T> otherModel)
{
_listeners.addAll(otherModel._listeners);
otherModel._listeners.clear();
}
boolean notifySelectionListeners(T currValue, T newValue, boolean isCancellable)
{
_isSelectionInProgress = true;
SelectionAction action = new SelectionAction(isCancellable);
for(SelectionListener<T> listener : _listeners)
{
listener.selectionPerformed(currValue, newValue, action);
}
_isSelectionInProgress = false;
return action.isCancelled();
}
public boolean isSelectionInProgress()
{
return _isSelectionInProgress;
}
/**
* Finds the object stored in this model that is the <strong>exact</strong> same instance of {@code obj}. If none is
* found, {@code null} is returned.
*
* @param obj
* @return
*/
private T findMatchingObject(Object obj)
{
T match = null;
for(T elem : this.getElements())
{
if(obj == elem)
{
match = elem;
break;
}
}
return match;
}
@Override
public T getSelectedItem()
{
return _selectedItem;
}
}

View File

@ -1,35 +0,0 @@
package support.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A generic list model that does not provide a means for its contents to be mutated.
*
* @author jak2
*/
public class GenericImmutableListModel<T> extends GenericAbstractListModel<T>
{
private static final long serialVersionUID = 1L;
private final List<T> _elements;
public GenericImmutableListModel(Iterable<T> data)
{
//Implementation note: this code intentionally does not use Google Collection's ImmutableList because it does
//not support the list containg null
ArrayList<T> tempList = new ArrayList<T>();
for(T item : data)
{
tempList.add(item);
}
_elements = Collections.unmodifiableList(tempList);
}
@Override
public List<T> getElements()
{
return _elements;
}
}

View File

@ -1,287 +0,0 @@
package support.ui;
import java.util.Collections;
import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
/**
* A parameterized {@link JComboBox}. Does <strong>not</strong> support adding, inserting, or removing specific items.
* <br/><br/>
* Unlike the standard {@code JComboBox}, this class supports having an item that is {@code null}. However, when
* {@code null} is stored in this combo box, it is not possible to have no item in the combo box selected.
* <br/><br/>
* Unexpected behavior may arise if not all entries are unique.
*
* @author jak2
*/
public class GenericJComboBox<E> extends JComboBox implements DescriptionProviderCellRenderer.ItemInfoProvider<E>
{
private static final long serialVersionUID = 1L;
private GenericComboBoxModel<E> _model;
private DescriptionProviderCellRenderer _renderer;
public GenericJComboBox(Iterable<E> values, DescriptionProvider<E> descriptionProvider)
{
this(values);
this.setDescriptionProvider(descriptionProvider);
}
public GenericJComboBox(DescriptionProvider<E> descriptionProvider)
{
this();
this.setDescriptionProvider(descriptionProvider);
}
public GenericJComboBox(Iterable<E> items)
{
this.setItems(items);
}
public GenericJComboBox()
{
this(Collections.<E>emptyList());
}
public void setDescriptionProvider(DescriptionProvider<E> descriptionProvider)
{
_renderer = new DescriptionProviderCellRenderer<E>(new BasicComboBoxRenderer(), this, descriptionProvider);
this.setRenderer(_renderer);
_model.notifyRefresh();
}
/**
* For internal use <strong>only</strong>.
* <br/><br/>
* This method must be public in order to interact properly with {@link JComboBox}; however, it should not be called
* from other classes.
*
* @param obj
*
* @deprecated deprecated due to lack of type safety
* @see #setGenericSelectedItem(java.lang.Object)
*/
@Override
@Deprecated
public void setSelectedItem(Object obj)
{
_model.setSelectedItem(obj);
}
/**
* Sets the selected item in a typesafe manner.
*
* @param item
*/
public void setGenericSelectedItem(E item)
{
_model.setGenericSelectedItem(item);
}
/**
* Adds the selection listener.
*
* @param listener
*/
public void addSelectionListener(SelectionListener<E> listener)
{
_model.addSelectionListener(listener);
}
/**
* Removes the selection listener.
*
* @param listener
*/
public void removeSelectionListener(SelectionListener<E> listener)
{
_model.removeSelectionListener(listener);
}
@Override
public E getSelectedItem()
{
return _model.getSelectedItem();
}
@Override
public int getSelectedIndex()
{
//This allows for a null item in the list to be considered selected
return _model.getElements().indexOf(_model.getSelectedItem());
}
@Override
public E getItemAt(int index)
{
return _model.getElementAt(index);
}
/**
* Replaces all existing data with {@code items}.
*
* @param items
*/
public void setItems(Iterable<E> items)
{
this.setModel(new GenericComboBoxModel<E>(items));
}
public void setItems(Iterable<E> items, E initialSelection)
{
this.setModel(new GenericComboBoxModel<E>(items, initialSelection));
}
/**
* Returns an immutable list of all of items in this combo box.
*
* @return
*/
public List<E> getItems()
{
return _model.getElements();
}
/**
* This method cannot ensure type safety.
* <br/><br/>
* The no argument super constructor will call this method with an empty {@code model}, this behavior will be
* allowed, but the model provided will not be used.
*
* @param model
* @deprecated
*/
@Override
@Deprecated
public void setModel(ComboBoxModel model)
{
//If an empty model, swap it out
if(model.getSize() == 0)
{
this.setModel(new GenericComboBoxModel<E>());
}
//Due to type-erasure, it is not possible to verify that the elements of the model are of type E, so do not
//allow this behavior
else
{
throw new UnsupportedOperationException("Not valid for GenericJComboBox. Please use setItems(...)");
}
}
/**
* Sets the model in a type-safe manner.
*
* @param model
*/
private void setModel(GenericComboBoxModel<E> model)
{
E initSelection = null;
if(_model != null)
{
initSelection = _model.getSelectedItem();
model.transferSelectionListeners(_model);
}
_model = model;
super.setModel(model);
//If initial selection is in the new model maintain the selection
if(_model.getElements().contains(initSelection))
{
_model.setGenericSelectedItem(initSelection);
}
//Otherwise, notify listeners the selection has changed
else
{
_model.notifySelectionListeners(initSelection, _model.getSelectedItem(), false);
}
}
@Override
public GenericComboBoxModel<E> getModel()
{
return _model;
}
/**
* This method must be public to match a required interface; however, it is not intended for external use.
*
* @param i
* @return
*/
@Override
public E getElementDisplayedAt(int i)
{
E elem;
//For a JComboBox -1 indicates the popup is closed and it is rendering the selected item
if(i == -1)
{
elem = getSelectedItem();
}
else
{
elem = _model.getElementAt(i);
}
return elem;
}
@Override
public void removeAllItems()
{
this.setModel(new GenericComboBoxModel<E>());
}
/**
* <strong>Not supported</strong>
*
* @param anObject
*/
@Override
@Deprecated
public void addItem(Object anObject)
{
throw new UnsupportedOperationException("Mutation not supported");
}
/**
* <strong>Not supported</strong>
*
* @param anObject
* @param index
*/
@Override
@Deprecated
public void insertItemAt(Object anObject, int index)
{
throw new UnsupportedOperationException("Mutation not supported");
}
/**
* <strong>Not supported</strong>
*
* @param anObject
*/
@Override
@Deprecated
public void removeItem(Object anObject)
{
throw new UnsupportedOperationException("Mutation not supported");
}
/**
* <strong>Not supported</strong>
*
* @param anIndex
*/
@Override
@Deprecated
public void removeItemAt(int anIndex)
{
throw new UnsupportedOperationException("Mutation not supported");
}
}

View File

@ -1,40 +0,0 @@
package support.ui;
import java.util.List;
import javax.swing.ListModel;
/**
* A generic version {@link ListModel} with some additional functionality.
*
* @author jak2
*/
public interface GenericListModel<T> extends ListModel
{
/**
* Returns an immutable list of all of the elements in the model.
*
* @return
*/
public List<T> getElements();
/**
* If the model has any elements.
*
* @return
*/
public boolean hasElements();
/**
* Overrides this method in {@code ListModel} to always return an element of type {@code T}.
*
* @return
*/
@Override
public T getElementAt(int i);
/**
* Fires off an event that all of the elements of this model have changed. This will result in the UI using this
* model to repaint the elements.
*/
public void notifyRefresh();
}

View File

@ -1,46 +0,0 @@
package support.ui;
/**
* A listener for changes in selection.
*
* @author jak2
*/
public interface SelectionListener<E>
{
public static final class SelectionAction
{
private final boolean _isCancellable;
private boolean _cancel = false;
SelectionAction(boolean isCancellable)
{
_isCancellable = isCancellable;
}
public void cancel()
{
if(_isCancellable)
{
_cancel = true;
}
}
public boolean isCancelled()
{
return _cancel;
}
/**
* If the selection action can be canceled. In some situations, such as the items in the UI component changing,
* selection will change and there is no way to undo the implicit change in selection that results.
*
* @return
*/
public boolean isCancellable()
{
return isCancellable();
}
}
public void selectionPerformed(E currValue, E newValue, SelectionAction action);
}