org.eclipse.ui.internal.views.markers.ViewerColumnsDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.internal.views.markers.ViewerColumnsDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 ******************************************************************************/

package org.eclipse.ui.internal.views.markers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
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.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.views.markers.internal.MarkerMessages;

/**
 * This was introduced as a fix to Bug 231081 and related, as an effort to
 * combine the columns and preference dialogs into one. It should be noted that
 * the class can be re-used or turned into a tool for column viewers in general,
 * but with some modifications. See example attached at the end of this class
 * 
 * @since 3.7
 * 
 * @author Hitesh Soliwal
 * 
 * @noextend This class is not intended to be subclassed by clients.
 * 
 */
abstract class ViewerColumnsDialog extends ViewerSettingsAndStatusDialog {

    /** The list contains columns that are currently visible in viewer */
    private List visible;

    /** The list contains columns that are note shown in viewer */
    private List nonVisible;

    private TableViewer visibleViewer, nonVisibleViewer;

    private Button upButton, downButton;

    private Button toVisibleBtt, toNonVisibleBtt;

    private Label widthLabel;
    private Text widthText;

    private Point tableLabelSize;

    /**
     * Create a new instance of the receiver.
     * 
     * @param parentShell
     */
    ViewerColumnsDialog(Shell parentShell) {
        super(parentShell);
    }

    /**
     * Initialize visible /non-visible columns.
     * 
     * @param columnObjs
     */
    void setColumnsObjs(Object[] columnObjs) {
        IColumnInfoProvider columnInfo = doGetColumnInfoProvider();
        IColumnUpdater updater = doGetColumnUpdater();
        List visible = getVisible();
        List nonVisible = getNonVisible();
        visible.clear();
        nonVisible.clear();
        Object data = null;
        for (int i = 0; i < columnObjs.length; i++) {
            data = columnObjs[i];
            if (columnInfo.isColumnVisible(data)) {
                updater.setColumnVisible(data, true);
                updater.setColumnIndex(data, visible.size());
                visible.add(data);
            } else {
                updater.setColumnVisible(data, false);
                updater.setColumnIndex(data, nonVisible.size());
                nonVisible.add(data);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.internal.views.markers.ViewerSettingsAndStatusDialog#
     * createDialogContentArea(org.eclipse.swt.widgets.Composite)
     */
    protected Control createDialogContentArea(Composite dialogArea) {
        Composite composite = new Composite(dialogArea, SWT.NONE);
        GridLayout gridLayout = new GridLayout(4, false);
        gridLayout.marginHeight = 0;
        composite.setLayout(gridLayout);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));

        createInvisibleTable(composite);
        createMoveButtons(composite);
        createVisibleTable(composite);
        createUpDownBtt(composite);
        createWidthArea(composite);
        Object element = visibleViewer.getElementAt(0);
        if (element != null)
            visibleViewer.setSelection(new StructuredSelection(element));
        visibleViewer.getTable().setFocus();
        return composite;
    }

    /**
     * The Up and Down button to change column ordering.
     * 
     * @param parent
     */
    Control createUpDownBtt(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout compositeLayout = new GridLayout();
        compositeLayout.marginHeight = 0;
        compositeLayout.marginWidth = 0;
        composite.setLayout(compositeLayout);
        composite.setLayoutData(new GridData(SWT.NONE, SWT.FILL, false, true));

        Composite bttArea = new Composite(composite, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        bttArea.setLayout(layout);
        bttArea.setLayoutData(new GridData(SWT.NONE, SWT.CENTER, false, true));
        upButton = new Button(bttArea, SWT.PUSH);
        upButton.setText(JFaceResources.getString("ConfigureColumnsDialog_up")); //$NON-NLS-1$
        upButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                handleUpButton(event);
            }
        });
        setButtonLayoutData(upButton);
        ((GridData) upButton.getLayoutData()).verticalIndent = tableLabelSize.y;
        upButton.setEnabled(false);

