org.eclipse.datatools.sqltools.result.internal.ui.viewer.ResultSetViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.datatools.sqltools.result.internal.ui.viewer.ResultSetViewer.java

Source

/*******************************************************************************
 * Copyright (c) 2005, 2013 Sybase, Inc. 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:
 *    Sybase, Inc. - initial API and implementation
 *    IBM Corporation - Bug 376356
 *******************************************************************************/
package org.eclipse.datatools.sqltools.result.internal.ui.viewer;

import java.sql.Types;
import java.util.Date;

import org.eclipse.datatools.sqltools.result.IResultSetObject;
import org.eclipse.datatools.sqltools.result.IResultSetRow;
import org.eclipse.datatools.sqltools.result.internal.ui.LongDataDialog;
import org.eclipse.datatools.sqltools.result.internal.ui.Messages;
import org.eclipse.datatools.sqltools.result.internal.ui.export.actions.CopyRowsAction;
import org.eclipse.datatools.sqltools.result.internal.ui.export.actions.ExportAllResultSetsAction;
import org.eclipse.datatools.sqltools.result.internal.ui.export.actions.ExportResultSetAction;
import org.eclipse.datatools.sqltools.result.internal.ui.export.actions.PrintResultSetAction;
import org.eclipse.datatools.sqltools.result.internal.ui.export.actions.SaveAllResultSetsAction;
import org.eclipse.datatools.sqltools.result.internal.ui.export.actions.SaveResultSetAction;
import org.eclipse.datatools.sqltools.result.internal.ui.utils.UIUtil;
import org.eclipse.datatools.sqltools.result.internal.utils.HexHelper;
import org.eclipse.datatools.sqltools.result.internal.utils.SQLUtil;
import org.eclipse.datatools.sqltools.result.model.IResultInstance;
import org.eclipse.datatools.sqltools.result.ui.ResultsViewUIPlugin;
import org.eclipse.datatools.sqltools.result.ui.view.ResultsViewControl;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;

import com.ibm.icu.text.Collator;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;

/**
 * This is a configurable viewer used to display result set object.
 * 
 * @author Dafan Yang
 *  
 */
public class ResultSetViewer extends TableViewer {
    private IResultInstance _instance;
    private IResultSetObject _result;
    private boolean _showRowCount;
    private String[] _columnProperties;
    private Composite _parent;
    private ITableLabelProvider _labelProvider;
    private ViewerSorter _currentSorter;
    private ResultsViewControl _resultsViewControl;
    private MenuManager mgr;
    /* to compute the average widht of each character (including average distance between characters) */
    private static final double FONT_AVER_WIDTH_FACTOR = 1.6;
    /* the minimum width of the row count column */
    private static final int MIN_WIDTH = 30;

    /* if the lenght of data is bigger than LONG_BOUNDARY, we will use a pop-up dialog to display it */
    public static final int LONG_BOUNDARY = 130;

    /**
     * Creates a result set viewer.
     * 
     * @param parent the parent
     * @param style the style
     * @param instance the result instance
     * @param result the result set object
     * @param showRowCount the show row count option
     */
    public ResultSetViewer(Composite parent, int style, IResultInstance instance, IResultSetObject result,
            boolean showRowCount, ResultsViewControl resultsViewControl) {
        super(parent, style);
        _showRowCount = showRowCount;
        _instance = instance;
        _result = result;
        _parent = parent;
        _resultsViewControl = resultsViewControl;
        configTableViewer();
        setInput(_result);
        // set focus to the first row
        getTable().setSelection(0);
    }

