org.csstudio.swt.widgets.natives.SpreadSheetTable.java Source code

Java tutorial

Introduction

Here is the source code for org.csstudio.swt.widgets.natives.SpreadSheetTable.java

Source

/*******************************************************************************
 * Copyright (c) 2012 Oak Ridge National Laboratory.
 * 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
 ******************************************************************************/

package org.csstudio.swt.widgets.natives;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.csstudio.ui.util.CustomMediaFactory;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

/**A table allow displaying and editing 2D text array as in spreadsheet.
 * The internal data operated by this table is a nested string list.
 * @author Xihui Chen
 *
 */
public class SpreadSheetTable extends Composite {

    public enum CellEditorType {
        TEXT, CHECKBOX, DROPDOWN, CUSTOMIZED
    }

    private static final String TEXT_EDITING_SUPPORT_KEY = "text_editing_support"; //$NON-NLS-1$

    private static final String[] DEFAULT_BOOLEAN_TEXTS = new String[] { "No", "Yes" }; //$NON-NLS-1$ //$NON-NLS-2$

    /**
     * Listener on table cell editing events.
     *
     */
    public interface ITableCellEditingListener {
        /**Called whenever the value in a cell has been edited.
         * @param row index of the row
         * @param col index of the column
         * @param oldValue old value in the cell
         * @param newValue new value in the cell.
         */
        public void cellValueChanged(int row, int col, String oldValue, String newValue);
    }

    /**
     * Listener on table contents modified events.
     *
     */
    public interface ITableModifiedListener {

        /**Called whenever the table content is modified.
         * @param content of the table.
         */
        public void modified(String[][] content);
    }

    /**
     *Listener on table selection changed events.
     *
     */
    public interface ITableSelectionChangedListener {

        /**Called when selection on the table changed.
         * @param selection a 2D string array which represents the selected rows.
         */
        public void selectionChanged(String[][] selection);
    }

    private class TextEditingSupport extends EditingSupport {

        private CellEditor cellEditor;
        private Object cellEditorData;
        private int cellEditorStyle = SWT.NONE;
        private String oldValue;
        private ViewerCell viewerCell;
        private boolean columnEditable = true;
        private CellEditorType cellEditorType = CellEditorType.TEXT;

        public TextEditingSupport(ColumnViewer viewer) {
            super(viewer);
        }

        @Override
        protected boolean canEdit(Object element) {
            if (!editable)
                return false;
            return columnEditable;
        }

        private int findColumnIndex() {
            return viewerCell.getColumnIndex();
        }

        private int findRowIndex() {
            Table table = tableViewer.getTable();
            TableItem cellItem = (TableItem) viewerCell.getItem();
            return table.indexOf(cellItem);
        }