        downButton = new Button(bttArea, SWT.PUSH);
        downButton.setText(JFaceResources.getString("ConfigureColumnsDialog_down")); //$NON-NLS-1$
        downButton.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                handleDownButton(event);
            }
        });
        setButtonLayoutData(downButton);
        downButton.setEnabled(false);
        return bttArea;
    }

    /**
     * Create the controls responsible to display/edit column widths.
     * 
     * @param parent
     * @return {@link Control}
     */
    Control createWidthArea(Composite parent) {

        Label dummy = new Label(parent, SWT.NONE);
        dummy.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false, 2, 1));

        Composite widthComposite = new Composite(parent, SWT.NONE);
        GridLayout gridLayout = new GridLayout(2, false);
        gridLayout.marginHeight = 0;
        widthComposite.setLayout(gridLayout);
        widthComposite.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false, 2, 1));

        widthLabel = new Label(widthComposite, SWT.NONE);
        widthLabel.setText(MarkerMessages.MarkerPreferences_WidthOfShownColumn);
        GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
        widthLabel.setLayoutData(gridData);

        widthText = new Text(widthComposite, SWT.BORDER);
        widthText.addVerifyListener(new VerifyListener() {

            public void verifyText(VerifyEvent e) {
                if (e.character != 0 && e.keyCode != SWT.BS && e.keyCode != SWT.DEL
                        && !Character.isDigit(e.character)) {
                    e.doit = false;
                }
            }
        });

        gridData = new GridData();
        gridData.widthHint = convertWidthInCharsToPixels(5);
        widthText.setLayoutData(gridData);
        widthText.addModifyListener(new ModifyListener() {

            public void modifyText(ModifyEvent e) {
                updateWidth();
            }
        });
        setWidthEnabled(false);
        return widthText;
    }

    private void setWidthEnabled(boolean enabled) {
        widthLabel.setEnabled(enabled);
        widthText.setEnabled(enabled);
    }

    /**
     * Creates the table that lists out visible columns in the viewer
     * 
     * @param parent
     * @return {@link Control}
     */
    Control createVisibleTable(Composite parent) {

        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout gridLayout = new GridLayout(1, false);
        gridLayout.marginHeight = 0;
        composite.setLayout(gridLayout);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));

        Label label = new Label(composite, SWT.NONE);
        label.setText(MarkerMessages.MarkerPreferences_VisibleColumnsTitle);

        final Table table = new Table(composite, SWT.BORDER | SWT.MULTI);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        data.widthHint = convertWidthInCharsToPixels(20);
        data.heightHint = table.getItemHeight() * 15;
        table.setLayoutData(data);

        final TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(MarkerMessages.MarkerPreferences_VisibleColumnsTitle);
        Listener columnResize = new Listener() {
            public void handleEvent(Event event) {
                column.setWidth(table.getClientArea().width);
            }
        };
        table.addListener(SWT.Resize, columnResize);

        visibleViewer = new TableViewer(table);
        visibleViewer.setLabelProvider(doGetLabelProvider());
        visibleViewer.setContentProvider(ArrayContentProvider.getInstance());
        visibleViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                handleVisibleSelection(event.getSelection());
            }
        });
        table.addListener(SWT.MouseDoubleClick, new Listener() {
            public void handleEvent(Event event) {
                handleToNonVisibleButton(event);
            }
        });
        visibleViewer.setInput(getVisible());
        return table;
    }

    /**
     * Creates the table that lists out non-visible columns in the viewer
     * 
     * @param parent
     * @return {@link Control}
     */
    Control createInvisibleTable(Composite parent) {

        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout gridLayout = new GridLayout(1, false);
        gridLayout.marginHeight = 0;
        composite.setLayout(gridLayout);

        composite.setLayoutData(new GridData(GridData.FILL_BOTH));

        Label label = new Label(composite, SWT.NONE);
        label.setText(MarkerMessages.MarkerPreferences_HiddenColumnsTitle);
        applyDialogFont(label);
        tableLabelSize = label.computeSize(SWT.DEFAULT, SWT.DEFAULT);

        final Table table = new Table(composite, SWT.BORDER | SWT.MULTI);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        data.widthHint = convertWidthInCharsToPixels(20);
        data.heightHint = table.getItemHeight() * 15;
        table.setLayoutData(data);

        final TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText(MarkerMessages.MarkerPreferences_HiddenColumnsTitle);
        Listener columnResize = new Listener() {
            public void handleEvent(Event event) {
                column.setWidth(table.getClientArea().width);
            }
        };
        table.addListener(SWT.Resize, columnResize);

        nonVisibleViewer = new TableViewer(table);
        nonVisibleViewer.setLabelProvider(doGetLabelProvider());
        nonVisibleViewer.setContentProvider(ArrayContentProvider.getInstance());
        nonVisibleViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                handleNonVisibleSelection(event.getSelection());
            }
        });
        table.addListener(SWT.MouseDoubleClick, new Listener() {
            public void handleEvent(Event event) {
                handleToVisibleButton(event);
            }
        });
        nonVisibleViewer.setInput(getNonVisible());
        return table;
    }

    /**
     * Creates buttons for moving columns from non-visible to visible and
     * vice-versa
     * 
     * @param parent
     * @return {@link Control}
     */
    Control createMoveButtons(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        GridLayout compositeLayout = new GridLayout();
        compositeLayout.marginHeight = 0;
        compositeLayout.marginWidth = 0;
        composite.setLayout(compositeLayout);
        composite.setLayoutData(new GridData(SWT.NONE, SWT.FILL, false, true));

        Composite bttArea = new Composite(composite, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        bttArea.setLayout(layout);
        bttArea.setLayoutData(new GridData(SWT.NONE, SWT.CENTER, false, true));

        toVisibleBtt = new Button(bttArea, SWT.PUSH);
        toVisibleBtt.setText(MarkerMessages.MarkerPreferences_MoveRight);
        setButtonLayoutData(toVisibleBtt);
        ((GridData) toVisibleBtt.getLayoutData()).verticalIndent = tableLabelSize.y;
        toVisibleBtt.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                handleToVisibleButton(event);
            }
        });
        toVisibleBtt.setEnabled(false);

        toNonVisibleBtt = new Button(bttArea, SWT.PUSH);
        toNonVisibleBtt.setText(MarkerMessages.MarkerPreferences_MoveLeft);
        setButtonLayoutData(toNonVisibleBtt);

        toNonVisibleBtt.addListener(SWT.Selection, new Listener() {
            public void handleEvent(Event event) {
                handleToNonVisibleButton(event);
            }
        });
        toNonVisibleBtt.setEnabled(false);

        return bttArea;
    }

    /**
     * Handles a selection change in the viewer that lists out the non-visible
     * columns
     * 
     * @param selection
     */
    void handleNonVisibleSelection(ISelection selection) {
        Object[] nvKeys = ((IStructuredSelection) selection).toArray();
        toVisibleBtt.setEnabled(nvKeys.length > 0);
        if (visibleViewer.getControl().isFocusControl() && getVisible().size() <= 1) {
            handleStatusUdpate(IStatus.INFO, MarkerMessages.MarkerPreferences_AtLeastOneVisibleColumn);
        } else {
            handleStatusUdpate(IStatus.INFO, getDefaultMessage());
        }
    }

    /**
     * Handles a selection change in the viewer that lists out the visible
     * columns. Takes care of various enablements.
     * 
     * @param selection
     */
    void handleVisibleSelection(ISelection selection) {
        List selVCols = ((IStructuredSelection) selection).toList();
        List allVCols = getVisible();
        toNonVisibleBtt.setEnabled(selVCols.size() > 0 && allVCols.size() > selVCols.size());

        IColumnInfoProvider infoProvider = doGetColumnInfoProvider();
        boolean moveDown = !selVCols.isEmpty(), moveUp = !selVCols.isEmpty();
        Iterator iterator = selVCols.iterator();
        while (iterator.hasNext()) {
            Object columnObj = iterator.next();
            if (!infoProvider.isColumnMovable(columnObj)) {
                moveUp = false;
                moveDown = false;
                break;
            }
            int i = allVCols.indexOf(columnObj);
            if (i == 0) {
                moveUp = false;
                if (!moveDown) {
                    break;
                }
            }
            if (i == (allVCols.size() - 1)) {
                moveDown = false;
                if (!moveUp) {
                    break;
                }
            }
        }
        upButton.setEnabled(moveUp);
        downButton.setEnabled(moveDown);

        boolean edit = selVCols.size() == 1 ? infoProvider.isColumnResizable(selVCols.get(0)) : false;
        setWidthEnabled(edit);
        if (edit) {
            int width = infoProvider.getColumnWidth(selVCols.get(0));
            widthText.setText(Integer.toString(width));
        } else {
            widthText.setText(""); //$NON-NLS-1$
        }
    }

    /**
     * Applies to visible columns, and handles the changes in the order of
     * columns
     * 
     * @param e
     *            event from the button click
     */
    void handleDownButton(Event e) {
        IStructuredSelection selection = (IStructuredSelection) visibleViewer.getSelection();
        Object[] selVCols = selection.toArray();
        List allVCols = getVisible();
        IColumnUpdater updater = doGetColumnUpdater();
        for (int i = selVCols.length - 1; i >= 0; i--) {
            Object colObj = selVCols[i];
            int index = allVCols.indexOf(colObj);
            updater.setColumnIndex(colObj, index + 1);
            allVCols.remove(index);
            allVCols.add(index + 1, colObj);
        }
        visibleViewer.refresh();
        handleVisibleSelection(selection);
    }

    /**
     * Applies to visible columns, and handles the changes in the order of
     * columns
     * 
     * @param e
     *            event from the button click
     */
    void handleUpButton(Event e) {
        IStructuredSelection selection = (IStructuredSelection) visibleViewer.getSelection();
        Object[] selVCols = selection.toArray();
        List allVCols = getVisible();
        IColumnUpdater updater = doGetColumnUpdater();
        for (int i = 0; i < selVCols.length; i++) {
            Object colObj = selVCols[i];
            int index = allVCols.indexOf(colObj);
            updater.setColumnIndex(colObj, index - 1);
            allVCols.remove(index);
            allVCols.add(index - 1, colObj);
        }
        visibleViewer.refresh();
        handleVisibleSelection(selection);
    }

    /**
     * Moves selected columns from non-visible to visible state
     * 
     * @param e
     *            event from the button click
     */
    void handleToVisibleButton(Event e) {
        IStructuredSelection selection = (IStructuredSelection) nonVisibleViewer.getSelection();
        List selVCols = selection.toList();
        List nonVisible = getNonVisible();
        nonVisible.removeAll(selVCols);

        List list = getVisible();
        list.addAll(selVCols);

        updateVisibility(selVCols, true);
        updateIndices(getVisible());
        updateIndices(getNonVisible());

        visibleViewer.refresh();
        visibleViewer.setSelection(selection);
        nonVisibleViewer.refresh();
        handleVisibleSelection(selection);
        handleNonVisibleSelection(nonVisibleViewer.getSelection());

    }

    /**
     * Moves selected columns from visible to non-visible state
     * 
     * @param e
     *            event from the button click
     */
    protected void handleToNonVisibleButton(Event e) {
        if (visibleViewer.getControl().isFocusControl() && getVisible().size() <= 1) {
            handleStatusUdpate(IStatus.INFO, MarkerMessages.MarkerPreferences_AtLeastOneVisibleColumn);
            return;
        }
        IStructuredSelection selection = (IStructuredSelection) visibleViewer.getSelection();
        List selVCols = selection.toList();
        getVisible().removeAll(selVCols);
        getNonVisible().addAll(selVCols);

        updateVisibility(selVCols, false);
        updateIndices(getVisible());
        updateIndices(getNonVisible());

        nonVisibleViewer.refresh();
        nonVisibleViewer.setSelection(selection);
        visibleViewer.refresh();
        handleVisibleSelection(visibleViewer.getSelection());
        handleNonVisibleSelection(nonVisibleViewer.getSelection());
    }

    void updateIndices(List list) {
        ListIterator iterator = list.listIterator();
        IColumnUpdater updater = doGetColumnUpdater();
        while (iterator.hasNext()) {
            updater.setColumnIndex(iterator.next(), iterator.previousIndex());
        }
    }

    void updateVisibility(List list, boolean visibility) {
        IColumnUpdater updater = doGetColumnUpdater();
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            updater.setColumnVisible(iterator.next(), visibility);
        }
    }

    protected void performDefaults() {
        refreshViewers();
        super.performDefaults();
    }

    /**
     * Updates the UI based on values of the variable
     */
    void refreshViewers() {
        if (nonVisibleViewer != null) {
            nonVisibleViewer.refresh();
        }
        if (visibleViewer != null) {
            visibleViewer.refresh();
        }
    }

    /**
     * @return List of visible columns
     */
    public List getVisible() {
        if (visible == null) {
            visible = new ArrayList();
        }
        return visible;
    }

    /**
     * @return List of non-visible columns
     */
    public List getNonVisible() {
        if (nonVisible == null) {
            nonVisible = new ArrayList();
        }
        return nonVisible;
    }

    /**
     * An adapter class to {@link ITableLabelProvider}
     * 
     */
    class TableLabelProvider extends LabelProvider implements ITableLabelProvider {
        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            return getText(element);
        }
    }

    /**
     * Internal helper to @see {@link ViewerColumnsDialog#getLabelProvider()}
     */
    ITableLabelProvider doGetLabelProvider() {
        return getLabelProvider();
    }

    /**
     * The tables-columns need to be displayed appropriately. The supplied
     * column objects are adapted to text and image as dictacted by this
     * {@link ITableLabelProvider}
     */
    protected abstract ITableLabelProvider getLabelProvider();

    /**
     * Internal helper to @see
     * {@link ViewerColumnsDialog#getColumnInfoProvider()}
     */
    IColumnInfoProvider doGetColumnInfoProvider() {
        return getColumnInfoProvider();
    }

    /**
     * To configure the columns we need further information. The supplied column
     * objects are adapted for its properties via {@link IColumnInfoProvider}
     */
    protected abstract IColumnInfoProvider getColumnInfoProvider();

    /**
     * Internal helper to @see {@link ViewerColumnsDialog#getColumnUpdater()}
     */
    IColumnUpdater doGetColumnUpdater() {
        return getColumnUpdater();
    }

    /**
     * To configure properties/order of the columns is achieved via
     * {@link IColumnUpdater}
     */
    protected abstract IColumnUpdater getColumnUpdater();

    /**
     * 
     */
    private void updateWidth() {
        try {
            int width = Integer.parseInt(widthText.getText());
            Object data = ((IStructuredSelection) visibleViewer.getSelection()).getFirstElement();
            if (data != null) {
                IColumnUpdater updater = getColumnUpdater();
                updater.setColumnWidth(data, width);
            }
        } catch (NumberFormatException ex) {
            // ignore
        }
    }

    /**
     * Update various aspects of a columns from a viewer such
     * {@link TableViewer}
     */
    public interface IColumnInfoProvider {

        /**
         * Get corresponding index for the column
         * 
         * @param columnObj
         */
        public int getColumnIndex(Object columnObj);

        /**
         * Get the width of the column
         * 
         * @param columnObj
         */
        public int getColumnWidth(Object columnObj);

        /**
         * Returns true if the column represented by parameters is showing in
         * the viewer
         * 
         * @param columnObj
         */
        public boolean isColumnVisible(Object columnObj);

        /**
         * Returns true if the column represented by parameters is configured as
         * movable
         * 
         * @param columnObj
         */
        public boolean isColumnMovable(Object columnObj);

        /**
         * Returns true if the column represented by parameters is configured as
         * resizable
         * 
         * @param columnObj
         */
        public boolean isColumnResizable(Object columnObj);

    }

    /**
     * Update various aspects of a columns from a viewer such
     * {@link TableViewer}
     */
    public interface IColumnUpdater {

        /**
         * Set the column represented by parameters as visible
         * 
         * @param columnObj
         * @param visible
         */
        public void setColumnVisible(Object columnObj, boolean visible);

        /**
         * Dummy method - more a result of symmetry
         * 
         * @param columnObj
         * @param movable
         */
        public void setColumnMovable(Object columnObj, boolean movable);

        /**
         * Call back to notify change in the index of the column represented by
         * columnObj
         * 
         * @param columnObj
         * @param index
         */
        public void setColumnIndex(Object columnObj, int index);

        /**
         * Dummy method - more a result of symmetry
         * 
         * @param columnObj
         * @param resizable
         */
        public void setColumnResizable(Object columnObj, boolean resizable);

        /**
         * Call back to notify change in the width of the column represented by
         * columnObj
         * 
         * @param columnObj
         * @param newWidth
         */
        public void setColumnWidth(Object columnObj, int newWidth);

    }

    // //////////////////////////////////////////////////////////////////////////////////
    /**
     * Ignore the class below as it is simply meant to test the above. I intend
     * to retain this for a while.
     */
    static class TestData {

        final Object key;

        final int keyIndex;

        int newIndex, width;

        boolean visibility, movable, resizable;

        TestData(Object key, int currIndex) {
            this.key = key;
            this.keyIndex = currIndex;
        }

        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((key == null) ? 0 : key.hashCode());
            result = prime * result + keyIndex;
            return result;
        }

        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof TestData)) {
                return false;
            }
            TestData other = (TestData) obj;
            if (key == null) {
                if (other.key != null) {
                    return false;
                }
            } else if (!key.equals(other.key)) {
                return false;
            }
            if (keyIndex != other.keyIndex) {
                return false;
            }
            return true;
        }

        public String toString() {
            return key.toString();
        }

        private static ViewerColumnsDialog getColumnsDialog(Shell shell, final TestData[] colums) {
            ViewerColumnsDialog dialog = new ViewerColumnsDialog(shell) {

                protected IColumnInfoProvider getColumnInfoProvider() {
                    return getInfoProvider(colums);
                }

                protected ITableLabelProvider getLabelProvider() {
                    return new TableLabelProvider();
                }

                protected IColumnUpdater getColumnUpdater() {
                    return getUpdater(colums);
                }
            };
            dialog.setColumnsObjs(colums);
            return dialog;
        }

        private static IColumnUpdater getUpdater(final TestData[] data) {
            return new IColumnUpdater() {

                public void setColumnWidth(Object columnObj, int newWidth) {
                    ((TestData) columnObj).width = newWidth;
                }

                public void setColumnVisible(Object columnObj, boolean visible) {
                    ((TestData) columnObj).visibility = visible;
                }

                public void setColumnResizable(Object columnObj, boolean resizable) {

                }

                public void setColumnMovable(Object columnObj, boolean movable) {
                    ((TestData) columnObj).movable = movable;

                }

                public void setColumnIndex(Object columnObj, int index) {
                    ((TestData) columnObj).newIndex = index;
                }
            };
        }

        private static IColumnInfoProvider getInfoProvider(final TestData[] colData) {
            return new IColumnInfoProvider() {

                public boolean isColumnVisible(Object columnObj) {
                    return ((TestData) columnObj).visibility;
                }

                public boolean isColumnResizable(Object columnObj) {
                    return ((TestData) columnObj).resizable;
                }

                public boolean isColumnMovable(Object columnObj) {
                    return ((TestData) columnObj).movable;
                }

                public int getColumnWidth(Object columnObj) {
                    return ((TestData) columnObj).width;
                }

                public int getColumnIndex(Object columnObj) {
                    return ((TestData) columnObj).newIndex;
                }
            };
        }

        private static TestData[] genData(int count) {
            String[] cols = new String[count];
            for (int i = 0; i < cols.length; i++) {
                cols[i] = new String("Column-" + (i + 1)); //$NON-NLS-1$
            }
            Random random = new Random();

            boolean[] visibility = new boolean[cols.length];
            Arrays.fill(visibility, true);
            int ranInt = random.nextInt() % cols.length;
            for (int i = 0; i < ranInt; i++) {
                visibility[random.nextInt(ranInt)] = false;
            }

            boolean[] resizable = new boolean[cols.length];
            Arrays.fill(resizable, true);
            ranInt = random.nextInt() % cols.length;
            for (int i = 0; i < ranInt; i++) {
                resizable[random.nextInt(ranInt)] = false;
            }

            boolean[] movable = new boolean[cols.length];
            Arrays.fill(movable, true);
            ranInt = random.nextInt() % cols.length;
            for (int i = 0; i < ranInt; i++) {
                movable[random.nextInt(ranInt)] = false;
            }

            int[] widths = new int[cols.length];
            Arrays.fill(widths, 100);
            return TestData.generateColumnsData(cols, visibility, resizable, movable, widths);
        }

        public static TestData[] generateColumnsData(Object[] keys, boolean[] visibility, boolean[] resizable,
                boolean[] movable, int[] widths) {
            TestData[] colData = new TestData[keys.length];
            int m = 0, n = 0;
            for (int i = 0; i < colData.length; i++) {
                TestData data = new TestData(keys[i], i);
                data.visibility = visibility[i];
                data.resizable = resizable[i];
                data.movable = movable[i];
                data.width = widths[i];
                if (data.visibility) {
                    data.newIndex = m++;
                } else {
                    data.newIndex = n++;
                }
                colData[i] = data;
            }
            return colData;
        }

        /**
         * Demo
         * 
         * @param args
         */
        public static void main(String[] args) {
            Display display = new Display();
            final Shell shell = new Shell(display);
            shell.setLayout(new FillLayout());
            ViewerColumnsDialog dialog = getColumnsDialog(shell, genData(100));
            dialog.open();
            shell.dispose();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
            display.dispose();

        }

    }

}