    protected void configTableViewer() {
        getTable().setHeaderVisible(true);
        getTable().setLinesVisible(true);

        getTable().addMouseListener(new MouseAdapter() {
            public void mouseDoubleClick(MouseEvent event) {

                // compute the row id and column id
                Table table = ResultSetViewer.this.getTable();
                Point pt = new Point(event.x, event.y);
                Rectangle clientRect = table.getClientArea();
                int columnCount = table.getColumnCount();
                int maxColumnIndex = columnCount == 0 ? 0 : columnCount - 1;
                int start = table.getTopIndex();
                int end = table.getItemCount();
                int i = 0, j = 0;
                outer: for (i = start; i < end; i++) {
                    TableItem item = table.getItem(i);
                    for (j = 0; j <= maxColumnIndex; j++) {
                        Rectangle rect = item.getBounds(j);
                        if (rect.y > clientRect.y + clientRect.height) {
                            return;
                        }
                        if (rect.contains(pt)) {
                            break outer;
                        }
                    }
                }

                // must get data from the sorted result
                ResultSetViewer.this.setSorter(_currentSorter);
                Integer[] rows = (Integer[]) ResultSetViewer.this.getSortedChildren(_result);
                IResultSetRow row = _result.getRowData(rows[i].intValue());
                if (row == null) {
                    return;
                }
                if (_showRowCount) {
                    j--;
                }
                Object data = row.getData(j);
                if (data == null) {
                    return;
                }
                String strValue = ""; //$NON-NLS-1$

                //consider the binay type
                if (data instanceof byte[]) {
                    byte[] os = (byte[]) data;
                    strValue = HexHelper.toHexString(os);
                } else {
                    strValue = data.toString();
                }
                if (strValue.length() > LONG_BOUNDARY) {
                    LongDataDialog dlg = new LongDataDialog(ResultSetViewer.this.getTable().getShell(),
                            _result.getColumnName(j + 1), SQLUtil.convertToString(_result.getColumnSQLType(j + 1)),
                            strValue);
                    dlg.open();
                }
            }
        });

        // set the tooltip of this table viewer
        int totalRowCount = _result.getTotalRowCount();
        int rowCount = _result.getRowCount();
        if (totalRowCount == rowCount) {
            getTable().setToolTipText(
                    NLS.bind(Messages.ResultSection_resultset_tooltip1, new Object[] { String.valueOf(rowCount) })); //$NON-NLS-1$
        } else {
            getTable().setToolTipText(NLS.bind(Messages.ResultSection_resultset_tooltip,
                    new Object[] { String.valueOf(totalRowCount), String //$NON-NLS-1$
                            .valueOf(rowCount) }));
        }

        GridData tableGridData = new GridData();
        tableGridData.grabExcessHorizontalSpace = true;
        tableGridData.grabExcessVerticalSpace = true;
        tableGridData.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
        tableGridData.verticalAlignment = org.eclipse.swt.layout.GridData.FILL;

        getTable().setLayoutData(tableGridData);

        int columnNum = 0;
        if (_showRowCount) {
            columnNum++;
            TableColumn rowCountColumn = new TableColumn(getTable(), SWT.NONE);
            rowCountColumn.setResizable(true);
        }

        columnNum += _result.getColumnCount();
        _columnProperties = new String[columnNum];

        if (_showRowCount) {
            _columnProperties[0] = "RowCount"; //$NON-NLS-1$
        }

        // create the table columns for the result set (according to the metadata)
        for (int i = 0; i < _result.getColumnCount(); i++) {
            final TableColumn column = new TableColumn(getTable(), SWT.NONE);
            column.setText(_result.getColumnName(i + 1));
            column.setResizable(true);

            final int finalIndex = i + 1;
            column.addSelectionListener(new SelectionAdapter() {
                private int _index = finalIndex;
                private int _order = 1;

                public void widgetSelected(SelectionEvent e) {
                    ViewerSorterByColumn sorter = new ViewerSorterByColumn(_index, _result, _order, _labelProvider,
                            _showRowCount);
                    _currentSorter = sorter;
                    ResultSetViewer.this.setSorter(sorter);
                    _order *= -1;
                    getTable().setSortColumn(column);
                    getTable().setSortDirection(_order == -1 ? SWT.DOWN : SWT.UP);

                    if (_showRowCount) {
                        Table table = ResultSetViewer.this.getTable();
                        int itemCount = table.getItemCount();
                        for (int j = 0; j < itemCount; j++) {
                            TableItem item = table.getItem(j);
                            item.setText(0, Integer.toString(j + 1));
                        }
                    }
                }
            });

            int index = i;
            if (_showRowCount) {
                index = i + 1;
            }
            _columnProperties[index] = _result.getColumnName(i + 1);
        }

        setColumnProperties(_columnProperties);
        setContentProvider(new ResultSetContentProvider());
        _labelProvider = new ResultSetLabelProvider(_result, _showRowCount, _resultsViewControl);
        setLabelProvider(_labelProvider);

        int columnCount = _columnProperties.length;
        int defaultWidth = 0;

        int i = _showRowCount ? 1 : 0;

        if (_showRowCount) {
            int chars = Integer.toString(rowCount).length();
            chars = chars < 2 ? 2 : chars;
            int computedWidth = Math
                    .round(Math.round(UIUtil.convertWidthInCharsToPixels(chars, _parent) * FONT_AVER_WIDTH_FACTOR));
            if (computedWidth < MIN_WIDTH) {
                computedWidth = MIN_WIDTH;
            }
            getTable().getColumn(0).setWidth(computedWidth);
        }
        for (; i < columnCount; i++) {
            TableColumn column = getTable().getColumn(i);
            column.pack();
            defaultWidth = defaultWidth + column.getWidth() + getTable().getGridLineWidth();
        }

        //don't adjust the rowcount column
        i = _showRowCount ? 1 : 0;

        int moreWidth = _parent.getParent().getBounds().width - 2 - defaultWidth;
        if (moreWidth > 0) {
            for (; i < columnCount; i++) {
                TableColumn col = getTable().getColumn(i);
                int adjustColumnCount = _showRowCount ? (columnCount - 1) : columnCount;
                col.setWidth(col.getWidth() + moreWidth / adjustColumnCount);
            }
        }

        //create the context menu on this viewer
        mgr = new MenuManager();

        MenuManager saveMgr = new MenuManager(Messages.Save_name);
        saveMgr.add(new SaveResultSetAction(getTable().getShell(), _result));
        saveMgr.add(new SaveAllResultSetsAction(getTable().getShell(), _instance));

        MenuManager exportMgr = new MenuManager(Messages.Export_name);
        exportMgr.add(new ExportResultSetAction(getTable().getShell(), _result));
        exportMgr.add(new ExportAllResultSetsAction(getTable().getShell(), _instance));

        MenuManager printMgr = new MenuManager(Messages.Print_name);
        printMgr.add(new PrintResultSetAction(_result, _parent));
        printMgr.add(new PrintResultSetAction(_instance, _parent));

        final CopyRowsAction copyAction = new CopyRowsAction(Messages.ResultSetViewer_copy_rows, this, _result);

        mgr.add(copyAction);
        mgr.add(saveMgr);
        mgr.add(exportMgr);
        mgr.add(printMgr);

        mgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                IStructuredSelection ss = (IStructuredSelection) ResultSetViewer.this.getSelection();
                if (ss == null || ss.toList().size() == 0) {
                    copyAction.setEnabled(false);
                } else {
                    copyAction.setEnabled(true);
                }
            }
        });
        Menu menu = mgr.createContextMenu(getControl());
        getControl().setMenu(menu);
    }

    protected void doUpdateItem(Widget widget, Object element, boolean fullMap) {
        super.doUpdateItem(widget, element, fullMap);
        if (element instanceof Integer) {
            if (_showRowCount) {
                /**
                 * set the row count column's backgroud color to make it different from other columns
                 */
                TableItem item = getTable().getItem(((Integer) element).intValue());
                item.setBackground(0, ResultsViewUIPlugin.getDefault().getDisabledBakColor());
            }
        }
    }

    /**
     * Gets the menuManager for this viewers control
     * @return the menuManger
     */
    public MenuManager getMenuManager() {
        return mgr;
    }
}

