/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.viewers; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.draw2d.ColorConstants; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.util.OpenStrategy; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckable; import org.eclipse.jface.viewers.IColorProvider; import org.eclipse.jface.viewers.IElementComparer; import org.eclipse.jface.viewers.IFontProvider; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Widget; public class CheckListViewer extends StructuredViewer implements ICheckable { protected static class CheckItem { private CheckListViewer listViewer; private Object data; private Composite bar; private Button checkbox; private Label imageLabel; private Label textLabel; private boolean selected; private boolean internalSetChecked = false; public CheckItem(CheckListViewer listViewer, Composite parent) { this.listViewer = listViewer; bar = new Composite(parent, SWT.NO_FOCUS); bar.setBackground(parent.getBackground()); bar.setData(this); GridLayoutFactory.fillDefaults().numColumns(3) .extendedMargins(5, 5, 1, 1).applyTo(bar); checkbox = new Button(bar, SWT.CHECK); checkbox.setText(""); //$NON-NLS-1$ checkbox.setBackground(bar.getBackground()); GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(checkbox); imageLabel = new Label(bar, SWT.NONE); imageLabel.setImage(null); imageLabel.setBackground(bar.getBackground()); GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER) .applyTo(imageLabel); textLabel = new Label(bar, SWT.NONE); textLabel.setText(""); //$NON-NLS-1$ textLabel.setBackground(bar.getBackground()); GridDataFactory.fillDefaults().grab(true, false) .align(SWT.FILL, SWT.CENTER).applyTo(textLabel); addControlListeners(); } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public CheckListViewer getListViewer() { return listViewer; } public Control getControl() { return bar; } protected Composite getBarComposite() { return bar; } protected void addControlListeners() { Listener listener = new Listener() { public void handleEvent(Event event) { int type = event.type; switch (type) { case SWT.Paint: paintBackground(event.gc); break; case SWT.MouseDown: if (event.widget == checkbox) { selectSingle(); } else { userSelect(event); if ((OpenStrategy.getOpenMethod() & OpenStrategy.SINGLE_CLICK) != 0) { userOpen(event); } } break; case SWT.MouseDoubleClick: if (OpenStrategy .getOpenMethod() == OpenStrategy.DOUBLE_CLICK) { userOpen(event); } break; case SWT.MouseHover: if ((OpenStrategy.getOpenMethod() & OpenStrategy.SELECT_ON_HOVER) != 0) { userSelect(event); } break; case SWT.Selection: if (!internalSetChecked) { userCheck(); } break; } } }; bar.addListener(SWT.Paint, listener); bar.addListener(SWT.MouseDown, listener); bar.addListener(SWT.MouseDoubleClick, listener); bar.addListener(SWT.MouseHover, listener); imageLabel.addListener(SWT.MouseDown, listener); imageLabel.addListener(SWT.MouseDoubleClick, listener); imageLabel.addListener(SWT.MouseHover, listener); textLabel.addListener(SWT.MouseDown, listener); textLabel.addListener(SWT.MouseDoubleClick, listener); textLabel.addListener(SWT.MouseHover, listener); checkbox.addListener(SWT.MouseDown, listener); checkbox.addListener(SWT.Selection, listener); } protected void userCheck() { getListViewer().fireChecked(this); } protected void paintBackground(GC gc) { if (isSelected()) { Rectangle bounds = bar.getBounds(); bounds.x = 0; bounds.y = 0; //Rectangle labelBounds = label.getBounds(); gc.setBackground(getSelectionBackground()); gc.fillRectangle(bounds); //gc.fillRectangle( labelBounds.x, bounds.y, bounds.x + bounds.width - labelBounds.x, bounds.height ); } } protected void userSelect(Event e) { selectSingle(); getListViewer().getControl().setFocus(); getListViewer().handleSelect(new SelectionEvent(e)); } protected void userOpen(Event e) { selectSingle(); getListViewer().getControl().setFocus(); getListViewer().handleOpen(new SelectionEvent(e)); } protected void selectSingle() { getListViewer().setSelectedItem(this); } public Button getCheckbox() { return checkbox; } public Label getLabel() { return textLabel; } public boolean isChecked() { return checkbox.getSelection(); } public void setChecked(boolean checked) { internalSetChecked = true; checkbox.setSelection(checked); internalSetChecked = false; } public String getText() { return textLabel.getText(); } public void setText(String text) { textLabel.setText(text); } public Image getImage() { return imageLabel.getImage(); } public void setImage(Image image) { imageLabel.setImage(image); } public boolean isSelected() { return selected; } public void setSelection(boolean selected) { if (selected == this.selected) return; this.selected = selected; bar.redraw(); textLabel.redraw(); if (selected) { checkbox.setBackground(getSelectionBackground()); imageLabel.setBackground(getSelectionBackground()); textLabel.setBackground(getSelectionBackground()); textLabel.setForeground(getSelectionTextColor()); } else { Color background = bar.getBackground(); checkbox.setBackground(background); imageLabel.setBackground(background); textLabel.setBackground(background); textLabel.setForeground(null); } } public void dispose() { bar.dispose(); } public boolean isDisposed() { return bar.isDisposed(); } } private static Color selectionBackground = null; private static Color selectionTextColor = null; protected static Color getSelectionBackground() { if (selectionBackground == null) { selectionBackground = ColorConstants.lightBlue; } return selectionBackground; } protected static Color getSelectionTextColor() { if (selectionTextColor == null) { selectionTextColor = Display.getCurrent() .getSystemColor(SWT.COLOR_BLACK); } return selectionTextColor; } private Composite list; /** * A list of viewer elements (element type: <code>Object</code>). */ private List<Object> listMap = new ArrayList<Object>(); private List<CheckItem> items = new ArrayList<CheckItem>(); private List<ICheckStateListener> checkStateListeners = new ArrayList<ICheckStateListener>(); private CheckItem selectedItem = null; public CheckListViewer(Composite parent, int style) { list = new Composite(parent, style) { @Override public boolean setFocus() { return super.forceFocus(); } @Override public Point computeSize(int wHint, int hHint, boolean changed) { Point size; if (getItemCount() == 0) { size = new Point(0, 0); if (wHint != SWT.DEFAULT) size.x = wHint; if (hHint != SWT.DEFAULT) size.y = hHint; Rectangle trim = computeTrim(0, 0, size.x, size.y); size = new Point(trim.width, trim.height); } else { size = super.computeSize(wHint, hHint, changed); } return size; } }; // list.addListener( SWT.MouseDown, new Listener() { // public void handleEvent( Event event ) { // } // } ); list.addListener(SWT.KeyDown, new Listener() { public void handleEvent(Event event) { int keyCode = event.keyCode; int stateMask = event.stateMask; if (keyCode == SWT.TAB) { if (stateMask == SWT.MOD2) { list.traverse(SWT.TRAVERSE_TAB_PREVIOUS); } else if (stateMask == 0) { list.traverse(SWT.TRAVERSE_TAB_NEXT); } } else if (SWTUtils.matchKey(stateMask, keyCode, 0, SWT.CR)) { CheckItem item = getSelectedItem(); if (item != null) item.userOpen(event); } else if (SWTUtils.matchKey(stateMask, keyCode, 0, ' ')) { if (selectedItem != null) { selectedItem.setChecked(!selectedItem.isChecked()); fireChecked(selectedItem); } } else if (SWTUtils.matchKey(stateMask, keyCode, 0, SWT.ARROW_UP)) { if (selectedItem != null) { userSelectPrevious(selectedItem, event); } else if (!items.isEmpty()) { userSelectItem(0, event); } } else if (SWTUtils.matchKey(stateMask, keyCode, 0, SWT.ARROW_DOWN)) { if (selectedItem != null) { userSelectNext(selectedItem, event); } else if (!items.isEmpty()) { userSelectItem(0, event); } } } }); list.setTabList(new Control[0]); list.setBackground(parent.getBackground()); GridLayoutFactory.fillDefaults().spacing(0, 0).applyTo(list); //hookControl( list ); list.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { handleDispose(e); } }); } protected void userSelectPrevious(CheckItem item, Event event) { int index = items.indexOf(item); if (index >= 1) { index--; userSelectItem(index, event); } } private void userSelectItem(int index, Event event) { setSelectedItem(items.get(index)); handleSelect(new SelectionEvent(event)); } protected void userSelectNext(CheckItem item, Event event) { int index = items.indexOf(item); if (index < listGetItemCount() - 1) { index++; userSelectItem(index, event); } } protected void setSelectedItem(CheckItem item) { if (item == this.selectedItem) return; this.selectedItem = item; for (CheckItem it : items) { it.setSelection(it == item); } } protected CheckItem getSelectedItem() { return selectedItem; } @Override public Control getControl() { return list; } protected Composite getListComposite() { return list; } protected List<CheckItem> getItems() { return items; } public int getItemCount() { return listGetItemCount(); } protected CheckItem listAdd(String string, Image image, int index) { CheckItem newItem = new CheckItem(this, list); GridDataFactory.fillDefaults().grab(true, false) .applyTo(newItem.getControl()); newItem.setImage(image); newItem.setText(string); list.layout(); if (index < 0 || index >= listGetItemCount()) { items.add(newItem); } else { CheckItem oldItem = items.get(index); items.add(index, newItem); newItem.getControl().moveAbove(oldItem.getControl()); } return newItem; } protected void listDeselectAll() { setSelectedItem(null); // for ( CheckboxItem item : items ) { // item.setSelection( false ); // } } protected int listGetItemCount() { return items.size(); } protected int[] listGetSelectionIndices() { int total = listGetItemCount(); int[] counts = new int[total]; int num = 0; int j = 0; for (int i = 0; i < total; i++) { CheckItem item = items.get(i); if (item.isSelected()) { counts[j] = i; num++; j++; } } int[] ixs = new int[num]; System.arraycopy(counts, 0, ixs, 0, num); return ixs; } protected CheckItem listRemove(int index) { if (index < 0 || index >= listGetItemCount()) return null; CheckItem item = items.remove(index); if (item != null) item.dispose(); return item; } protected void listRemoveAll() { for (CheckItem item : items) { item.dispose(); } items.clear(); } protected void listSetItem(int index, String string, Image image) { if (index < 0 || index >= listGetItemCount()) return; CheckItem item = items.get(index); if (!item.isDisposed()) { item.setImage(image); item.setText(string); } } // protected void listSetItems( String[] labels ) { // if ( labels != null && labels.length > 0 ) { // for ( String label : labels ) { // listAdd( label, null, -1 ); // } // } // } protected void listSetSelection(int[] ixs) { listDeselectAll(); int total = listGetItemCount(); for (int index : ixs) { if (index >= 0 && index < total) { CheckItem item = items.get(index); if (selectedItem == null) selectedItem = item; item.setSelection(true); } } } protected void listShowSelection() { } public void reveal(Object element) { } public void addCheckStateListener(ICheckStateListener listener) { checkStateListeners.add(listener); } public boolean getChecked(Object element) { int index = getElementIndex(element); if (index >= 0) { CheckItem item = items.get(index); return !item.isDisposed() && item.isChecked(); } return false; } public Object[] getCheckedElements() { int count = getItemCount(); ArrayList<Object> checked = new ArrayList<Object>(count); for (int i = 0; i < count; i++) { CheckItem item = items.get(i); if (item.isChecked()) checked.add(listMap.get(i)); } return checked.toArray(); } // private int findIndex( Object element ) { // int total = listGetItemCount(); // for ( int i = 0; i < total; i++ ) { // if ( getElementAt( i ) == element ) // return i; // } // return -1; // } public void removeCheckStateListener(ICheckStateListener listener) { checkStateListeners.remove(listener); } public boolean setChecked(Object element, boolean state) { int index = getElementIndex(element); if (index >= 0) { CheckItem item = items.get(index); if (!item.isDisposed()) item.setChecked(state); } return false; } // protected Object findElementByCheckbox( Widget checkboxWidget ) { // int total = listGetItemCount(); // for ( int i = 0; i < total; i++ ) { // CheckboxItem item = items.get( i ); // if ( !item.isDisposed() ) { // if ( item.getCheckbox() == checkboxWidget ) { // return getElementAt( i ); // } // } // } // return null; // } protected void fireChecked(CheckItem item) { Object element = getElementAt(items.indexOf(item)); if (element == null) return; final CheckStateChangedEvent event = new CheckStateChangedEvent(this, element, item.isChecked()); for (final Object o : checkStateListeners.toArray()) { SafeRunner.run(new SafeRunnable() { public void run() throws Exception { ((ICheckStateListener) o).checkStateChanged(event); } }); } } @Override protected void preservingSelection(Runnable updateCode) { Map<Object, Boolean> checkStateMap = new HashMap<Object, Boolean>(); int total = listGetItemCount(); for (int i = 0; i < total; i++) { Object element = getElementAt(i); boolean checked = items.get(i).isChecked(); checkStateMap.put(element, checked); } super.preservingSelection(updateCode); total = listGetItemCount(); for (int i = 0; i < total; i++) { Object element = getElementAt(i); Boolean checked = checkStateMap.get(element); if (checked != null) { items.get(i).setChecked(checked); } } } /** * Adds the given elements to this list viewer. If this viewer does not have * a sorter, the elements are added at the end in the order given; otherwise * the elements are inserted at appropriate positions. * <p> * This method should be called (by the content provider) when elements have * been added to the model, in order to cause the viewer to accurately * reflect the model. This method only affects the viewer, not the model. * </p> * * @param elements * the elements to add */ public void add(Object[] elements) { assertElementsNotNull(elements); Object[] filtered = filter(elements); ILabelProvider labelProvider = (ILabelProvider) getLabelProvider(); for (int i = 0; i < filtered.length; i++) { Object element = filtered[i]; int ix = indexForElement(element); insertItem(labelProvider, element, ix); } } private void insertItem(ILabelProvider labelProvider, Object element, int index) { String label = getLabelProviderText(labelProvider, element); Image image = getImage(labelProvider, element); CheckItem item = listAdd(label, image, index); listMap.add(index, element); mapElement(element, item.getControl()); // must map it, since findItem only looks in map, if enabled } /** * Inserts the given element into this list viewer at the given position. If * this viewer has a sorter, the position is ignored and the element is * inserted at the correct position in the sort order. * <p> * This method should be called (by the content provider) when elements have * been added to the model, in order to cause the viewer to accurately * reflect the model. This method only affects the viewer, not the model. * </p> * * @param element * the element * @param position * a 0-based position relative to the model, or -1 to indicate * the last position * @since 3.3 */ public void insert(Object element, int position) { if (getComparator() != null || hasFilters()) { add(element); return; } insertItem((ILabelProvider) getLabelProvider(), element, position); } /** * Return the text for the element from the labelProvider. If it is null * then return the empty String. * * @param labelProvider * ILabelProvider * @param element * @return String. Return the emptyString if the labelProvider returns null * for the text. * @since 3.1 */ private String getLabelProviderText(ILabelProvider labelProvider, Object element) { String text = labelProvider.getText(element); if (text == null) { return "";//$NON-NLS-1$ } return text; } private Image getImage(ILabelProvider labelProvider, Object element) { return labelProvider.getImage(element); } /** * Adds the given element to this list viewer. If this viewer does not have * a sorter, the element is added at the end; otherwise the element is * inserted at the appropriate position. * <p> * This method should be called (by the content provider) when a single * element has been added to the model, in order to cause the viewer to * accurately reflect the model. This method only affects the viewer, not * the model. Note that there is another method for efficiently processing * the simultaneous addition of multiple elements. * </p> * * @param element * the element */ public void add(Object element) { add(new Object[] { element }); } /* * (non-Javadoc) Method declared on StructuredViewer. Since SWT.List doesn't * use items we always return the List itself. */ protected Widget doFindInputItem(Object element) { if (element != null && equals(element, getRoot())) { return getControl(); } return null; } /* * (non-Javadoc) Method declared on StructuredViewer. Since SWT.List doesn't * use items we always return the List itself. */ protected Widget doFindItem(Object element) { if (element != null) { int index = getElementIndex(element); if (index >= 0) { return items.get(index).getControl(); } // if (listMapContains(element)) { // return getControl(); // } } return null; } /* * (non-Javadoc) Method declared on StructuredViewer. */ protected void doUpdateItem(Widget data, Object element, boolean fullMap) { if (element != null) { int ix = getElementIndex(element); if (ix >= 0) { ILabelProvider labelProvider = (ILabelProvider) getLabelProvider(); String label = getLabelProviderText(labelProvider, element); Image image = getImage(labelProvider, element); listSetItem(ix, label, image); } } } /** * Returns the element with the given index from this list viewer. Returns * <code>null</code> if the index is out of range. * * @param index * the zero-based index * @return the element at the given index, or <code>null</code> if the index * is out of range */ public Object getElementAt(int index) { if (index >= 0 && index < listMap.size()) { return listMap.get(index); } return null; } /** * The list viewer implementation of this <code>Viewer</code> framework * method returns the label provider, which in the case of list viewers will * be an instance of <code>ILabelProvider</code>. */ public IBaseLabelProvider getLabelProvider() { return super.getLabelProvider(); } /* * (non-Javadoc) Method declared on Viewer. */ /* * (non-Javadoc) Method declared on StructuredViewer. */ protected List getSelectionFromWidget() { int[] ixs = listGetSelectionIndices(); List<Object> list = new ArrayList<Object>(ixs.length); for (int i = 0; i < ixs.length; i++) { Object e = getElementAt(ixs[i]); if (e != null) { list.add(e); } } return list; } /** * @param element * the element to insert * @return the index where the item should be inserted. */ protected int indexForElement(Object element) { ViewerComparator comparator = getComparator(); if (comparator == null) { return listGetItemCount(); } int count = listGetItemCount(); int min = 0, max = count - 1; while (min <= max) { int mid = (min + max) / 2; Object data = listMap.get(mid); int compare = comparator.compare(this, data, element); if (compare == 0) { // find first item > element while (compare == 0) { ++mid; if (mid >= count) { break; } data = listMap.get(mid); compare = comparator.compare(this, data, element); } return mid; } if (compare < 0) { min = mid + 1; } else { max = mid - 1; } } return min; } /* * (non-Javadoc) Method declared on Viewer. */ protected void inputChanged(Object input, Object oldInput) { listMap.clear(); Object[] children = getSortedChildren(getRoot()); int size = children.length; listRemoveAll(); //String[] labels = new String[size]; for (int i = 0; i < size; i++) { Object el = children[i]; String label = getLabelProviderText( (ILabelProvider) getLabelProvider(), el); Image image = getImage((ILabelProvider) getLabelProvider(), el); CheckItem item = listAdd(label, image, -1); listMap.add(el); mapElement(el, item.getControl()); // must map it, since findItem only looks in map, if enabled } //listSetItems(labels); } /* * (non-Javadoc) Method declared on StructuredViewer. */ protected void internalRefresh(Object element) { Control list = getControl(); if (element == null || equals(element, getRoot())) { // the parent if (listMap != null) { listMap.clear(); } unmapAllElements(); List selection = getSelectionFromWidget(); int topIndex = -1; if (selection == null || selection.isEmpty()) { topIndex = listGetTopIndex(); } list.setRedraw(false); listRemoveAll(); Object[] children = getSortedChildren(getRoot()); //String[] items = new String[children.length]; ILabelProvider labelProvider = (ILabelProvider) getLabelProvider(); for (int i = 0; i < children.length; i++) { Object el = children[i]; String label = getLabelProviderText(labelProvider, el); Image image = getImage(labelProvider, el); CheckItem item = listAdd(label, image, -1); listMap.add(el); mapElement(el, item.getControl()); // must map it, since findItem only looks in map, if enabled } //listSetItems(items); list.setRedraw(true); if (topIndex == -1) { setSelectionToWidget(selection, false); } else { listSetTopIndex(Math.min(topIndex, children.length)); } } else { doUpdateItem(list, element, true); } } /** * Returns the index of the item currently at the top of the viewable area. * <p> * Default implementation returns -1. * </p> * * @return index, -1 for none * @since 3.3 */ protected int listGetTopIndex() { return -1; } /** * Sets the index of the item to be at the top of the viewable area. * <p> * Default implementation does nothing. * </p> * * @param index * the given index. -1 for none. index will always refer to a * valid index. * @since 3.3 */ protected void listSetTopIndex(int index) { } /** * Removes the given elements from this list viewer. * * @param elements * the elements to remove */ private void internalRemove(final Object[] elements) { Object input = getInput(); for (int i = 0; i < elements.length; ++i) { if (equals(elements[i], input)) { setInput(null); return; } int ix = getElementIndex(elements[i]); if (ix >= 0) { CheckItem item = listRemove(ix); listMap.remove(ix); unmapElement(elements[i], item.getControl()); } } } /** * Removes the given elements from this list viewer. The selection is * updated if required. * <p> * This method should be called (by the content provider) when elements have * been removed from the model, in order to cause the viewer to accurately * reflect the model. This method only affects the viewer, not the model. * </p> * * @param elements * the elements to remove */ public void remove(final Object[] elements) { assertElementsNotNull(elements); if (elements.length == 0) { return; } preservingSelection(new Runnable() { public void run() { internalRemove(elements); } }); } /** * Removes the given element from this list viewer. The selection is updated * if necessary. * <p> * This method should be called (by the content provider) when a single * element has been removed from the model, in order to cause the viewer to * accurately reflect the model. This method only affects the viewer, not * the model. Note that there is another method for efficiently processing * the simultaneous removal of multiple elements. * </p> * * @param element * the element */ public void remove(Object element) { remove(new Object[] { element }); } /** * The list viewer implementation of this <code>Viewer</code> framework * method ensures that the given label provider is an instance of * <code>ILabelProvider</code>. <b>The optional interfaces * {@link IColorProvider} and {@link IFontProvider} have no effect for this * type of viewer</b> */ public void setLabelProvider(IBaseLabelProvider labelProvider) { Assert.isTrue(labelProvider instanceof ILabelProvider); super.setLabelProvider(labelProvider); } /* * (non-Javadoc) Method declared on StructuredViewer. */ protected void setSelectionToWidget(List in, boolean reveal) { if (in == null || in.size() == 0) { // clear selection listDeselectAll(); } else { int n = in.size(); int[] ixs = new int[n]; int count = 0; for (int i = 0; i < n; ++i) { Object el = in.get(i); int ix = getElementIndex(el); if (ix >= 0) { ixs[count++] = ix; } } if (count < n) { System.arraycopy(ixs, 0, ixs = new int[count], 0, count); } listSetSelection(ixs); if (reveal) { listShowSelection(); } } } /** * Returns the index of the given element in listMap, or -1 if the element * cannot be found. As of 3.3, uses the element comparer if available. * * @param element * @return the index */ protected int getElementIndex(Object element) { IElementComparer comparer = getComparer(); if (comparer == null) { return listMap.indexOf(element); } int size = listMap.size(); for (int i = 0; i < size; i++) { if (comparer.equals(element, listMap.get(i))) return i; } return -1; } // /** // * @param element // * @return true if listMap contains the given element // * // * @since 3.3 // */ // private boolean listMapContains(Object element) { // return getElementIndex(element) != -1; // } }