        @Override
        protected CellEditor getCellEditor(Object element) {
            if (cellEditor == null) {
                switch (cellEditorType) {
                case CHECKBOX:
                    if (cellEditorData == null)
                        cellEditorData = DEFAULT_BOOLEAN_TEXTS;
                    cellEditor = new CheckboxCellEditor(tableViewer.getTable()) {
                        @Override
                        protected Object doGetValue() {
                            return ((Boolean) super.doGetValue()) ? ((String[]) cellEditorData)[1]
                                    : ((String[]) cellEditorData)[0];
                        };

                        @Override
                        protected void doSetValue(Object value) {
                            if (value.toString().toLowerCase().equals(((String[]) cellEditorData)[1].toLowerCase()))
                                super.doSetValue(true);
                            else
                                super.doSetValue(false);
                        }
                    };
                    break;
                case DROPDOWN:
                    cellEditor = new ComboBoxCellEditor(tableViewer.getTable(), (String[]) cellEditorData,
                            cellEditorStyle) {
                        @Override
                        protected Object doGetValue() {
                            return ((CCombo) getControl()).getText();
                        }

                        @Override
                        protected void doSetValue(Object value) {
                            ((CCombo) getControl()).setText(value.toString());
                        }
                    };
                    break;
                default:
                    cellEditor = new TextCellEditor(tableViewer.getTable());
                    break;
                }
            }
            return cellEditor;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected Object getValue(Object element) {
            oldValue = ((List<String>) element).get(findColumnIndex());
            return oldValue;
        }

        @Override
        protected void initializeCellEditorValue(CellEditor cellEditor, ViewerCell cell) {
            this.viewerCell = cell;
            super.initializeCellEditorValue(cellEditor, cell);

        }

        @SuppressWarnings("unchecked")
        @Override
        protected void setValue(Object element, Object value) {
            int col = findColumnIndex();
            String oldValue = ((List<String>) element).get(col);
            ((List<String>) element).set(col, value.toString());
            if (!value.equals(oldValue)) {
                if (tableEditingListeners != null && !tableEditingListeners.isEmpty()) {
                    int row = findRowIndex();
                    for (Object listener : tableEditingListeners.getListeners()) {
                        ((ITableCellEditingListener) listener).cellValueChanged(row, col, oldValue,
                                value.toString());
                    }
                }
                fireTableModified();
            }
            TableItem tableItem = (TableItem) viewerCell.getItem();
            tableItem.setText(col, value.toString());
            Image image = ((TextTableLableProvider) tableViewer.getLabelProvider()).getColumnImage(element, col);
            tableItem.setImage(col, image);
        }

        public CellEditorType getCellEditorType() {
            return cellEditorType;
        }

        public void setCellEditorType(CellEditorType cellEditorType) {
            this.cellEditorType = cellEditorType;
            cellEditor = null;
        }

        public boolean isColumnEditable() {
            return columnEditable;
        }

        public void setColumnEditable(boolean columnEditable) {
            this.columnEditable = columnEditable;
        }

        public void setCellEditor(CellEditor cellEditor) {
            cellEditorType = CellEditorType.CUSTOMIZED;
            this.cellEditor = cellEditor;
        }

        public void setCellEditorData(Object data) {
            this.cellEditorData = data;
        }

        public void setCellEditorStyle(int cellEditorStyle) {
            this.cellEditorStyle = cellEditorStyle;
        }

    }

    private class TextTableLableProvider extends BaseLabelProvider implements ITableLabelProvider {