/**
 * this class is used to sort the table viewer according to the given column's
 * SQL type and order (ASCEND or DESCEND)
 * 
 */
class ViewerSorterByColumn extends ViewerSorter {
    private int _columnIndex;
    private IResultSetObject _result;
    private int _order;
    private ITableLabelProvider _labelProvider;
    private boolean _showRowCount;

    public ViewerSorterByColumn(int index, IResultSetObject result, int order, ITableLabelProvider labelProvider,
            boolean showRowCount) {
        super();
        _columnIndex = index;
        _result = result;
        _order = order;
        _labelProvider = labelProvider;
        _showRowCount = showRowCount;
    }

    public int compare(Viewer viewer, Object e1, Object e2) {
        int type = _result.getColumnSQLType(_columnIndex);

        int index = _columnIndex;

        //if there is a row count column, we must decrease column index by one to get the right value
        if (!_showRowCount) {
            index = _columnIndex - 1;
        }
        if (type == Types.INTEGER || type == Types.DECIMAL || type == Types.DOUBLE || type == Types.FLOAT
                || type == Types.NUMERIC || type == Types.REAL || type == Types.TINYINT || type == Types.SMALLINT
                || type == Types.BIGINT) {
            try {
                double value1 = Double.parseDouble(_labelProvider.getColumnText(e1, index));
                double value2 = Double.parseDouble(_labelProvider.getColumnText(e2, index));
                if (value1 > value2) {
                    return -1 * _order;
                } else if (value1 == value2) {
                    return 0;
                } else {
                    return 1 * _order;
                }
            } catch (Exception e) {
                //should not happen
                return 0;
            }
        } else if (type == Types.CHAR || type == Types.VARCHAR || type == Types.LONGVARCHAR) {

            String str1 = _labelProvider.getColumnText(e1, index);
            String str2 = _labelProvider.getColumnText(e2, index);
            Collator collator = Collator.getInstance();
            collator.setStrength(Collator.PRIMARY);
            if (collator.compare(str1, str2) > 0) {
                return -1 * _order;
            } else if (collator.compare(str1, str2) == 0) {
                return 0;
            } else {
                return 1 * _order;
            }
        } else if (type == Types.DATE || type == Types.TIMESTAMP || type == Types.TIME) {
            try {
                //WARN: if the date output format is configurable, should also change the format here.
                DateFormat dFormatter = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss"); //$NON-NLS-1$
                Date date1 = dFormatter.parse(_labelProvider.getColumnText(e1, index));
                Date date2 = dFormatter.parse(_labelProvider.getColumnText(e2, index));
                return date1.before(date2) ? 1 * _order : -1 * _order;
            } catch (Exception e) {
                //should not happen
            }
            return 0;
        } else if (type == Types.BIT || type == Types.BOOLEAN) {
            try {
                Boolean value1 = Boolean.valueOf(_labelProvider.getColumnText(e1, index));
                Boolean value2 = Boolean.valueOf(_labelProvider.getColumnText(e2, index));
                if (value1.booleanValue() && !value2.booleanValue()) {
                    return 1 * _order;
                } else if (!value1.booleanValue() && value2.booleanValue()) {
                    return -1 * _order;
                } else {
                    return 0;
                }
            } catch (Exception e) {
                //should not happen
            }
            return 0;
        }
        //for now, we don't consider the sorting for BINARY, VARBINARY, LONGVARBINARY, CLOB, BLOB
        else {
            return 0;
        }
    }
}