/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ui.controls.resultset.spreadsheet;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ControlEditor;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.jkiss.dbeaver.ui.controls.lightgrid.LightGrid;
/**
* Spreadsheet cell editor
*
* @author serge@jkiss.org
*/
public class SpreadsheetCellEditor extends ControlEditor
{
private LightGrid grid;
private int column = -1;
private int row = -1;
private ControlListener columnListener;
private Listener resizeListener;
private SelectionListener scrollListener;
/**
* Creates a TableEditor for the specified Table.
*
* @param grid the Table Control above which this editor will be displayed
*/
public SpreadsheetCellEditor(final LightGrid grid)
{
super(grid);
this.grid = grid;
columnListener = new ControlListener()
{
@Override
public void controlMoved(ControlEvent e)
{
layout();
}
@Override
public void controlResized(ControlEvent e)
{
layout();
}
};
resizeListener = new Listener()
{
@Override
public void handleEvent(Event event)
{
layout();
}
};
scrollListener = new SelectionListener()
{
@Override
public void widgetSelected(SelectionEvent e)
{
layout();
}
@Override
public void widgetDefaultSelected(SelectionEvent e)
{
}
};
// The following three listeners are workarounds for
// Eclipse bug 105764
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=105764
grid.addListener(SWT.Resize, resizeListener);
if (grid.getVerticalScrollBarProxy() != null)
{
grid.getVerticalScrollBarProxy().addSelectionListener(scrollListener);
}
if (grid.getHorizontalScrollBarProxy() != null)
{
grid.getHorizontalScrollBarProxy().addSelectionListener(scrollListener);
}
// To be consistent with older versions of SWT, grabVertical defaults to
// true
grabVertical = true;
}
/**
* Returns the bounds of the editor.
*
* @return bounds of the editor.
*/
private Rectangle computeEditorBounds()
{
if (row == -1 || column == -1)
return new Rectangle(0, 0, 0, 0);
Rectangle cell = grid.getCellBounds(column, row);
Rectangle area = grid.getClientArea();
if (cell.x < area.x + area.width)
{
if (cell.x + cell.width > area.x + area.width)
{
cell.width = area.x + area.width - cell.x;
}
}
Rectangle editorRect = new Rectangle(cell.x, cell.y, minimumWidth, minimumHeight);
if (grabHorizontal)
{
editorRect.width = Math.max(cell.width, minimumWidth);
}
if (grabVertical)
{
editorRect.height = Math.max(cell.height, minimumHeight);
}
if (horizontalAlignment == SWT.RIGHT)
{
editorRect.x += cell.width - editorRect.width;
}
else if (horizontalAlignment == SWT.LEFT)
{
// do nothing - cell.x is the right answer
}
else
{ // default is CENTER
editorRect.x += (cell.width - editorRect.width) / 2;
}
if (verticalAlignment == SWT.BOTTOM)
{
editorRect.y += cell.height - editorRect.height;
}
else if (verticalAlignment == SWT.TOP)
{
// do nothing - cell.y is the right answer
}
else
{ // default is CENTER
editorRect.y += (cell.height - editorRect.height) / 2;
}
return editorRect;
}
/**
* Removes all associations between the TableEditor and the cell in the
* table. The Table and the editor Control are <b>not</b> disposed.
*/
@Override
public void dispose()
{
if (!grid.isDisposed())
{
grid.removeListener(SWT.Resize, resizeListener);
if (grid.getVerticalScrollBarProxy() != null)
grid.getVerticalScrollBarProxy().removeSelectionListener(scrollListener);
if (grid.getHorizontalScrollBarProxy() != null)
grid.getHorizontalScrollBarProxy().removeSelectionListener(scrollListener);
}
columnListener = null;
resizeListener = null;
grid = null;
row = -1;
column = -1;
super.dispose();
}
/**
* Returns the zero based index of the column of the cell being tracked by
* this editor.
*
* @return the zero based index of the column of the cell being tracked by
* this editor
*/
public int getColumn()
{
return column;
}
/**
* Returns the TableItem for the row of the cell being tracked by this
* editor.
*
* @return the TableItem for the row of the cell being tracked by this
* editor
*/
public int getRow()
{
return row;
}
public void setRow(int row) {
this.row = row;
layout();
}
/**
* Sets the zero based index of the column of the cell being tracked by this
* editor.
*
* @param column the zero based index of the column of the cell being
* tracked by this editor
*/
public void setColumn(int column)
{
int columnCount = grid.getColumnCount();
// Separately handle the case where the grid has no TableColumns.
// In this situation, there is a single default column.
if (columnCount == 0)
{
this.column = (column == 0) ? 0 : -1;
layout();
return;
}
if (this.column > -1 && this.column < columnCount)
{
this.column = -1;
}
if (column < 0 || column >= grid.getColumnCount())
return;
this.column = column;
layout();
}
/**
* Specify the Control that is to be displayed and the cell in the table
* that it is to be positioned above.
* <p>
* Note: The Control provided as the editor <b>must</b> be created with its
* parent being the Table control specified in the TableEditor constructor.
*
* @param editor the Control that is displayed above the cell being edited
* @param row the row of the cell being tracked by this editor
* @param column the zero based index of the column of the cell being
* tracked by this editor
*/
public void setEditor(Control editor, int column, int row)
{
setRow(row);
setColumn(column);
setEditor(editor);
layout();
}
@Override
public void layout()
{
if (grid.isDisposed())
return;
if (row == -1)
return;
int columnCount = grid.getColumnCount();
if (columnCount == 0 && column != 0)
return;
if (columnCount > 0 && (column < 0 || column >= columnCount))
return;
boolean hadFocus = false;
if (getEditor() == null || getEditor().isDisposed())
return;
if (getEditor().getVisible())
{
hadFocus = getEditor().isFocusControl();
} // this doesn't work because
// resizing the column takes the focus away
// before we get here
getEditor().setBounds(computeEditorBounds());
if (hadFocus)
{
if (getEditor() == null || getEditor().isDisposed())
return;
getEditor().setFocus();
}
}
}