        @Override
        public Image getColumnImage(Object element, int columnIndex) {
            CellEditorType cellEditorType = ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex)
                    .getData(TEXT_EDITING_SUPPORT_KEY))).getCellEditorType();
            switch (cellEditorType) {
            case CHECKBOX:
                if (!isColumnEditable(columnIndex))
                    return null;
                String[] booleanTexts = (String[]) ((TextEditingSupport) (tableViewer.getTable()
                        .getColumn(columnIndex).getData(TEXT_EDITING_SUPPORT_KEY))).cellEditorData;
                if (booleanTexts == null)
                    booleanTexts = DEFAULT_BOOLEAN_TEXTS;
                if (getColumnText(element, columnIndex).trim().equalsIgnoreCase(booleanTexts[1]))
                    return getOnImage();
                else
                    return getOffImage();
            default:
                break;
            }
            return null;
        }

        @Override
        @SuppressWarnings("unchecked")
        public String getColumnText(Object element, int columnIndex) {
            return ((List<String>) element).get(columnIndex);
        }
    }

    private static final int DEFAULT_COLUMN_WIDTH = 60;

    private static Image onImage, offImage;

    private TableViewer tableViewer;

    private boolean editable = true;

    private List<List<String>> input;

    private ListenerList tableEditingListeners;
    private ListenerList selectionChangedListeners;
    private ListenerList tableModifiedListeners;

    /**Create a spreadsheet table.
     * @param parent parent composite.
     * @param style the style of widget to construct
     */
    public SpreadSheetTable(Composite parent) {
        super(parent, SWT.NONE);
        setLayout(new FillLayout());
        tableViewer = new TableViewer(this,
                SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
        tableViewer.getTable().setLinesVisible(true);
        tableViewer.getTable().setHeaderVisible(true);
        tableViewer.setContentProvider(new ArrayContentProvider());
        setInput(new ArrayList<List<String>>());
    }

    /**Add a table cell editing listener. Called whenever the value in a cell has been edited.
     * @param listener the listener
     */
    public void addCellEditingListener(ITableCellEditingListener listener) {
        if (tableEditingListeners == null)
            tableEditingListeners = new ListenerList();
        tableEditingListeners.add(listener);
    }

    /**Add a table modified listener. Called whenever content of the table has been modified from the table.
     * @param listener the listener
     */
    public void addModifiedListener(ITableModifiedListener listener) {
        if (tableModifiedListeners == null)
            tableModifiedListeners = new ListenerList();
        tableModifiedListeners.add(listener);
    }

    /**Add a selection changed listener. Call whenever selection of the table changes.
     * @param listener the listener
     */
    public void addSelectionChangedListener(ITableSelectionChangedListener listener) {
        if (selectionChangedListeners == null) {
            selectionChangedListeners = new ListenerList();
            tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {

                @Override
                public void selectionChanged(SelectionChangedEvent event) {
                    String[][] selection = getSelection();
                    for (Object listener : selectionChangedListeners.getListeners()) {
                        ((ITableSelectionChangedListener) listener).selectionChanged(selection);
                    }
                }
            });
        }
        selectionChangedListeners.add(listener);
    }

    /**
     * Auto size all columns.
     */
    public void autoSizeColumns() {
        for (TableColumn column : tableViewer.getTable().getColumns()) {
            column.pack();
        }
    }

    /**
     * @param col
     */
    private void checkColumnIndex(int col) {
        if (col >= getColumnCount() || col < 0) {
            throw new IllegalArgumentException(
                    NLS.bind("column index {0} out of range [0, {1}].", col, getColumnCount()));
        }
    }

    /**
     * @param row
     */
    private void checkRowIndex(int row) {
        if (row < 0 || row >= input.size()) {
            throw new IllegalArgumentException(NLS.bind("row index {0} out of range [0, {1}].", row, input.size()));
        }
    }

    /**
     * Delete a column.
     *
     * @param index
     *            index of the column.
     */
    public void deleteColumn(int index) {
        if (!isColumnEditable(index))
            throw new IllegalStateException(NLS.bind("column {0} is not editable", index));
        tableViewer.getTable().getColumn(index).dispose();
        if (getColumnCount() == 0) {
            input.clear();
            refresh();
        } else {
            for (int i = 0; i < getRowCount(); i++) {
                input.get(i).remove(index);
            }
        }

        fireTableModified();
    }

    /**
     * Delete a row.
     *
     * @param index
     *            index of the row.
     */
    public void deleteRow(int index) {
        input.remove(index);
        tableViewer.refresh();
        fireTableModified();
    }

    protected void fireTableModified() {
        if (tableModifiedListeners != null) {
            String[][] content = getContent();
            for (Object o : tableModifiedListeners.getListeners()) {
                ((ITableModifiedListener) o).modified(content);
            }
        }
    }

    /**
     * Get text of a cell.
     *
     * @param row
     *            row index of the cell.
     * @param col
     *            column index of the cell.
     * @return the cell text.
     */
    public String getCellText(int row, int col) {
        return input.get(row).get(col);
    }

    /**
     * Get number of columns.
     *
     * @see {@link Table#getColumnCount()}
     */
    public int getColumnCount() {
        return tableViewer.getTable().getColumnCount();
    }

    /**Get column headers.
     * @return the column headers.
     */
    public String[] getColumnHeaders() {
        String[] r = new String[getColumnCount()];
        for (int i = 0; i < r.length; i++) {
            r[i] = tableViewer.getTable().getColumn(i).getText();
        }
        return r;
    }

    /**
     * Get content of the table in a 2D string array.
     *
     * @return content of the table.
     */
    public String[][] getContent() {
        String[][] result = new String[input.size()][getColumnCount()];
        for (int i = 0; i < input.size(); i++) {
            for (int j = 0; j < getColumnCount(); j++) {
                result[i][j] = input.get(i).get(j);
            }
        }
        return result;
    }

    /**
     * Get input of the table by which the table is backed. To keep the table's
     * content synchronized with the table, client should call
     * {@link #refresh()} if the returned list has been modified outside.
     *
     * @return the input of the table.
     */
    public List<List<String>> getInput() {
        return input;
    }

    /**Get row and column index under given point.
     * @param point the widget-relative coordinates
     * @return int[0] is row index, int[1] is column index.
     * null if no cell was found under given point.
     */
    public int[] getRowColumnIndex(Point point) {
        Table table = tableViewer.getTable();
        ViewerCell cell = tableViewer.getCell(point);
        if (cell == null)
            return null;
        int col = cell.getColumnIndex();
        //        int row = table.indexOf((TableItem) cell.getItem());
        //        return new int[]{row, col};
        int row = -1;
        // get row index
        Rectangle clientArea = table.getClientArea();

        int index = table.getTopIndex();
        while (index < table.getItemCount()) {
            boolean visible = false;
            TableItem item = table.getItem(index);
            Rectangle rect = item.getBounds(col);
            if (rect.contains(point)) {
                row = index;
                return new int[] { row, col };
            }
            if (!visible && rect.intersects(clientArea)) {
                visible = true;
            }

            if (!visible)
                return new int[] { row, col };
            index++;
        }
        return new int[] { row, col };
    }

    public int getRowCount() {
        return input.size();
    }

    /**
     * Get selected part.
     *
     * @return the 2D string array under selection.
     */
    @SuppressWarnings("unchecked")
    public String[][] getSelection() {
        IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
        String[][] result = new String[selection.size()][getColumnCount()];
        int i = 0;
        for (Object o : selection.toArray()) {
            for (int j = 0; j < getColumnCount(); j++) {
                result[i][j] = ((List<String>) o).get(j);
            }
            i++;
        }
        return result;
    }

    /**
     * @return the {@link TableViewer} wrapped by this widget.
     */
    public TableViewer getTableViewer() {
        return tableViewer;
    }

    /**
     * Insert a column. Default values for the new column are empty strings.
     *
     * @param index
     *            index of the column.
     */
    public void insertColumn(int index) {
        for (List<String> row : input) {
            row.add(index, ""); //$NON-NLS-1$
        }
        final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE, index);
        viewerColumn.getColumn().setMoveable(false);
        viewerColumn.getColumn().setWidth(DEFAULT_COLUMN_WIDTH);
        TextEditingSupport textEditingSupport = new TextEditingSupport(tableViewer);
        viewerColumn.setEditingSupport(textEditingSupport);
        viewerColumn.getColumn().setData(TEXT_EDITING_SUPPORT_KEY, textEditingSupport);
        tableViewer.setLabelProvider(new TextTableLableProvider());
        fireTableModified();
    }

    /**
     * Insert a row. Shifts the element currently at that position (if any) and any subsequent elements to the below
     *  (adds one to their indices).Default values for the new row are empty strings.
     *
     * @param index
     *            index of the row.
     */
    public void insertRow(int index) {
        String[] array = new String[getColumnCount()];
        Arrays.fill(array, ""); //$NON-NLS-1$
        input.add(index, new ArrayList<String>(Arrays.asList(array)));
        tableViewer.refresh(false);
        fireTableModified();
    }

    /**
     * @return true if table is editable.
     */
    public boolean isEditable() {
        return editable;
    }

    /**
     * @return true if table content is empty.
     */
    public boolean isEmpty() {
        return input.isEmpty();
    }

    /**
     * @param columnIndex index of the column.
     * @return true if the column is editable.
     */
    public boolean isColumnEditable(int columnIndex) {
        checkColumnIndex(columnIndex);
        return ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex)
                .getData(TEXT_EDITING_SUPPORT_KEY))).isColumnEditable();
    }

    @Override
    public void pack() {
        for (int i = 0; i < getColumnCount(); i++)
            tableViewer.getTable().getColumn(i).pack();
        super.pack();
    }

    /**
     * Refresh the table to reflect its content.
     */
    public void refresh() {
        getTableViewer().refresh();
    }

    /**Set background color of the cell.
     * @param row row index of the cell.
     * @param col column index of the cell.
     * @param rgbColor color in RGB.
     */
    public void setCellBackground(int row, int col, RGB rgbColor) {
        checkRowIndex(row);
        checkColumnIndex(col);
        tableViewer.getTable().getItem(row).setBackground(col, CustomMediaFactory.getInstance().getColor(rgbColor));
    }

    /**Set forground color of the cell.
     * @param row row index of the cell.
     * @param col column index of the cell.
     * @param rgbColor color in RGB.
     */
    public void setCellForeground(int row, int col, RGB rgbColor) {
        checkRowIndex(row);
        checkColumnIndex(col);
        tableViewer.getTable().getItem(row).setForeground(col, CustomMediaFactory.getInstance().getColor(rgbColor));
    }

    /**
     * Set the text of a cell. If the row index is larger than current content,
     *  it will extend the current content to have that row.
     *
     *
     * @param row
     *            row index of the cell. Start from 0.
     * @param col
     *            column index of the cell. Start from 0.
     * @param text
     *            text to be set.
     */
    public void setCellText(int row, int col, String text) {
        checkColumnIndex(col);
        if (row >= input.size()) {
            for (int i = input.size(); i <= row; i++) {
                String[] array = new String[getColumnCount()];
                Arrays.fill(array, ""); //$NON-NLS-1$
                input.add(new ArrayList<String>(Arrays.asList(array)));
            }
            tableViewer.refresh();
        }
        input.get(row).set(col, text);
        tableViewer.getTable().getItem(row).setText(col, text);

        // Does the column use CheckboxCellEditor?
        final CellEditorType cellEditorType = ((TextEditingSupport) (tableViewer.getTable().getColumn(col)
                .getData(TEXT_EDITING_SUPPORT_KEY))).getCellEditorType();
        // Force refresh, so TextTableLableProvider updates the checkbox image
        if (cellEditorType == CellEditorType.CHECKBOX)
            tableViewer.refresh(input.get(row));

        fireTableModified();
    }

    /**Set the cell editor type of a column
     * @param columnIndex index of the column.
     * @param cellEditorType the cell editor type.
     */
    public void setColumnCellEditorType(int columnIndex, CellEditorType cellEditorType) {
        checkColumnIndex(columnIndex);
        ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex).getData(TEXT_EDITING_SUPPORT_KEY)))
                .setCellEditorType(cellEditorType);
    }

    /**Set the needed data for the cell editor. For example, a String[] for dropdown cell editor.
     * @param columnIndex index of the column.
     * @param data data for the cell editor.
     */
    public void setColumnCellEditorData(int columnIndex, Object data) {
        checkColumnIndex(columnIndex);
        ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex).getData(TEXT_EDITING_SUPPORT_KEY)))
                .setCellEditorData(data);
    }

    /**Set the cell editor style. For example, {@link SWT#READ_ONLY} for dropdown cell editor.
     * @param columnIndex index of the column.
     * @param style the style
     */
    public void setColumnCellEditorStyle(int columnIndex, int style) {
        checkColumnIndex(columnIndex);
        ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex).getData(TEXT_EDITING_SUPPORT_KEY)))
                .setCellEditorStyle(style);
    }

    /**Set a customized cell editor for a column. The cell editor
     * must generate or accept String type value.
     * @param columnIndex index of the column.
     * @param cellEditor the cell editor.
     */
    public void setColumnCellEditor(int columnIndex, CellEditor cellEditor) {
        checkColumnIndex(columnIndex);
        ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex).getData(TEXT_EDITING_SUPPORT_KEY)))
                .setCellEditor(cellEditor);
    }

    /**Set if a column is editable.
     * @param columnIndex index of the column.
     * @param editable editable if true.
     */
    public void setColumnEditable(int columnIndex, boolean editable) {
        checkColumnIndex(columnIndex);
        ((TextEditingSupport) (tableViewer.getTable().getColumn(columnIndex).getData(TEXT_EDITING_SUPPORT_KEY)))
                .setColumnEditable(editable);
    }

    /**
     * Set the header of a column.
     *
     * @param columnIndex
     *            index of the column.
     * @param header
     *            header text.
     */
    public void setColumnHeader(int columnIndex, String header) {
        checkColumnIndex(columnIndex);
        tableViewer.getTable().getColumn(columnIndex).setText(header);
    }

    /**
     * Set column headers. If the size of the headers array is larger than the
     * existing columns count. It will increase the columns count automatically.
     *
     * @param headers
     *            headers text.
     */
    public void setColumnHeaders(String[] headers) {
        if (headers.length > getColumnCount()) {
            setColumnsCount(headers.length);
        }
        for (int i = 0; i < headers.length; i++) {
            tableViewer.getTable().getColumn(i).setText(headers[i]);
        }
    }

    /**
     * Show/hide table column headers.
     *
     * @param show
     *            the new visibility state
     */
    public void setColumnHeaderVisible(boolean show) {
        tableViewer.getTable().setHeaderVisible(show);
    }

    /**
     * Set number of columns. If the new count is less than old count, columns
     * from right will be deleted. If the new count is more than old count, new
     * columns will be appended to the right.
     *
     * @param count
     *            number of columns.
     */
    public void setColumnsCount(int count) {
        TableColumn[] columns = tableViewer.getTable().getColumns();
        int oldCount = getColumnCount();
        if (count == oldCount)
            return;
        if (count < oldCount) {
            for (int i = count; i < oldCount; i++) {
                columns[i].dispose();
            }
            for (List<String> row : input) {
                for (int i = oldCount - 1; i > count - 1; i--) {
                    row.remove(i);
                }
            }
            return;
        }

        // if count > old count
        for (List<String> row : input) {
            for (int i = 0; i < count - oldCount; i++) {
                row.add("");
            }
        }

        for (int i = oldCount; i < count; i++) {
            final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
            viewerColumn.getColumn().setMoveable(false);
            viewerColumn.getColumn().setWidth(DEFAULT_COLUMN_WIDTH);
            TextEditingSupport textEditingSupport = new TextEditingSupport(tableViewer);
            viewerColumn.setEditingSupport(textEditingSupport);
            viewerColumn.getColumn().setData(TEXT_EDITING_SUPPORT_KEY, textEditingSupport);
        }
        tableViewer.setLabelProvider(new TextTableLableProvider());
        fireTableModified();

    }

    public void setColumnWidth(int col, int width) {
        checkColumnIndex(col);
        tableViewer.getTable().getColumn(col).setWidth(width);
    }

    /**
     * Set width of each column. If length of the sizes array is larger than the
     * existing columns count. It will increase the columns count automatically.
     *
     * @param widthes
     *            column size in pixels.
     */
    public void setColumnWidths(int[] widthes) {
        if (widthes.length > tableViewer.getTable().getColumnCount()) {
            setColumnsCount(widthes.length);
        }
        for (int i = 0; i < widthes.length; i++) {
            tableViewer.getTable().getColumn(i).setWidth(widthes[i]);
        }
    }

    /**
     * Set content of the table.Old content in table will be replaced by the new
     * content.
     *
     * @param content
     *            the new content.
     */
    public void setContent(String[][] content) {
        Assert.isNotNull(content);
        input.clear();
        if (content.length <= 0) {
            tableViewer.refresh();
            return;
        }
        setColumnsCount(content[0].length);
        for (int i = 0; i < content.length; i++) {
            List<String> row = new ArrayList<String>(content[0].length);
            for (int j = 0; j < content[0].length; j++) {
                row.add(content[i][j]);
            }
            input.add(row);
        }
        tableViewer.refresh();
        fireTableModified();
    }

    /**
     * Set if the table is editable.
     *
     * @param editable
     *            true if table is editable.
     */
    public void setEditable(boolean editable) {
        this.editable = editable;
    }

    @Override
    public void setFont(Font font) {
        super.setFont(font);
        tableViewer.getTable().setFont(font);
    }

    /**
     * Set input of the table. The input is the back of the table, so content of
     * the input is always synchronized with content of the table.
     *
     * @param input
     *            input of the table.
     */
    public void setInput(List<List<String>> input) {
        tableViewer.setInput(input);
        this.input = input;
        fireTableModified();
    }

    @Override
    public void setMenu(Menu menu) {
        super.setMenu(menu);
        tableViewer.getTable().setMenu(menu);
    }

    /**Set background color of the row.
     * @param row row index of the cell.
     * @param rgbColor color in RGB.
     */
    public void setRowBackground(int row, RGB rgbColor) {
        checkRowIndex(row);
        tableViewer.getTable().getItem(row).setBackground(CustomMediaFactory.getInstance().getColor(rgbColor));
    }

    /**Set foreground color of the row.
     * @param row row index of the cell.
     * @param rgbColor color in RGB.
     */
    public void setRowForeground(int row, RGB rgbColor) {
        checkRowIndex(row);
        tableViewer.getTable().getItem(row).setForeground(CustomMediaFactory.getInstance().getColor(rgbColor));
    }

    private synchronized static Image getOnImage() {
        if (onImage == null) {
            String path = "images/checked.gif"; //$NON-NLS-1$

            InputStream stream = SpreadSheetTable.class.getResourceAsStream(path);
            onImage = new Image(Display.getCurrent(), stream);
            try {
                stream.close();
            } catch (IOException e) {
            }
        }
        return onImage;
    }

    private synchronized static Image getOffImage() {
        if (offImage == null) {
            String path = "images/unchecked.gif"; //$NON-NLS-1$

            InputStream stream = SpreadSheetTable.class.getResourceAsStream(path);
            offImage = new Image(Display.getCurrent(), stream);
            try {
                stream.close();
            } catch (IOException e) {
            }
        }
        return offImage;
    }

}