org.xmind.ui.viewers.CheckListViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.xmind.ui.viewers.CheckListViewer.java

Source

/* ******************************************************************************
 * 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;
    //    }

}